mirror of https://github.com/vuejs/core.git
feat(hydration): handle consecutive if node
This commit is contained in:
parent
5ee1628687
commit
85693f0eb3
|
@ -1269,6 +1269,26 @@ describe('Vapor Mode hydration', () => {
|
||||||
expect(container.innerHTML).toBe(`<!--${anchorLabel}-->`)
|
expect(container.innerHTML).toBe(`<!--${anchorLabel}-->`)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
test('consecutive if node', async () => {
|
||||||
|
const data = ref(true)
|
||||||
|
const { container } = await testHydration(
|
||||||
|
`<template>
|
||||||
|
<components.Child v-if="data"/>
|
||||||
|
</template>`,
|
||||||
|
{ Child: `<template><div v-if="data">foo</div></template>` },
|
||||||
|
data,
|
||||||
|
)
|
||||||
|
expect(container.innerHTML).toBe(`<div>foo</div><!--if--><!--if-->`)
|
||||||
|
|
||||||
|
data.value = false
|
||||||
|
await nextTick()
|
||||||
|
expect(container.innerHTML).toBe(`<!--if-->`)
|
||||||
|
|
||||||
|
data.value = true
|
||||||
|
await nextTick()
|
||||||
|
expect(container.innerHTML).toBe(`<div>foo</div><!--if--><!--if-->`)
|
||||||
|
})
|
||||||
|
|
||||||
test('v-if/else-if/else chain on component - switch branches', async () => {
|
test('v-if/else-if/else chain on component - switch branches', async () => {
|
||||||
const data = ref('a')
|
const data = ref('a')
|
||||||
const { container } = await testHydration(
|
const { container } = await testHydration(
|
||||||
|
|
|
@ -8,6 +8,7 @@ import {
|
||||||
import { createComment, createTextNode } from './dom/node'
|
import { createComment, createTextNode } from './dom/node'
|
||||||
import { EffectScope, setActiveSub } from '@vue/reactivity'
|
import { EffectScope, setActiveSub } from '@vue/reactivity'
|
||||||
import {
|
import {
|
||||||
|
advanceHydrationNode,
|
||||||
currentHydrationNode,
|
currentHydrationNode,
|
||||||
isComment,
|
isComment,
|
||||||
isHydrating,
|
isHydrating,
|
||||||
|
@ -41,12 +42,13 @@ export class DynamicFragment extends VaporFragment {
|
||||||
current?: BlockFn
|
current?: BlockFn
|
||||||
fallback?: BlockFn
|
fallback?: BlockFn
|
||||||
teardown?: () => void
|
teardown?: () => void
|
||||||
|
anchorLabel?: string
|
||||||
|
|
||||||
constructor(anchorLabel?: string) {
|
constructor(anchorLabel?: string) {
|
||||||
super([])
|
super([])
|
||||||
if (isHydrating) {
|
if (isHydrating) {
|
||||||
|
this.anchorLabel = anchorLabel
|
||||||
locateHydrationNode()
|
locateHydrationNode()
|
||||||
this.hydrate(anchorLabel!)
|
|
||||||
} else {
|
} else {
|
||||||
this.anchor =
|
this.anchor =
|
||||||
__DEV__ && anchorLabel ? createComment(anchorLabel) : createTextNode()
|
__DEV__ && anchorLabel ? createComment(anchorLabel) : createTextNode()
|
||||||
|
@ -55,12 +57,13 @@ export class DynamicFragment extends VaporFragment {
|
||||||
|
|
||||||
update(render?: BlockFn, key: any = render): void {
|
update(render?: BlockFn, key: any = render): void {
|
||||||
if (key === this.current) {
|
if (key === this.current) {
|
||||||
|
if (isHydrating) this.hydrate(this.anchorLabel!)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
this.current = key
|
this.current = key
|
||||||
|
|
||||||
const prevSub = setActiveSub()
|
const prevSub = setActiveSub()
|
||||||
const parent = this.anchor.parentNode
|
const parent = isHydrating ? null : this.anchor.parentNode
|
||||||
|
|
||||||
// teardown previous branch
|
// teardown previous branch
|
||||||
if (this.scope) {
|
if (this.scope) {
|
||||||
|
@ -89,6 +92,8 @@ export class DynamicFragment extends VaporFragment {
|
||||||
}
|
}
|
||||||
|
|
||||||
setActiveSub(prevSub)
|
setActiveSub(prevSub)
|
||||||
|
|
||||||
|
if (isHydrating) this.hydrate(this.anchorLabel!)
|
||||||
}
|
}
|
||||||
|
|
||||||
hydrate(label: string): void {
|
hydrate(label: string): void {
|
||||||
|
@ -105,6 +110,7 @@ export class DynamicFragment extends VaporFragment {
|
||||||
throw new Error(`${label} fragment anchor node was not found.`)
|
throw new Error(`${label} fragment anchor node was not found.`)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
advanceHydrationNode(this.anchor)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -19,6 +19,10 @@ export function setCurrentHydrationNode(node: Node | null): void {
|
||||||
currentHydrationNode = node
|
currentHydrationNode = node
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function advanceHydrationNode(node: Node): void {
|
||||||
|
setCurrentHydrationNode(node.nextSibling || node.parentNode)
|
||||||
|
}
|
||||||
|
|
||||||
let isOptimized = false
|
let isOptimized = false
|
||||||
|
|
||||||
function performHydration<T>(
|
function performHydration<T>(
|
||||||
|
@ -96,7 +100,7 @@ function adoptTemplateImpl(node: Node, template: string): Node | null {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
currentHydrationNode = node.nextSibling
|
advanceHydrationNode(node)
|
||||||
return node
|
return node
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -169,12 +173,12 @@ export function isNonHydrationNode(node: Node): boolean {
|
||||||
export function locateVaporFragmentAnchor(
|
export function locateVaporFragmentAnchor(
|
||||||
node: Node,
|
node: Node,
|
||||||
anchorLabel: string,
|
anchorLabel: string,
|
||||||
): Comment | undefined {
|
): Comment | null {
|
||||||
let n = node.nextSibling
|
while (node) {
|
||||||
while (n) {
|
if (isComment(node, anchorLabel)) return node
|
||||||
if (isComment(n, anchorLabel)) return n
|
node = node.nextSibling!
|
||||||
n = n.nextSibling
|
|
||||||
}
|
}
|
||||||
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
export function isEmptyTextNode(node: Node): node is Text {
|
export function isEmptyTextNode(node: Node): node is Text {
|
||||||
|
|
Loading…
Reference in New Issue