mirror of https://github.com/vuejs/core.git
fix(teleport/css-v-bind): fix css v-bind for teleported content
fix #4605 close #4609 (used tests from this PR)
This commit is contained in:
parent
9ca8b7c1b5
commit
42239cf284
|
@ -458,6 +458,12 @@ export interface ComponentInternalInstance {
|
||||||
* @internal
|
* @internal
|
||||||
*/
|
*/
|
||||||
n?: () => Promise<void>
|
n?: () => Promise<void>
|
||||||
|
/**
|
||||||
|
* `updateTeleportCssVars`
|
||||||
|
* For updating css vars on contained teleports
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
ut?: (vars?: Record<string, string>) => void
|
||||||
}
|
}
|
||||||
|
|
||||||
const emptyAppContext = createAppContext()
|
const emptyAppContext = createAppContext()
|
||||||
|
|
|
@ -222,6 +222,8 @@ export const TeleportImpl = {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
updateCssVars(parentComponent, n2)
|
||||||
},
|
},
|
||||||
|
|
||||||
remove(
|
remove(
|
||||||
|
@ -383,6 +385,7 @@ function hydrateTeleport(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
updateCssVars(parentComponent, vnode)
|
||||||
}
|
}
|
||||||
return vnode.anchor && nextSibling(vnode.anchor as Node)
|
return vnode.anchor && nextSibling(vnode.anchor as Node)
|
||||||
}
|
}
|
||||||
|
@ -392,3 +395,20 @@ export const Teleport = TeleportImpl as unknown as {
|
||||||
__isTeleport: true
|
__isTeleport: true
|
||||||
new (): { $props: VNodeProps & TeleportProps }
|
new (): { $props: VNodeProps & TeleportProps }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function updateCssVars(
|
||||||
|
parentComponent: ComponentInternalInstance | null,
|
||||||
|
vnode: VNode
|
||||||
|
) {
|
||||||
|
// presence of .ut method indicates owner component uses css vars.
|
||||||
|
// code path here can assume browser environment.
|
||||||
|
if (parentComponent && parentComponent.ut) {
|
||||||
|
let node = (vnode.children as VNode[])[0].el!
|
||||||
|
while (node !== vnode.targetAnchor) {
|
||||||
|
if (node.nodeType === 1)
|
||||||
|
node.setAttribute('data-v-owner', parentComponent.uid)
|
||||||
|
node = node.nextSibling
|
||||||
|
}
|
||||||
|
parentComponent.ut()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -8,6 +8,7 @@ import {
|
||||||
nextTick,
|
nextTick,
|
||||||
ComponentOptions,
|
ComponentOptions,
|
||||||
Suspense,
|
Suspense,
|
||||||
|
Teleport,
|
||||||
FunctionalComponent
|
FunctionalComponent
|
||||||
} from '@vue/runtime-dom'
|
} from '@vue/runtime-dom'
|
||||||
|
|
||||||
|
@ -196,4 +197,58 @@ describe('useCssVars', () => {
|
||||||
expect((c as HTMLElement).style.getPropertyValue(`--color`)).toBe('red')
|
expect((c as HTMLElement).style.getPropertyValue(`--color`)).toBe('red')
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
test('with teleport', async () => {
|
||||||
|
document.body.innerHTML = ''
|
||||||
|
const state = reactive({ color: 'red' })
|
||||||
|
const root = document.createElement('div')
|
||||||
|
const target = document.body
|
||||||
|
|
||||||
|
const App = {
|
||||||
|
setup() {
|
||||||
|
useCssVars(() => state)
|
||||||
|
return () => [h(Teleport, { to: target }, [h('div')])]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
render(h(App), root)
|
||||||
|
await nextTick()
|
||||||
|
for (const c of [].slice.call(target.children as any)) {
|
||||||
|
expect((c as HTMLElement).style.getPropertyValue(`--color`)).toBe('red')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
test('with teleport(change subTree)', async () => {
|
||||||
|
document.body.innerHTML = ''
|
||||||
|
const state = reactive({ color: 'red' })
|
||||||
|
const root = document.createElement('div')
|
||||||
|
const target = document.body
|
||||||
|
const toggle = ref(false)
|
||||||
|
|
||||||
|
const App = {
|
||||||
|
setup() {
|
||||||
|
useCssVars(() => state)
|
||||||
|
return () => [
|
||||||
|
h(Teleport, { to: target }, [
|
||||||
|
h('div'),
|
||||||
|
toggle.value ? h('div') : null
|
||||||
|
])
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
render(h(App), root)
|
||||||
|
await nextTick()
|
||||||
|
expect(target.children.length).toBe(1)
|
||||||
|
for (const c of [].slice.call(target.children as any)) {
|
||||||
|
expect((c as HTMLElement).style.getPropertyValue(`--color`)).toBe('red')
|
||||||
|
}
|
||||||
|
|
||||||
|
toggle.value = true
|
||||||
|
await nextTick()
|
||||||
|
expect(target.children.length).toBe(2)
|
||||||
|
for (const c of [].slice.call(target.children as any)) {
|
||||||
|
expect((c as HTMLElement).style.getPropertyValue(`--color`)).toBe('red')
|
||||||
|
}
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
|
@ -25,9 +25,20 @@ export function useCssVars(getter: (ctx: any) => Record<string, string>) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
const setVars = () =>
|
const updateTeleports = (instance.ut = (vars = getter(instance.proxy)) => {
|
||||||
setVarsOnVNode(instance.subTree, getter(instance.proxy!))
|
Array.from(
|
||||||
|
document.querySelectorAll(`[data-v-owner="${instance.uid}"]`)
|
||||||
|
).forEach(node => setVarsOnNode(node, vars))
|
||||||
|
})
|
||||||
|
|
||||||
|
const setVars = () => {
|
||||||
|
const vars = getter(instance.proxy)
|
||||||
|
setVarsOnVNode(instance.subTree, vars)
|
||||||
|
updateTeleports(vars)
|
||||||
|
}
|
||||||
|
|
||||||
watchPostEffect(setVars)
|
watchPostEffect(setVars)
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
const ob = new MutationObserver(setVars)
|
const ob = new MutationObserver(setVars)
|
||||||
ob.observe(instance.subTree.el!.parentNode, { childList: true })
|
ob.observe(instance.subTree.el!.parentNode, { childList: true })
|
||||||
|
|
Loading…
Reference in New Issue