wip: portal
This commit is contained in:
parent
178c7c827e
commit
453cdcd600
@ -14,7 +14,14 @@ import {
|
||||
createComponentInstance,
|
||||
setupStatefulComponent
|
||||
} from './component'
|
||||
import { isString, isArray, EMPTY_OBJ, EMPTY_ARR } from '@vue/shared'
|
||||
import {
|
||||
isString,
|
||||
isArray,
|
||||
isFunction,
|
||||
isObject,
|
||||
EMPTY_OBJ,
|
||||
EMPTY_ARR
|
||||
} from '@vue/shared'
|
||||
import { TEXT, CLASS, STYLE, PROPS, KEYED, UNKEYED } from './patchFlags'
|
||||
import { queueJob, queuePostFlushCb, flushPostFlushCbs } from './scheduler'
|
||||
import { effect, stop, ReactiveEffectOptions } from '@vue/observer'
|
||||
@ -69,6 +76,7 @@ export interface RendererOptions {
|
||||
setElementText(node: HostNode, text: string): void
|
||||
parentNode(node: HostNode): HostNode | null
|
||||
nextSibling(node: HostNode): HostNode | null
|
||||
querySelector(selector: string): HostNode | null
|
||||
}
|
||||
|
||||
export function createRenderer(options: RendererOptions) {
|
||||
@ -82,7 +90,8 @@ export function createRenderer(options: RendererOptions) {
|
||||
setText: hostSetText,
|
||||
setElementText: hostSetElementText,
|
||||
parentNode: hostParentNode,
|
||||
nextSibling: hostNextSibling
|
||||
nextSibling: hostNextSibling,
|
||||
querySelector: hostQuerySelector
|
||||
} = options
|
||||
|
||||
function patch(
|
||||
@ -111,12 +120,15 @@ export function createRenderer(options: RendererOptions) {
|
||||
processFragment(n1, n2, container, anchor, optimized)
|
||||
break
|
||||
case Portal:
|
||||
// TODO
|
||||
processPortal(n1, n2, container, anchor, optimized)
|
||||
break
|
||||
default:
|
||||
if (isString(type)) {
|
||||
processElement(n1, n2, container, anchor, optimized)
|
||||
} else {
|
||||
if (__DEV__ && !isFunction(type) && !isObject(type)) {
|
||||
// TODO warn invalid node type
|
||||
}
|
||||
processComponent(n1, n2, container, anchor)
|
||||
}
|
||||
break
|
||||
@ -340,6 +352,61 @@ export function createRenderer(options: RendererOptions) {
|
||||
}
|
||||
}
|
||||
|
||||
function processPortal(
|
||||
n1: VNode | null,
|
||||
n2: VNode,
|
||||
container: HostNode,
|
||||
anchor?: HostNode,
|
||||
optimized?: boolean
|
||||
) {
|
||||
const targetSelector = n2.props && n2.props.target
|
||||
if (n1 == null) {
|
||||
const children = n2.children
|
||||
const target = (n2.target = isString(targetSelector)
|
||||
? hostQuerySelector(targetSelector)
|
||||
: null)
|
||||
if (target != null) {
|
||||
if (isString(children)) {
|
||||
hostSetElementText(target, children)
|
||||
} else if (children != null) {
|
||||
mountChildren(children, target)
|
||||
}
|
||||
} else {
|
||||
// TODO warn missing or invalid target
|
||||
}
|
||||
} else {
|
||||
// update content
|
||||
const target = (n2.target = n1.target)
|
||||
if (n2.patchFlag === TEXT) {
|
||||
hostSetElementText(target, n2.children as string)
|
||||
} else if (!optimized) {
|
||||
patchChildren(n1, n2, target)
|
||||
}
|
||||
// target changed
|
||||
if (targetSelector !== (n1.props && n1.props.target)) {
|
||||
const nextTarget = (n2.target = isString(targetSelector)
|
||||
? hostQuerySelector(targetSelector)
|
||||
: null)
|
||||
if (nextTarget != null) {
|
||||
// move content
|
||||
const children = n2.children
|
||||
if (isString(children)) {
|
||||
hostSetElementText(target, '')
|
||||
hostSetElementText(nextTarget, children)
|
||||
} else if (children != null) {
|
||||
for (let i = 0; i < children.length; i++) {
|
||||
move(children[i] as VNode, nextTarget, null)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// TODO warn missing or invalid target
|
||||
}
|
||||
}
|
||||
}
|
||||
// insert an empty node as the placeholder for the portal
|
||||
processEmptyNode(n1, n2, container, anchor)
|
||||
}
|
||||
|
||||
function processComponent(
|
||||
n1: VNode | null,
|
||||
n2: VNode,
|
||||
@ -409,8 +476,9 @@ export function createRenderer(options: RendererOptions) {
|
||||
patch(
|
||||
prevTree,
|
||||
nextTree,
|
||||
container || hostParentNode(prevTree.el),
|
||||
anchor || getNextHostNode(prevTree)
|
||||
// may have moved
|
||||
hostParentNode(prevTree.el),
|
||||
getNextHostNode(prevTree)
|
||||
)
|
||||
if (next != null) {
|
||||
next.el = nextTree.el
|
||||
|
@ -4,8 +4,7 @@ export {
|
||||
createBlock,
|
||||
createVNode,
|
||||
Fragment,
|
||||
Text,
|
||||
Empty
|
||||
Portal
|
||||
} from './vnode'
|
||||
|
||||
export {
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { isArray, isFunction } from '@vue/shared'
|
||||
import { isArray, isFunction, EMPTY_ARR } from '@vue/shared'
|
||||
import { ComponentInstance } from './component'
|
||||
import { HostNode } from './createRenderer'
|
||||
|
||||
@ -29,6 +29,7 @@ export interface VNode {
|
||||
// DOM
|
||||
el: HostNode | null
|
||||
anchor: HostNode | null // fragment anchor
|
||||
target: HostNode | null // portal target
|
||||
|
||||
// optimization only
|
||||
patchFlag: number | null
|
||||
@ -59,7 +60,7 @@ export function createBlock(
|
||||
shouldTrack = true
|
||||
const trackedNodes = blockStack.pop()
|
||||
vnode.dynamicChildren =
|
||||
trackedNodes && trackedNodes.length ? trackedNodes : null
|
||||
trackedNodes && trackedNodes.length ? trackedNodes : EMPTY_ARR
|
||||
// a block is always going to be patched
|
||||
trackDynamicNode(vnode)
|
||||
return vnode
|
||||
@ -81,6 +82,7 @@ export function createVNode(
|
||||
component: null,
|
||||
el: null,
|
||||
anchor: null,
|
||||
target: null,
|
||||
patchFlag,
|
||||
dynamicProps,
|
||||
dynamicChildren: null
|
||||
|
@ -1,6 +1,7 @@
|
||||
import { RendererOptions } from '@vue/runtime-core'
|
||||
import { patchProp } from './patchProp'
|
||||
|
||||
const doc = document
|
||||
const svgNS = 'http://www.w3.org/2000/svg'
|
||||
|
||||
export const DOMRendererOptions: RendererOptions = {
|
||||
@ -23,11 +24,11 @@ export const DOMRendererOptions: RendererOptions = {
|
||||
},
|
||||
|
||||
createElement: (tag: string, isSVG?: boolean): Element =>
|
||||
isSVG ? document.createElementNS(svgNS, tag) : document.createElement(tag),
|
||||
isSVG ? doc.createElementNS(svgNS, tag) : doc.createElement(tag),
|
||||
|
||||
createText: (text: string): Text => document.createTextNode(text),
|
||||
createText: (text: string): Text => doc.createTextNode(text),
|
||||
|
||||
createComment: (text: string): Comment => document.createComment(text),
|
||||
createComment: (text: string): Comment => doc.createComment(text),
|
||||
|
||||
setText: (node: Text, text: string) => {
|
||||
node.nodeValue = text
|
||||
@ -39,5 +40,7 @@ export const DOMRendererOptions: RendererOptions = {
|
||||
|
||||
parentNode: (node: Node): Node | null => node.parentNode,
|
||||
|
||||
nextSibling: (node: Node): Node | null => node.nextSibling
|
||||
nextSibling: (node: Node): Node | null => node.nextSibling,
|
||||
|
||||
querySelector: (selector: string): Node | null => doc.querySelector(selector)
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user