feat(portal): hydration support for portal disabled mode

This commit is contained in:
Evan You
2020-03-30 11:23:59 -04:00
parent 9ed9bf3687
commit b74bab216c
3 changed files with 244 additions and 117 deletions

View File

@@ -8,23 +8,17 @@ import {
VNodeHook
} from './vnode'
import { flushPostFlushCbs } from './scheduler'
import { ComponentInternalInstance } from './component'
import { ComponentOptions, ComponentInternalInstance } from './component'
import { invokeDirectiveHook } from './directives'
import { warn } from './warning'
import {
PatchFlags,
ShapeFlags,
isReservedProp,
isOn,
isString
} from '@vue/shared'
import { PatchFlags, ShapeFlags, isReservedProp, isOn } from '@vue/shared'
import { RendererInternals, invokeVNodeHook } from './renderer'
import {
SuspenseImpl,
SuspenseBoundary,
queueEffectWithSuspense
} from './components/Suspense'
import { ComponentOptions } from './apiOptions'
import { PortalImpl } from './components/Portal'
export type RootHydrateFunction = (
vnode: VNode<Node, Element>,
@@ -182,8 +176,15 @@ export function createHydrationFunctions(
if (domType !== DOMNodeTypes.COMMENT) {
return onMismatch()
}
hydratePortal(vnode, parentComponent, parentSuspense, optimized)
return nextSibling(node)
return (vnode.type as typeof PortalImpl).hydrate(
node,
vnode,
parentComponent,
parentSuspense,
optimized,
rendererInternals,
hydrateChildren
)
} else if (__FEATURE_SUSPENSE__ && shapeFlag & ShapeFlags.SUSPENSE) {
return (vnode.type as typeof SuspenseImpl).hydrate(
node,
@@ -366,41 +367,6 @@ export function createHydrationFunctions(
}
}
interface PortalTargetElement extends Element {
// last portal target
_lpa?: Node | null
}
const hydratePortal = (
vnode: VNode,
parentComponent: ComponentInternalInstance | null,
parentSuspense: SuspenseBoundary | null,
optimized: boolean
) => {
const targetSelector = vnode.props && vnode.props.target
const target = (vnode.target = isString(targetSelector)
? document.querySelector(targetSelector)
: targetSelector)
if (target && vnode.shapeFlag & ShapeFlags.ARRAY_CHILDREN) {
vnode.anchor = hydrateChildren(
// if multiple portals rendered to the same target element, we need to
// pick up from where the last portal finished instead of the first node
(target as PortalTargetElement)._lpa || target.firstChild,
vnode,
target,
parentComponent,
parentSuspense,
optimized
)
;(target as PortalTargetElement)._lpa = nextSibling(vnode.anchor as Node)
} else if (__DEV__) {
warn(
`Attempting to hydrate portal but target ${targetSelector} does not ` +
`exist in server-rendered markup.`
)
}
}
const handleMismtach = (
node: Node,
vnode: VNode,