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
|
||||
*/
|
||||
n?: () => Promise<void>
|
||||
/**
|
||||
* `updateTeleportCssVars`
|
||||
* For updating css vars on contained teleports
|
||||
* @internal
|
||||
*/
|
||||
ut?: (vars?: Record<string, string>) => void
|
||||
}
|
||||
|
||||
const emptyAppContext = createAppContext()
|
||||
|
|
|
@ -222,6 +222,8 @@ export const TeleportImpl = {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
updateCssVars(parentComponent, n2)
|
||||
},
|
||||
|
||||
remove(
|
||||
|
@ -383,6 +385,7 @@ function hydrateTeleport(
|
|||
)
|
||||
}
|
||||
}
|
||||
updateCssVars(parentComponent, vnode)
|
||||
}
|
||||
return vnode.anchor && nextSibling(vnode.anchor as Node)
|
||||
}
|
||||
|
@ -392,3 +395,20 @@ export const Teleport = TeleportImpl as unknown as {
|
|||
__isTeleport: true
|
||||
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,
|
||||
ComponentOptions,
|
||||
Suspense,
|
||||
Teleport,
|
||||
FunctionalComponent
|
||||
} from '@vue/runtime-dom'
|
||||
|
||||
|
@ -196,4 +197,58 @@ describe('useCssVars', () => {
|
|||
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
|
||||
}
|
||||
|
||||
const setVars = () =>
|
||||
setVarsOnVNode(instance.subTree, getter(instance.proxy!))
|
||||
const updateTeleports = (instance.ut = (vars = 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)
|
||||
|
||||
onMounted(() => {
|
||||
const ob = new MutationObserver(setVars)
|
||||
ob.observe(instance.subTree.el!.parentNode, { childList: true })
|
||||
|
|
Loading…
Reference in New Issue