From 421658884f7ca786747abf9b89e00925fdfdfba8 Mon Sep 17 00:00:00 2001 From: Evan You Date: Wed, 11 Oct 2017 11:17:46 -0400 Subject: [PATCH] fix: fix scoped CSS for nested nodes in functional components --- src/core/vdom/create-functional-component.js | 3 ++- src/core/vdom/patch.js | 2 +- src/core/vdom/vnode.js | 9 +++++++-- test/unit/features/options/_scopeId.spec.js | 14 +++++++++----- 4 files changed, 19 insertions(+), 9 deletions(-) diff --git a/src/core/vdom/create-functional-component.js b/src/core/vdom/create-functional-component.js index b3d1c967c3d..24f57e52c6c 100644 --- a/src/core/vdom/create-functional-component.js +++ b/src/core/vdom/create-functional-component.js @@ -51,7 +51,8 @@ function FunctionalRenderContext ( this._c = (a, b, c, d) => { const vnode: ?VNode = createElement(contextVm, a, b, c, d, needNormalization) if (vnode) { - vnode.fnScopeId = options._scopeId + vnode.functionalScopeId = options._scopeId + vnode.functionalContext = parent } return vnode } diff --git a/src/core/vdom/patch.js b/src/core/vdom/patch.js index 7358b7430de..f41f5a90763 100644 --- a/src/core/vdom/patch.js +++ b/src/core/vdom/patch.js @@ -281,7 +281,7 @@ export function createPatchFunction (backend) { // of going through the normal attribute patching process. function setScope (vnode) { let i - if (isDef(i = vnode.fnScopeId)) { + if (isDef(i = vnode.functionalScopeId)) { nodeOps.setAttribute(vnode.elm, i, '') } else { let ancestor = vnode diff --git a/src/core/vdom/vnode.js b/src/core/vdom/vnode.js index 3b19a9b4d27..3c5f2322712 100644 --- a/src/core/vdom/vnode.js +++ b/src/core/vdom/vnode.js @@ -8,11 +8,12 @@ export default class VNode { elm: Node | void; ns: string | void; context: Component | void; // rendered in this component's scope - functionalContext: Component | void; // only for functional component root nodes key: string | number | void; componentOptions: VNodeComponentOptions | void; componentInstance: Component | void; // component instance parent: VNode | void; // component placeholder node + + // strictly internal raw: boolean; // contains raw HTML? (server only) isStatic: boolean; // hoisted static node isRootInsert: boolean; // necessary for enter transition check @@ -23,7 +24,9 @@ export default class VNode { asyncMeta: Object | void; isAsyncPlaceholder: boolean; ssrContext: Object | void; - fnScopeId: ?string; + functionalContext: Component | void; // real context vm for functional nodes + functionalOptions: ?ComponentOptions; // for SSR caching + functionalScopeId: ?string; // functioanl scope id support constructor ( tag?: string, @@ -43,6 +46,8 @@ export default class VNode { this.ns = undefined this.context = context this.functionalContext = undefined + this.functioanlOptions = undefined + this.functionalScopeId = undefined this.key = data && data.key this.componentOptions = componentOptions this.componentInstance = undefined diff --git a/test/unit/features/options/_scopeId.spec.js b/test/unit/features/options/_scopeId.spec.js index be13b9dc22c..ec45f902c32 100644 --- a/test/unit/features/options/_scopeId.spec.js +++ b/test/unit/features/options/_scopeId.spec.js @@ -74,7 +74,9 @@ describe('Options _scopeId', () => { functional: true, _scopeId: 'child', render (h) { - return h('div', { class: 'child' }, 'child') + return h('div', { class: 'child' }, [ + h('span', { class: 'child' }, 'child') + ]) } } const vm = new Vue({ @@ -84,9 +86,11 @@ describe('Options _scopeId', () => { }).$mount() expect(vm.$el.hasAttribute('parent')).toBe(true) - const childEl = vm.$el.querySelector('.child') - expect(childEl.hasAttribute('child')).toBe(true) - // functional component with scopeId will not inherit parent scopeId - expect(childEl.hasAttribute('parent')).toBe(false) + const childEls = vm.$el.querySelectorAll('.child') + ;[].forEach.call(childEls, el => { + expect(el.hasAttribute('child')).toBe(true) + // functional component with scopeId will not inherit parent scopeId + expect(el.hasAttribute('parent')).toBe(false) + }) }) })