diff --git a/packages/runtime-core/__tests__/components/KeepAlive.spec.ts b/packages/runtime-core/__tests__/components/KeepAlive.spec.ts index 0b3e7f5938a..a6311bd64b2 100644 --- a/packages/runtime-core/__tests__/components/KeepAlive.spec.ts +++ b/packages/runtime-core/__tests__/components/KeepAlive.spec.ts @@ -809,7 +809,9 @@ describe('KeepAlive', () => { __scopeId: 'foo', render: withId(() => { return h(KeepAlive, null, { - default: () => h(views[viewRef.value], { ref: instanceRef }) + // since the children of the KeepAlive component will not be compiled as slots, + // so, the parent's scopeId should be attached to it's children + default: withId(() => h(views[viewRef.value], { ref: instanceRef })) }) }) } diff --git a/packages/runtime-core/__tests__/helpers/scopeId.spec.ts b/packages/runtime-core/__tests__/helpers/scopeId.spec.ts index f570c7f0c12..235fdfe6529 100644 --- a/packages/runtime-core/__tests__/helpers/scopeId.spec.ts +++ b/packages/runtime-core/__tests__/helpers/scopeId.spec.ts @@ -1,5 +1,12 @@ import { withScopeId } from '../../src/helpers/scopeId' -import { h, render, nodeOps, serializeInner } from '@vue/runtime-test' +import { + h, + render, + nodeOps, + serializeInner, + BaseTransition, + KeepAlive +} from '@vue/runtime-test' describe('scopeId runtime support', () => { const withParentId = withScopeId('parent') @@ -102,4 +109,54 @@ describe('scopeId runtime support', () => { expect(serializeInner(root)).toBe(`
`) }) + + test("The Transition component should inherit its parent's scopeId", () => { + const Child = { + __scopeId: 'child', + render: withChildId(function(this: any) { + return h(BaseTransition, withChildId(() => this.$slots.default())) + }) + } + const App = { + __scopeId: 'parent', + render: withParentId(() => { + return h( + 'div', + h(Child, null, { + default: withParentId(() => h('span')) + }) + ) + }) + } + const root = nodeOps.createElement('div') + render(h(App), root) + expect(serializeInner(root)).toBe( + `
` + ) + }) + + test("The KeepAlive component should inherit its parent's scopeId", () => { + const Child = { + __scopeId: 'child', + render: withChildId(function(this: any) { + return h(KeepAlive, withChildId(() => this.$slots.default())) + }) + } + const App = { + __scopeId: 'parent', + render: withParentId((ctx: any) => { + return h( + 'div', + h(Child, null, { + default: withParentId(() => h('span')) + }) + ) + }) + } + const root = nodeOps.createElement('div') + render(h(App), root) + expect(serializeInner(root)).toBe( + `
` + ) + }) }) diff --git a/packages/runtime-core/src/component.ts b/packages/runtime-core/src/component.ts index 9b142036219..f9971b32e90 100644 --- a/packages/runtime-core/src/component.ts +++ b/packages/runtime-core/src/component.ts @@ -87,6 +87,10 @@ export interface ComponentInternalOptions { * @internal */ __scopeId?: string + /** + * @internal + */ + __inheritScopeId?: boolean /** * @internal */ diff --git a/packages/runtime-core/src/components/BaseTransition.ts b/packages/runtime-core/src/components/BaseTransition.ts index 674eb795616..c25af6fed2f 100644 --- a/packages/runtime-core/src/components/BaseTransition.ts +++ b/packages/runtime-core/src/components/BaseTransition.ts @@ -113,6 +113,8 @@ const TransitionHookValidator = [Function, Array] const BaseTransitionImpl = { name: `BaseTransition`, + __inheritScopeId: true, + props: { mode: String, appear: Boolean, diff --git a/packages/runtime-core/src/components/KeepAlive.ts b/packages/runtime-core/src/components/KeepAlive.ts index 6ad53fda72e..5c73595c331 100644 --- a/packages/runtime-core/src/components/KeepAlive.ts +++ b/packages/runtime-core/src/components/KeepAlive.ts @@ -70,6 +70,8 @@ const KeepAliveImpl = { // would prevent it from being tree-shaken. __isKeepAlive: true, + __inheritScopeId: true, + props: { include: [String, RegExp, Array], exclude: [String, RegExp, Array], diff --git a/packages/runtime-core/src/renderer.ts b/packages/runtime-core/src/renderer.ts index bc1d154527b..9d46fe6fd8b 100644 --- a/packages/runtime-core/src/renderer.ts +++ b/packages/runtime-core/src/renderer.ts @@ -807,6 +807,15 @@ function baseCreateRenderer( } } + const getTreeOwnerWithScopeId = ( + parent: ComponentInternalInstance + ): ComponentInternalInstance => { + if (parent.type.__inheritScopeId && parent.parent) { + return getTreeOwnerWithScopeId(parent.parent) + } + return parent + } + const setScopeId = ( el: RendererElement, scopeId: string | false | null, @@ -817,13 +826,14 @@ function baseCreateRenderer( hostSetScopeId(el, scopeId) } if (parentComponent) { - const treeOwnerId = parentComponent.type.__scopeId + const treeOwner = getTreeOwnerWithScopeId(parentComponent) + const treeOwnerId = treeOwner.type.__scopeId // vnode's own scopeId and the current patched component's scopeId is // different - this is a slot content node. if (treeOwnerId && treeOwnerId !== scopeId) { hostSetScopeId(el, treeOwnerId + '-s') } - let subTree = parentComponent.subTree + let subTree = treeOwner.subTree if (__DEV__ && subTree.type === Fragment) { subTree = filterSingleRoot(subTree.children as VNodeArrayChildren) || subTree diff --git a/packages/runtime-dom/src/components/Transition.ts b/packages/runtime-dom/src/components/Transition.ts index 2c0248825e5..7caf00ec44d 100644 --- a/packages/runtime-dom/src/components/Transition.ts +++ b/packages/runtime-dom/src/components/Transition.ts @@ -43,6 +43,7 @@ export const Transition: FunctionalComponent = ( ) => h(BaseTransition, resolveTransitionProps(props), slots) Transition.displayName = 'Transition' +Transition.__inheritScopeId = true const DOMTransitionPropsValidators = { name: String, diff --git a/packages/runtime-dom/src/components/TransitionGroup.ts b/packages/runtime-dom/src/components/TransitionGroup.ts index 16a6aa39ee1..47b95114592 100644 --- a/packages/runtime-dom/src/components/TransitionGroup.ts +++ b/packages/runtime-dom/src/components/TransitionGroup.ts @@ -40,6 +40,8 @@ export type TransitionGroupProps = Omit & { const TransitionGroupImpl = { name: 'TransitionGroup', + __inheritScopeId: true, + props: /*#__PURE__*/ extend({}, TransitionPropsValidators, { tag: String, moveClass: String