|
|
|
|
@@ -38,6 +38,8 @@ import { PatchFlags } from './patchFlags'
|
|
|
|
|
import { ShapeFlags } from './shapeFlags'
|
|
|
|
|
import { pushWarningContext, popWarningContext, warn } from './warning'
|
|
|
|
|
import { invokeDirectiveHook } from './directives'
|
|
|
|
|
import { ComponentPublicInstance } from './componentPublicInstanceProxy'
|
|
|
|
|
import { App, createAppAPI } from './apiApp'
|
|
|
|
|
|
|
|
|
|
const prodEffectOptions = {
|
|
|
|
|
scheduler: queueJob
|
|
|
|
|
@@ -67,40 +69,64 @@ function invokeHooks(hooks: Function[], arg?: any) {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export type HostNode = any
|
|
|
|
|
|
|
|
|
|
export interface RendererOptions {
|
|
|
|
|
export interface RendererOptions<HostNode = any, HostElement = any> {
|
|
|
|
|
patchProp(
|
|
|
|
|
el: HostNode,
|
|
|
|
|
el: HostElement,
|
|
|
|
|
key: string,
|
|
|
|
|
value: any,
|
|
|
|
|
oldValue: any,
|
|
|
|
|
isSVG: boolean,
|
|
|
|
|
prevChildren?: VNode[],
|
|
|
|
|
prevChildren?: VNode<HostNode, HostElement>[],
|
|
|
|
|
parentComponent?: ComponentInternalInstance | null,
|
|
|
|
|
unmountChildren?: (
|
|
|
|
|
children: VNode[],
|
|
|
|
|
children: VNode<HostNode, HostElement>[],
|
|
|
|
|
parentComponent: ComponentInternalInstance | null
|
|
|
|
|
) => void
|
|
|
|
|
): void
|
|
|
|
|
insert(el: HostNode, parent: HostNode, anchor?: HostNode): void
|
|
|
|
|
insert(el: HostNode, parent: HostElement, anchor?: HostNode | null): void
|
|
|
|
|
remove(el: HostNode): void
|
|
|
|
|
createElement(type: string, isSVG?: boolean): HostNode
|
|
|
|
|
createElement(type: string, isSVG?: boolean): HostElement
|
|
|
|
|
createText(text: string): HostNode
|
|
|
|
|
createComment(text: string): HostNode
|
|
|
|
|
setText(node: HostNode, text: string): void
|
|
|
|
|
setElementText(node: HostNode, text: string): void
|
|
|
|
|
setElementText(node: HostElement, text: string): void
|
|
|
|
|
parentNode(node: HostNode): HostNode | null
|
|
|
|
|
nextSibling(node: HostNode): HostNode | null
|
|
|
|
|
querySelector(selector: string): HostNode | null
|
|
|
|
|
querySelector(selector: string): HostElement | null
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export type RootRenderFunction = (
|
|
|
|
|
vnode: VNode | null,
|
|
|
|
|
dom: HostNode | string
|
|
|
|
|
export type RootRenderFunction<HostNode, HostElement> = (
|
|
|
|
|
vnode: VNode<HostNode, HostElement> | null,
|
|
|
|
|
dom: HostElement | string
|
|
|
|
|
) => void
|
|
|
|
|
|
|
|
|
|
export function createRenderer(options: RendererOptions): RootRenderFunction {
|
|
|
|
|
/**
|
|
|
|
|
* The createRenderer function accepts two generic arguments:
|
|
|
|
|
* HostNode and HostElement, corresponding to Node and Element types in the
|
|
|
|
|
* host environment. For example, for runtime-dom, HostNode would be the DOM
|
|
|
|
|
* `Node` interface and HostElement would be the DOM `Element` interface.
|
|
|
|
|
*
|
|
|
|
|
* Custom renderers can pass in the platform specific types like this:
|
|
|
|
|
*
|
|
|
|
|
* ``` js
|
|
|
|
|
* const { render, createApp } = createRenderer<Node, Element>({
|
|
|
|
|
* patchProp,
|
|
|
|
|
* ...nodeOps
|
|
|
|
|
* })
|
|
|
|
|
* ```
|
|
|
|
|
*/
|
|
|
|
|
export function createRenderer<
|
|
|
|
|
HostNode extends object = any,
|
|
|
|
|
HostElement extends HostNode = any
|
|
|
|
|
>(
|
|
|
|
|
options: RendererOptions<HostNode, HostElement>
|
|
|
|
|
): {
|
|
|
|
|
render: RootRenderFunction<HostNode, HostElement>
|
|
|
|
|
createApp: () => App<HostElement>
|
|
|
|
|
} {
|
|
|
|
|
type HostVNode = VNode<HostNode, HostElement>
|
|
|
|
|
type HostVNodeChildren = VNodeChildren<HostNode, HostElement>
|
|
|
|
|
|
|
|
|
|
const {
|
|
|
|
|
insert: hostInsert,
|
|
|
|
|
remove: hostRemove,
|
|
|
|
|
@@ -116,10 +142,10 @@ export function createRenderer(options: RendererOptions): RootRenderFunction {
|
|
|
|
|
} = options
|
|
|
|
|
|
|
|
|
|
function patch(
|
|
|
|
|
n1: VNode | null, // null means this is a mount
|
|
|
|
|
n2: VNode,
|
|
|
|
|
container: HostNode,
|
|
|
|
|
anchor: HostNode = null,
|
|
|
|
|
n1: HostVNode | null, // null means this is a mount
|
|
|
|
|
n2: HostVNode,
|
|
|
|
|
container: HostElement,
|
|
|
|
|
anchor: HostNode | null = null,
|
|
|
|
|
parentComponent: ComponentInternalInstance | null = null,
|
|
|
|
|
isSVG: boolean = false,
|
|
|
|
|
optimized: boolean = false
|
|
|
|
|
@@ -183,16 +209,16 @@ export function createRenderer(options: RendererOptions): RootRenderFunction {
|
|
|
|
|
optimized
|
|
|
|
|
)
|
|
|
|
|
} else if (__DEV__) {
|
|
|
|
|
warn('Invalid VNode type:', n2.type, `(${typeof n2.type})`)
|
|
|
|
|
warn('Invalid HostVNode type:', n2.type, `(${typeof n2.type})`)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function processText(
|
|
|
|
|
n1: VNode | null,
|
|
|
|
|
n2: VNode,
|
|
|
|
|
container: HostNode,
|
|
|
|
|
anchor: HostNode
|
|
|
|
|
n1: HostVNode | null,
|
|
|
|
|
n2: HostVNode,
|
|
|
|
|
container: HostElement,
|
|
|
|
|
anchor: HostNode | null
|
|
|
|
|
) {
|
|
|
|
|
if (n1 == null) {
|
|
|
|
|
hostInsert(
|
|
|
|
|
@@ -201,7 +227,7 @@ export function createRenderer(options: RendererOptions): RootRenderFunction {
|
|
|
|
|
anchor
|
|
|
|
|
)
|
|
|
|
|
} else {
|
|
|
|
|
const el = (n2.el = n1.el)
|
|
|
|
|
const el = (n2.el = n1.el) as HostNode
|
|
|
|
|
if (n2.children !== n1.children) {
|
|
|
|
|
hostSetText(el, n2.children as string)
|
|
|
|
|
}
|
|
|
|
|
@@ -209,10 +235,10 @@ export function createRenderer(options: RendererOptions): RootRenderFunction {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function processEmptyNode(
|
|
|
|
|
n1: VNode | null,
|
|
|
|
|
n2: VNode,
|
|
|
|
|
container: HostNode,
|
|
|
|
|
anchor: HostNode
|
|
|
|
|
n1: HostVNode | null,
|
|
|
|
|
n2: HostVNode,
|
|
|
|
|
container: HostElement,
|
|
|
|
|
anchor: HostNode | null
|
|
|
|
|
) {
|
|
|
|
|
if (n1 == null) {
|
|
|
|
|
hostInsert((n2.el = hostCreateComment('')), container, anchor)
|
|
|
|
|
@@ -222,10 +248,10 @@ export function createRenderer(options: RendererOptions): RootRenderFunction {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function processElement(
|
|
|
|
|
n1: VNode | null,
|
|
|
|
|
n2: VNode,
|
|
|
|
|
container: HostNode,
|
|
|
|
|
anchor: HostNode,
|
|
|
|
|
n1: HostVNode | null,
|
|
|
|
|
n2: HostVNode,
|
|
|
|
|
container: HostElement,
|
|
|
|
|
anchor: HostNode | null,
|
|
|
|
|
parentComponent: ComponentInternalInstance | null,
|
|
|
|
|
isSVG: boolean,
|
|
|
|
|
optimized: boolean
|
|
|
|
|
@@ -241,9 +267,9 @@ export function createRenderer(options: RendererOptions): RootRenderFunction {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function mountElement(
|
|
|
|
|
vnode: VNode,
|
|
|
|
|
container: HostNode,
|
|
|
|
|
anchor: HostNode,
|
|
|
|
|
vnode: HostVNode,
|
|
|
|
|
container: HostElement,
|
|
|
|
|
anchor: HostNode | null,
|
|
|
|
|
parentComponent: ComponentInternalInstance | null,
|
|
|
|
|
isSVG: boolean
|
|
|
|
|
) {
|
|
|
|
|
@@ -264,7 +290,7 @@ export function createRenderer(options: RendererOptions): RootRenderFunction {
|
|
|
|
|
hostSetElementText(el, vnode.children as string)
|
|
|
|
|
} else if (shapeFlag & ShapeFlags.ARRAY_CHILDREN) {
|
|
|
|
|
mountChildren(
|
|
|
|
|
vnode.children as VNodeChildren,
|
|
|
|
|
vnode.children as HostVNodeChildren,
|
|
|
|
|
el,
|
|
|
|
|
null,
|
|
|
|
|
parentComponent,
|
|
|
|
|
@@ -280,9 +306,9 @@ export function createRenderer(options: RendererOptions): RootRenderFunction {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function mountChildren(
|
|
|
|
|
children: VNodeChildren,
|
|
|
|
|
container: HostNode,
|
|
|
|
|
anchor: HostNode,
|
|
|
|
|
children: HostVNodeChildren,
|
|
|
|
|
container: HostElement,
|
|
|
|
|
anchor: HostNode | null,
|
|
|
|
|
parentComponent: ComponentInternalInstance | null,
|
|
|
|
|
isSVG: boolean,
|
|
|
|
|
start: number = 0
|
|
|
|
|
@@ -294,13 +320,13 @@ export function createRenderer(options: RendererOptions): RootRenderFunction {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function patchElement(
|
|
|
|
|
n1: VNode,
|
|
|
|
|
n2: VNode,
|
|
|
|
|
n1: HostVNode,
|
|
|
|
|
n2: HostVNode,
|
|
|
|
|
parentComponent: ComponentInternalInstance | null,
|
|
|
|
|
isSVG: boolean,
|
|
|
|
|
optimized: boolean
|
|
|
|
|
) {
|
|
|
|
|
const el = (n2.el = n1.el)
|
|
|
|
|
const el = (n2.el = n1.el) as HostElement
|
|
|
|
|
const { patchFlag, dynamicChildren } = n2
|
|
|
|
|
const oldProps = (n1 && n1.props) || EMPTY_OBJ
|
|
|
|
|
const newProps = n2.props || EMPTY_OBJ
|
|
|
|
|
@@ -353,7 +379,7 @@ export function createRenderer(options: RendererOptions): RootRenderFunction {
|
|
|
|
|
next,
|
|
|
|
|
prev,
|
|
|
|
|
isSVG,
|
|
|
|
|
n1.children as VNode[],
|
|
|
|
|
n1.children as HostVNode[],
|
|
|
|
|
parentComponent,
|
|
|
|
|
unmountChildren
|
|
|
|
|
)
|
|
|
|
|
@@ -378,7 +404,7 @@ export function createRenderer(options: RendererOptions): RootRenderFunction {
|
|
|
|
|
|
|
|
|
|
if (dynamicChildren != null) {
|
|
|
|
|
// children fast path
|
|
|
|
|
const olddynamicChildren = n1.dynamicChildren as VNode[]
|
|
|
|
|
const olddynamicChildren = n1.dynamicChildren as HostVNode[]
|
|
|
|
|
for (let i = 0; i < dynamicChildren.length; i++) {
|
|
|
|
|
patch(
|
|
|
|
|
olddynamicChildren[i],
|
|
|
|
|
@@ -403,8 +429,8 @@ export function createRenderer(options: RendererOptions): RootRenderFunction {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function patchProps(
|
|
|
|
|
el: HostNode,
|
|
|
|
|
vnode: VNode,
|
|
|
|
|
el: HostElement,
|
|
|
|
|
vnode: HostVNode,
|
|
|
|
|
oldProps: any,
|
|
|
|
|
newProps: any,
|
|
|
|
|
parentComponent: ComponentInternalInstance | null,
|
|
|
|
|
@@ -422,7 +448,7 @@ export function createRenderer(options: RendererOptions): RootRenderFunction {
|
|
|
|
|
next,
|
|
|
|
|
prev,
|
|
|
|
|
isSVG,
|
|
|
|
|
vnode.children as VNode[],
|
|
|
|
|
vnode.children as HostVNode[],
|
|
|
|
|
parentComponent,
|
|
|
|
|
unmountChildren
|
|
|
|
|
)
|
|
|
|
|
@@ -438,7 +464,7 @@ export function createRenderer(options: RendererOptions): RootRenderFunction {
|
|
|
|
|
null,
|
|
|
|
|
null,
|
|
|
|
|
isSVG,
|
|
|
|
|
vnode.children as VNode[],
|
|
|
|
|
vnode.children as HostVNode[],
|
|
|
|
|
parentComponent,
|
|
|
|
|
unmountChildren
|
|
|
|
|
)
|
|
|
|
|
@@ -449,24 +475,26 @@ export function createRenderer(options: RendererOptions): RootRenderFunction {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function processFragment(
|
|
|
|
|
n1: VNode | null,
|
|
|
|
|
n2: VNode,
|
|
|
|
|
container: HostNode,
|
|
|
|
|
anchor: HostNode,
|
|
|
|
|
n1: HostVNode | null,
|
|
|
|
|
n2: HostVNode,
|
|
|
|
|
container: HostElement,
|
|
|
|
|
anchor: HostNode | null,
|
|
|
|
|
parentComponent: ComponentInternalInstance | null,
|
|
|
|
|
isSVG: boolean,
|
|
|
|
|
optimized: boolean
|
|
|
|
|
) {
|
|
|
|
|
const fragmentStartAnchor = (n2.el = n1 ? n1.el : hostCreateComment(''))
|
|
|
|
|
const fragmentStartAnchor = (n2.el = n1
|
|
|
|
|
? n1.el
|
|
|
|
|
: hostCreateComment('')) as HostNode
|
|
|
|
|
const fragmentEndAnchor = (n2.anchor = n1
|
|
|
|
|
? n1.anchor
|
|
|
|
|
: hostCreateComment(''))
|
|
|
|
|
: hostCreateComment('')) as HostNode
|
|
|
|
|
if (n1 == null) {
|
|
|
|
|
hostInsert(fragmentStartAnchor, container, anchor)
|
|
|
|
|
hostInsert(fragmentEndAnchor, container, anchor)
|
|
|
|
|
// a fragment can only have array children
|
|
|
|
|
mountChildren(
|
|
|
|
|
n2.children as VNodeChildren,
|
|
|
|
|
n2.children as HostVNodeChildren,
|
|
|
|
|
container,
|
|
|
|
|
fragmentEndAnchor,
|
|
|
|
|
parentComponent,
|
|
|
|
|
@@ -486,10 +514,10 @@ export function createRenderer(options: RendererOptions): RootRenderFunction {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function processPortal(
|
|
|
|
|
n1: VNode | null,
|
|
|
|
|
n2: VNode,
|
|
|
|
|
container: HostNode,
|
|
|
|
|
anchor: HostNode,
|
|
|
|
|
n1: HostVNode | null,
|
|
|
|
|
n2: HostVNode,
|
|
|
|
|
container: HostElement,
|
|
|
|
|
anchor: HostNode | null,
|
|
|
|
|
parentComponent: ComponentInternalInstance | null,
|
|
|
|
|
isSVG: boolean,
|
|
|
|
|
optimized: boolean
|
|
|
|
|
@@ -505,7 +533,7 @@ export function createRenderer(options: RendererOptions): RootRenderFunction {
|
|
|
|
|
hostSetElementText(target, children as string)
|
|
|
|
|
} else if (shapeFlag & ShapeFlags.ARRAY_CHILDREN) {
|
|
|
|
|
mountChildren(
|
|
|
|
|
children as VNodeChildren,
|
|
|
|
|
children as HostVNodeChildren,
|
|
|
|
|
target,
|
|
|
|
|
null,
|
|
|
|
|
parentComponent,
|
|
|
|
|
@@ -517,7 +545,7 @@ export function createRenderer(options: RendererOptions): RootRenderFunction {
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
// update content
|
|
|
|
|
const target = (n2.target = n1.target)
|
|
|
|
|
const target = (n2.target = n1.target) as HostElement
|
|
|
|
|
if (patchFlag === PatchFlags.TEXT) {
|
|
|
|
|
hostSetElementText(target, children as string)
|
|
|
|
|
} else if (!optimized) {
|
|
|
|
|
@@ -534,8 +562,8 @@ export function createRenderer(options: RendererOptions): RootRenderFunction {
|
|
|
|
|
hostSetElementText(target, '')
|
|
|
|
|
hostSetElementText(nextTarget, children as string)
|
|
|
|
|
} else if (shapeFlag & ShapeFlags.ARRAY_CHILDREN) {
|
|
|
|
|
for (let i = 0; i < (children as VNode[]).length; i++) {
|
|
|
|
|
move((children as VNode[])[i], nextTarget, null)
|
|
|
|
|
for (let i = 0; i < (children as HostVNode[]).length; i++) {
|
|
|
|
|
move((children as HostVNode[])[i], nextTarget, null)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} else if (__DEV__) {
|
|
|
|
|
@@ -548,10 +576,10 @@ export function createRenderer(options: RendererOptions): RootRenderFunction {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function processComponent(
|
|
|
|
|
n1: VNode | null,
|
|
|
|
|
n2: VNode,
|
|
|
|
|
container: HostNode,
|
|
|
|
|
anchor: HostNode,
|
|
|
|
|
n1: HostVNode | null,
|
|
|
|
|
n2: HostVNode,
|
|
|
|
|
container: HostElement,
|
|
|
|
|
anchor: HostNode | null,
|
|
|
|
|
parentComponent: ComponentInternalInstance | null,
|
|
|
|
|
isSVG: boolean,
|
|
|
|
|
optimized: boolean
|
|
|
|
|
@@ -580,9 +608,9 @@ export function createRenderer(options: RendererOptions): RootRenderFunction {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function mountComponent(
|
|
|
|
|
initialVNode: VNode,
|
|
|
|
|
container: HostNode,
|
|
|
|
|
anchor: HostNode,
|
|
|
|
|
initialVNode: HostVNode,
|
|
|
|
|
container: HostElement,
|
|
|
|
|
anchor: HostNode | null,
|
|
|
|
|
parentComponent: ComponentInternalInstance | null,
|
|
|
|
|
isSVG: boolean
|
|
|
|
|
) {
|
|
|
|
|
@@ -624,7 +652,7 @@ export function createRenderer(options: RendererOptions): RootRenderFunction {
|
|
|
|
|
} else {
|
|
|
|
|
// updateComponent
|
|
|
|
|
// This is triggered by mutation of component's own state (next: null)
|
|
|
|
|
// OR parent calling processComponent (next: VNode)
|
|
|
|
|
// OR parent calling processComponent (next: HostVNode)
|
|
|
|
|
const { next } = instance
|
|
|
|
|
|
|
|
|
|
if (__DEV__) {
|
|
|
|
|
@@ -654,7 +682,7 @@ export function createRenderer(options: RendererOptions): RootRenderFunction {
|
|
|
|
|
prevTree,
|
|
|
|
|
nextTree,
|
|
|
|
|
// parent may have changed if it's in a portal
|
|
|
|
|
hostParentNode(prevTree.el),
|
|
|
|
|
hostParentNode(prevTree.el as HostNode) as HostElement,
|
|
|
|
|
// anchor may have changed if it's in a fragment
|
|
|
|
|
getNextHostNode(prevTree),
|
|
|
|
|
instance,
|
|
|
|
|
@@ -689,10 +717,10 @@ export function createRenderer(options: RendererOptions): RootRenderFunction {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function patchChildren(
|
|
|
|
|
n1: VNode | null,
|
|
|
|
|
n2: VNode,
|
|
|
|
|
container: HostNode,
|
|
|
|
|
anchor: HostNode,
|
|
|
|
|
n1: HostVNode | null,
|
|
|
|
|
n2: HostVNode,
|
|
|
|
|
container: HostElement,
|
|
|
|
|
anchor: HostNode | null,
|
|
|
|
|
parentComponent: ComponentInternalInstance | null,
|
|
|
|
|
isSVG: boolean,
|
|
|
|
|
optimized: boolean = false
|
|
|
|
|
@@ -708,8 +736,8 @@ export function createRenderer(options: RendererOptions): RootRenderFunction {
|
|
|
|
|
// this could be either fully-keyed or mixed (some keyed some not)
|
|
|
|
|
// presence of patchFlag means children are guaranteed to be arrays
|
|
|
|
|
patchKeyedChildren(
|
|
|
|
|
c1 as VNode[],
|
|
|
|
|
c2 as VNodeChildren,
|
|
|
|
|
c1 as HostVNode[],
|
|
|
|
|
c2 as HostVNodeChildren,
|
|
|
|
|
container,
|
|
|
|
|
anchor,
|
|
|
|
|
parentComponent,
|
|
|
|
|
@@ -720,8 +748,8 @@ export function createRenderer(options: RendererOptions): RootRenderFunction {
|
|
|
|
|
} else if (patchFlag & PatchFlags.UNKEYED) {
|
|
|
|
|
// unkeyed
|
|
|
|
|
patchUnkeyedChildren(
|
|
|
|
|
c1 as VNode[],
|
|
|
|
|
c2 as VNodeChildren,
|
|
|
|
|
c1 as HostVNode[],
|
|
|
|
|
c2 as HostVNodeChildren,
|
|
|
|
|
container,
|
|
|
|
|
anchor,
|
|
|
|
|
parentComponent,
|
|
|
|
|
@@ -735,7 +763,7 @@ export function createRenderer(options: RendererOptions): RootRenderFunction {
|
|
|
|
|
if (shapeFlag & ShapeFlags.TEXT_CHILDREN) {
|
|
|
|
|
// text children fast path
|
|
|
|
|
if (prevShapeFlag & ShapeFlags.ARRAY_CHILDREN) {
|
|
|
|
|
unmountChildren(c1 as VNode[], parentComponent)
|
|
|
|
|
unmountChildren(c1 as HostVNode[], parentComponent)
|
|
|
|
|
}
|
|
|
|
|
if (c2 !== c1) {
|
|
|
|
|
hostSetElementText(container, c2 as string)
|
|
|
|
|
@@ -745,7 +773,7 @@ export function createRenderer(options: RendererOptions): RootRenderFunction {
|
|
|
|
|
hostSetElementText(container, '')
|
|
|
|
|
if (shapeFlag & ShapeFlags.ARRAY_CHILDREN) {
|
|
|
|
|
mountChildren(
|
|
|
|
|
c2 as VNodeChildren,
|
|
|
|
|
c2 as HostVNodeChildren,
|
|
|
|
|
container,
|
|
|
|
|
anchor,
|
|
|
|
|
parentComponent,
|
|
|
|
|
@@ -756,8 +784,8 @@ export function createRenderer(options: RendererOptions): RootRenderFunction {
|
|
|
|
|
if (shapeFlag & ShapeFlags.ARRAY_CHILDREN) {
|
|
|
|
|
// two arrays, cannot assume anything, do full diff
|
|
|
|
|
patchKeyedChildren(
|
|
|
|
|
c1 as VNode[],
|
|
|
|
|
c2 as VNodeChildren,
|
|
|
|
|
c1 as HostVNode[],
|
|
|
|
|
c2 as HostVNodeChildren,
|
|
|
|
|
container,
|
|
|
|
|
anchor,
|
|
|
|
|
parentComponent,
|
|
|
|
|
@@ -766,17 +794,17 @@ export function createRenderer(options: RendererOptions): RootRenderFunction {
|
|
|
|
|
)
|
|
|
|
|
} else {
|
|
|
|
|
// c2 is null in this case
|
|
|
|
|
unmountChildren(c1 as VNode[], parentComponent, true)
|
|
|
|
|
unmountChildren(c1 as HostVNode[], parentComponent, true)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function patchUnkeyedChildren(
|
|
|
|
|
c1: VNode[],
|
|
|
|
|
c2: VNodeChildren,
|
|
|
|
|
container: HostNode,
|
|
|
|
|
anchor: HostNode,
|
|
|
|
|
c1: HostVNode[],
|
|
|
|
|
c2: HostVNodeChildren,
|
|
|
|
|
container: HostElement,
|
|
|
|
|
anchor: HostNode | null,
|
|
|
|
|
parentComponent: ComponentInternalInstance | null,
|
|
|
|
|
isSVG: boolean,
|
|
|
|
|
optimized: boolean
|
|
|
|
|
@@ -810,10 +838,10 @@ export function createRenderer(options: RendererOptions): RootRenderFunction {
|
|
|
|
|
|
|
|
|
|
// can be all-keyed or mixed
|
|
|
|
|
function patchKeyedChildren(
|
|
|
|
|
c1: VNode[],
|
|
|
|
|
c2: VNodeChildren,
|
|
|
|
|
container: HostNode,
|
|
|
|
|
parentAnchor: HostNode,
|
|
|
|
|
c1: HostVNode[],
|
|
|
|
|
c2: HostVNodeChildren,
|
|
|
|
|
container: HostElement,
|
|
|
|
|
parentAnchor: HostNode | null,
|
|
|
|
|
parentComponent: ComponentInternalInstance | null,
|
|
|
|
|
isSVG: boolean,
|
|
|
|
|
optimized: boolean
|
|
|
|
|
@@ -878,7 +906,8 @@ export function createRenderer(options: RendererOptions): RootRenderFunction {
|
|
|
|
|
if (i > e1) {
|
|
|
|
|
if (i <= e2) {
|
|
|
|
|
const nextPos = e2 + 1
|
|
|
|
|
const anchor = nextPos < l2 ? (c2[nextPos] as VNode).el : parentAnchor
|
|
|
|
|
const anchor =
|
|
|
|
|
nextPos < l2 ? (c2[nextPos] as HostVNode).el : parentAnchor
|
|
|
|
|
while (i <= e2) {
|
|
|
|
|
patch(
|
|
|
|
|
null,
|
|
|
|
|
@@ -960,7 +989,7 @@ export function createRenderer(options: RendererOptions): RootRenderFunction {
|
|
|
|
|
} else {
|
|
|
|
|
// key-less node, try to locate a key-less node of the same type
|
|
|
|
|
for (j = s2; j <= e2; j++) {
|
|
|
|
|
if (isSameType(prevChild, c2[j] as VNode)) {
|
|
|
|
|
if (isSameType(prevChild, c2[j] as HostVNode)) {
|
|
|
|
|
newIndex = j
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
@@ -977,7 +1006,7 @@ export function createRenderer(options: RendererOptions): RootRenderFunction {
|
|
|
|
|
}
|
|
|
|
|
patch(
|
|
|
|
|
prevChild,
|
|
|
|
|
c2[newIndex] as VNode,
|
|
|
|
|
c2[newIndex] as HostVNode,
|
|
|
|
|
container,
|
|
|
|
|
null,
|
|
|
|
|
parentComponent,
|
|
|
|
|
@@ -997,9 +1026,11 @@ export function createRenderer(options: RendererOptions): RootRenderFunction {
|
|
|
|
|
// looping backwards so that we can use last patched node as anchor
|
|
|
|
|
for (i = toBePatched - 1; i >= 0; i--) {
|
|
|
|
|
const nextIndex = s2 + i
|
|
|
|
|
const nextChild = c2[nextIndex] as VNode
|
|
|
|
|
const nextChild = c2[nextIndex] as HostVNode
|
|
|
|
|
const anchor =
|
|
|
|
|
nextIndex + 1 < l2 ? (c2[nextIndex + 1] as VNode).el : parentAnchor
|
|
|
|
|
nextIndex + 1 < l2
|
|
|
|
|
? (c2[nextIndex + 1] as HostVNode).el
|
|
|
|
|
: parentAnchor
|
|
|
|
|
if (newIndexToOldIndexMap[i] === 0) {
|
|
|
|
|
// mount new
|
|
|
|
|
patch(null, nextChild, container, anchor, parentComponent, isSVG)
|
|
|
|
|
@@ -1017,25 +1048,29 @@ export function createRenderer(options: RendererOptions): RootRenderFunction {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function move(vnode: VNode, container: HostNode, anchor: HostNode) {
|
|
|
|
|
function move(
|
|
|
|
|
vnode: HostVNode,
|
|
|
|
|
container: HostElement,
|
|
|
|
|
anchor: HostNode | null
|
|
|
|
|
) {
|
|
|
|
|
if (vnode.component !== null) {
|
|
|
|
|
move(vnode.component.subTree, container, anchor)
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
if (vnode.type === Fragment) {
|
|
|
|
|
hostInsert(vnode.el, container, anchor)
|
|
|
|
|
const children = vnode.children as VNode[]
|
|
|
|
|
hostInsert(vnode.el as HostNode, container, anchor)
|
|
|
|
|
const children = vnode.children as HostVNode[]
|
|
|
|
|
for (let i = 0; i < children.length; i++) {
|
|
|
|
|
hostInsert(children[i].el, container, anchor)
|
|
|
|
|
hostInsert(children[i].el as HostNode, container, anchor)
|
|
|
|
|
}
|
|
|
|
|
hostInsert(vnode.anchor, container, anchor)
|
|
|
|
|
hostInsert(vnode.anchor as HostNode, container, anchor)
|
|
|
|
|
} else {
|
|
|
|
|
hostInsert(vnode.el, container, anchor)
|
|
|
|
|
hostInsert(vnode.el as HostNode, container, anchor)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function unmount(
|
|
|
|
|
vnode: VNode,
|
|
|
|
|
vnode: HostVNode,
|
|
|
|
|
parentComponent: ComponentInternalInstance | null,
|
|
|
|
|
doRemove?: boolean
|
|
|
|
|
) {
|
|
|
|
|
@@ -1069,14 +1104,14 @@ export function createRenderer(options: RendererOptions): RootRenderFunction {
|
|
|
|
|
unmountChildren(dynamicChildren, parentComponent, shouldRemoveChildren)
|
|
|
|
|
} else if (shapeFlag & ShapeFlags.ARRAY_CHILDREN) {
|
|
|
|
|
unmountChildren(
|
|
|
|
|
children as VNode[],
|
|
|
|
|
children as HostVNode[],
|
|
|
|
|
parentComponent,
|
|
|
|
|
shouldRemoveChildren
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (doRemove) {
|
|
|
|
|
hostRemove(vnode.el)
|
|
|
|
|
hostRemove(vnode.el as HostNode)
|
|
|
|
|
if (anchor != null) hostRemove(anchor)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@@ -1110,7 +1145,7 @@ export function createRenderer(options: RendererOptions): RootRenderFunction {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function unmountChildren(
|
|
|
|
|
children: VNode[],
|
|
|
|
|
children: HostVNode[],
|
|
|
|
|
parentComponent: ComponentInternalInstance | null,
|
|
|
|
|
doRemove?: boolean,
|
|
|
|
|
start: number = 0
|
|
|
|
|
@@ -1120,9 +1155,9 @@ export function createRenderer(options: RendererOptions): RootRenderFunction {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function getNextHostNode(vnode: VNode): HostNode {
|
|
|
|
|
function getNextHostNode(vnode: HostVNode): HostNode | null {
|
|
|
|
|
return vnode.component === null
|
|
|
|
|
? hostNextSibling(vnode.anchor || vnode.el)
|
|
|
|
|
? hostNextSibling((vnode.anchor || vnode.el) as HostNode)
|
|
|
|
|
: getNextHostNode(vnode.component.subTree)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@@ -1130,7 +1165,7 @@ export function createRenderer(options: RendererOptions): RootRenderFunction {
|
|
|
|
|
ref: string | Function | Ref<any>,
|
|
|
|
|
oldRef: string | Function | Ref<any> | null,
|
|
|
|
|
parent: ComponentInternalInstance,
|
|
|
|
|
value: HostNode | ComponentInternalInstance | null
|
|
|
|
|
value: HostNode | ComponentPublicInstance | null
|
|
|
|
|
) {
|
|
|
|
|
const refs = parent.refs === EMPTY_OBJ ? (parent.refs = {}) : parent.refs
|
|
|
|
|
const renderContext = toRaw(parent.renderContext)
|
|
|
|
|
@@ -1163,39 +1198,33 @@ export function createRenderer(options: RendererOptions): RootRenderFunction {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return function render(vnode: VNode | null, dom: HostNode | string) {
|
|
|
|
|
if (isString(dom)) {
|
|
|
|
|
if (isFunction(hostQuerySelector)) {
|
|
|
|
|
dom = hostQuerySelector(dom)
|
|
|
|
|
if (!dom) {
|
|
|
|
|
if (__DEV__) {
|
|
|
|
|
warn(
|
|
|
|
|
`Failed to locate root container: ` +
|
|
|
|
|
`querySelector returned null.`
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
function render(vnode: HostVNode | null, rawContainer: HostElement | string) {
|
|
|
|
|
let container: any = rawContainer
|
|
|
|
|
if (isString(container)) {
|
|
|
|
|
container = hostQuerySelector(container)
|
|
|
|
|
if (!container) {
|
|
|
|
|
if (__DEV__) {
|
|
|
|
|
warn(
|
|
|
|
|
`Failed to locate root container: ` +
|
|
|
|
|
`target platform does not support querySelector.`
|
|
|
|
|
`Failed to locate root container: ` + `querySelector returned null.`
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (vnode == null) {
|
|
|
|
|
debugger
|
|
|
|
|
if (dom._vnode) {
|
|
|
|
|
unmount(dom._vnode, null, true)
|
|
|
|
|
if (container._vnode) {
|
|
|
|
|
unmount(container._vnode, null, true)
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
patch(dom._vnode, vnode, dom)
|
|
|
|
|
patch(container._vnode || null, vnode, container)
|
|
|
|
|
}
|
|
|
|
|
flushPostFlushCbs()
|
|
|
|
|
dom._vnode = vnode
|
|
|
|
|
container._vnode = vnode
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return {
|
|
|
|
|
render,
|
|
|
|
|
createApp: createAppAPI(render)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|