Skip to content

Commit cfe745e

Browse files
committed
apply scopeId to slot contents too
1 parent d76bf8c commit cfe745e

File tree

9 files changed

+95
-18
lines changed

9 files changed

+95
-18
lines changed

src/core/instance/render.js

+3-10
Original file line numberDiff line numberDiff line change
@@ -59,10 +59,10 @@ export function renderMixin (Vue: Class<Component>) {
5959
_parentVnode
6060
} = vm.$options
6161

62-
if (staticRenderFns && !vm._staticTrees) {
63-
// render static sub-trees for once on initial render
64-
renderStaticTrees(vm, staticRenderFns)
62+
if (staticRenderFns && !this._staticTrees) {
63+
this._staticTrees = []
6564
}
65+
6666
// resolve slots. becaues slots are rendered in parent scope,
6767
// we set the activeInstance to parent.
6868
if (_renderChildren) {
@@ -154,13 +154,6 @@ export function renderMixin (Vue: Class<Component>) {
154154
}
155155
}
156156

157-
function renderStaticTrees (vm: Component, fns: Array<Function>) {
158-
const trees = vm._staticTrees = new Array(fns.length)
159-
for (let i = 0; i < fns.length; i++) {
160-
trees[i] = fns[i].call(vm._renderProxy)
161-
}
162-
}
163-
164157
function resolveSlots (
165158
vm: Component,
166159
renderChildren: Array<any> | () => Array<any> | string

src/core/vdom/create-component.js

+2-1
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ export function createComponent (
1313
data?: VNodeData,
1414
parent: Component,
1515
context: Component,
16+
host: ?Component,
1617
tag?: string
1718
): VNode | void {
1819
if (!Ctor) {
@@ -66,7 +67,7 @@ export function createComponent (
6667
const name = Ctor.options.name || tag
6768
const vnode = new VNode(
6869
`vue-component-${Ctor.cid}${name ? `-${name}` : ''}`,
69-
data, undefined, undefined, undefined, undefined, context,
70+
data, undefined, undefined, undefined, undefined, context, host,
7071
{ Ctor, propsData, listeners, parent, tag, children: undefined }
7172
// children to be set later by renderElementWithChildren,
7273
// but before the init hook

src/core/vdom/create-element.js

+10-5
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ export function renderElement (
3737
// make sure to expose real self instead of proxy
3838
const context: Component = this._self
3939
const parent: ?Component = renderState.activeInstance
40+
const host = context !== parent ? parent : undefined
4041
if (!parent) {
4142
process.env.NODE_ENV !== 'production' && warn(
4243
'createElement cannot be called outside of component ' +
@@ -53,10 +54,10 @@ export function renderElement (
5354
if (config.isReservedTag(tag)) {
5455
return new VNode(
5556
tag, data, undefined,
56-
undefined, undefined, namespace, context
57+
undefined, undefined, namespace, context, host
5758
)
5859
} else if ((Ctor = resolveAsset(context.$options, 'components', tag))) {
59-
return createComponent(Ctor, data, parent, context, tag)
60+
return createComponent(Ctor, data, parent, context, host, tag)
6061
} else {
6162
if (process.env.NODE_ENV !== 'production') {
6263
if (!namespace && config.isUnknownElement(tag)) {
@@ -69,11 +70,11 @@ export function renderElement (
6970
}
7071
return new VNode(
7172
tag, data, undefined,
72-
undefined, undefined, namespace, context
73+
undefined, undefined, namespace, context, host
7374
)
7475
}
7576
} else {
76-
return createComponent(tag, data, parent, context)
77+
return createComponent(tag, data, parent, context, host)
7778
}
7879
}
7980

@@ -82,5 +83,9 @@ export function renderText (str?: string): string {
8283
}
8384

8485
export function renderStatic (index?: number): Object | void {
85-
return this._staticTrees[index]
86+
return this._staticTrees[index] || (
87+
this._staticTrees[index] = this.$options.staticRenderFns[index].call(
88+
this._renderProxy
89+
)
90+
)
8691
}

src/core/vdom/patch.js

+3
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,9 @@ export function createPatchFunction (backend) {
121121
// of going through the normal attribute patching process.
122122
function setScope (vnode) {
123123
let i
124+
if (isDef(i = vnode.host) && isDef(i = i.$options._scopeId)) {
125+
nodeOps.setAttribute(vnode.elm, i, '')
126+
}
124127
if (isDef(i = vnode.context) && isDef(i = i.$options._scopeId)) {
125128
nodeOps.setAttribute(vnode.elm, i, '')
126129
}

src/core/vdom/vnode.js

+4
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ export default class VNode {
88
elm: Node | void;
99
ns: string | void;
1010
context: Component | void;
11+
host: ?Component;
1112
key: string | number | void;
1213
componentOptions: VNodeComponentOptions | void;
1314
child: Component | void;
@@ -22,6 +23,7 @@ export default class VNode {
2223
elm?: Node,
2324
ns?: string,
2425
context?: Component,
26+
host?: ?Component,
2527
componentOptions?: VNodeComponentOptions
2628
) {
2729
this.tag = tag
@@ -31,10 +33,12 @@ export default class VNode {
3133
this.elm = elm
3234
this.ns = ns
3335
this.context = context
36+
this.host = host
3437
this.key = data && data.key
3538
this.componentOptions = componentOptions
3639
this.child = undefined
3740
this.parent = undefined
41+
this.raw = false
3842
// apply construct hook.
3943
// this is applied during render, before patch happens.
4044
// unlike other hooks, this is applied on both client and server.

src/server/render.js

+5-2
Original file line numberDiff line numberDiff line change
@@ -93,9 +93,12 @@ export function createRenderFunction (
9393
}
9494
}
9595
// attach scoped CSS ID
96+
let scopeId
97+
if (node.host && (scopeId = node.host.$options._scopeId)) {
98+
markup += ` ${scopeId}`
99+
}
96100
while (node) {
97-
const scopeId = node.context.$options._scopeId
98-
if (scopeId) {
101+
if ((scopeId = node.context.$options._scopeId)) {
99102
markup += ` ${scopeId}`
100103
}
101104
node = node.parent

test/ssr/ssr-string.spec.js

+23
Original file line numberDiff line numberDiff line change
@@ -439,6 +439,29 @@ describe('SSR: renderToString', () => {
439439
})
440440
})
441441

442+
it('_scopeId on slot content', done => {
443+
renderVmWithOptions({
444+
_scopeId: '_v-parent',
445+
template: '<div><child><p>foo</p></child></div>',
446+
components: {
447+
child: {
448+
_scopeId: '_v-child',
449+
render () {
450+
const h = this.$createElement
451+
return h('div', null, this.$slots.default)
452+
}
453+
}
454+
}
455+
}, result => {
456+
expect(result).toContain(
457+
'<div server-rendered="true" _v-parent>' +
458+
'<div _v-child _v-parent><p _v-child _v-parent>foo</p></div>' +
459+
'</div>'
460+
)
461+
done()
462+
})
463+
})
464+
442465
it('should catch error', done => {
443466
renderToString(new Vue({
444467
render () {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
import Vue from 'vue'
2+
3+
describe('Options _scopeId', () => {
4+
it('should add scopeId attributes', () => {
5+
const vm = new Vue({
6+
_scopeId: 'foo',
7+
template: '<div><p><span></span></p></div>'
8+
}).$mount()
9+
expect(vm.$el.hasAttribute('foo')).toBe(true)
10+
expect(vm.$el.children[0].hasAttribute('foo')).toBe(true)
11+
expect(vm.$el.children[0].children[0].hasAttribute('foo')).toBe(true)
12+
})
13+
14+
it('should add scopedId attributes from both parent and child on child root', () => {
15+
const vm = new Vue({
16+
_scopeId: 'foo',
17+
template: '<div><child></child></div>',
18+
components: {
19+
child: {
20+
_scopeId: 'bar',
21+
template: '<div></div>'
22+
}
23+
}
24+
}).$mount()
25+
expect(vm.$el.children[0].hasAttribute('foo')).toBe(true)
26+
expect(vm.$el.children[0].hasAttribute('bar')).toBe(true)
27+
})
28+
29+
it('should add scopedId attributes from both parent and child on slot contents', () => {
30+
const vm = new Vue({
31+
_scopeId: 'foo',
32+
template: '<div><child><p>hi</p></child></div>',
33+
components: {
34+
child: {
35+
_scopeId: 'bar',
36+
template: '<div><slot></slot></div>'
37+
}
38+
}
39+
}).$mount()
40+
expect(vm.$el.children[0].children[0].hasAttribute('foo')).toBe(true)
41+
expect(vm.$el.children[0].children[0].hasAttribute('bar')).toBe(true)
42+
})
43+
})

test/unit/modules/vdom/patch/element.spec.js

+2
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,9 @@ describe('element', () => {
3535
it('should create element with scope attribute', () => {
3636
const vnode = new VNode('div')
3737
vnode.context = new Vue({ _scopeId: 'foo' })
38+
vnode.host = new Vue({ _scopeId: 'bar' })
3839
const elm = patch(null, vnode)
3940
expect(elm.hasAttribute('foo')).toBe(true)
41+
expect(elm.hasAttribute('bar')).toBe(true)
4042
})
4143
})

0 commit comments

Comments
 (0)