wip: diffKeyedChildren
This commit is contained in:
parent
444d6f4bda
commit
e4ce78c8c9
@ -70,7 +70,7 @@ export function createRenderer(options: RendererOptions) {
|
||||
) {
|
||||
// patching & not same type, unmount old tree
|
||||
if (n1 != null && !isSameType(n1, n2)) {
|
||||
anchor = hostNextSibling(n1.el)
|
||||
anchor = hostNextSibling(n1.anchor || n1.el)
|
||||
unmount(n1, true)
|
||||
n1 = null
|
||||
}
|
||||
@ -304,13 +304,17 @@ export function createRenderer(options: RendererOptions) {
|
||||
anchor?: HostNode,
|
||||
optimized?: boolean
|
||||
) {
|
||||
const fragmentAnchor = (n2.el = n1 ? n1.el : document.createComment(''))
|
||||
const fragmentStartAnchor = (n2.el = n1 ? n1.el : hostCreateComment(''))
|
||||
const fragmentEndAnchor = (n2.anchor = n1
|
||||
? n1.anchor
|
||||
: hostCreateComment(''))
|
||||
if (n1 == null) {
|
||||
insert(fragmentAnchor, container, anchor)
|
||||
insert(fragmentStartAnchor, container, anchor)
|
||||
insert(fragmentEndAnchor, container, anchor)
|
||||
// a fragment can only have array children
|
||||
mountChildren(n2.children as VNodeChildren, container, fragmentAnchor)
|
||||
mountChildren(n2.children as VNodeChildren, container, fragmentEndAnchor)
|
||||
} else {
|
||||
patchChildren(n1, n2, container, fragmentAnchor, optimized)
|
||||
patchChildren(n1, n2, container, fragmentEndAnchor, optimized)
|
||||
}
|
||||
}
|
||||
|
||||
@ -369,7 +373,7 @@ export function createRenderer(options: RendererOptions) {
|
||||
patchKeyedChildren(c1 as VNode[], c2, container, anchor, optimized)
|
||||
} else {
|
||||
// c2 is null in this case
|
||||
unmountChildren(c1 as VNode[], 0, true)
|
||||
unmountChildren(c1 as VNode[], true)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -394,7 +398,7 @@ export function createRenderer(options: RendererOptions) {
|
||||
}
|
||||
if (oldLength > newLength) {
|
||||
// remove old
|
||||
unmountChildren(c1, commonLength, true)
|
||||
unmountChildren(c1, true, commonLength)
|
||||
} else {
|
||||
// mount new
|
||||
mountChildren(c2, container, anchor, commonLength)
|
||||
@ -409,29 +413,98 @@ export function createRenderer(options: RendererOptions) {
|
||||
anchor?: HostNode,
|
||||
optimized?: boolean
|
||||
) {
|
||||
// TODO
|
||||
patchUnkeyedChildren(c1, c2, container, anchor, optimized)
|
||||
let i = 0
|
||||
let e1 = c1.length - 1
|
||||
let e2 = c2.length - 1
|
||||
|
||||
// 1. sync from start
|
||||
// (a b) c
|
||||
// (a b) d e
|
||||
while (i <= e1 && i <= e2) {
|
||||
const n1 = c1[i]
|
||||
const n2 = (c2[i] = normalizeChild(c2[i]))
|
||||
if (isSameType(n1, n2)) {
|
||||
patch(n1, n2, container, anchor, optimized)
|
||||
} else {
|
||||
break
|
||||
}
|
||||
i++
|
||||
}
|
||||
|
||||
// 2. sync from end
|
||||
// a (b c)
|
||||
// d e (b c)
|
||||
while (i <= e1 && i <= e2) {
|
||||
const n1 = c1[e1]
|
||||
const n2 = (c2[e2] = normalizeChild(c2[e2]))
|
||||
if (isSameType(n1, n2)) {
|
||||
patch(n1, n2, container, anchor, optimized)
|
||||
} else {
|
||||
break
|
||||
}
|
||||
e1--
|
||||
e2--
|
||||
}
|
||||
|
||||
// 3. common sequence + mount
|
||||
// (a b)
|
||||
// (a b) c
|
||||
// i = 2, e1 = 1, e2 = 2
|
||||
// (a b)
|
||||
// c (a b)
|
||||
// i = 0, e1 = -1, e2 = 0
|
||||
if (i > e1) {
|
||||
if (i <= e2) {
|
||||
const nextPos = e2 + 1
|
||||
const nextAnchor =
|
||||
nextPos < c2.length ? (c2[nextPos] as VNode).el : anchor
|
||||
while (i <= e2) {
|
||||
patch(null, (c2[i] = normalizeChild(c2[i])), container, nextAnchor)
|
||||
i++
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 4. common sequence + unmount
|
||||
// (a b) c
|
||||
// (a b)
|
||||
// i = 2, e1 = 2, e2 = 1
|
||||
// a (b c)
|
||||
// (b c)
|
||||
// i = 0, e1 = 0, e2 = -1
|
||||
else if (i > e2) {
|
||||
while (i <= e1) {
|
||||
unmount(c1[i], true)
|
||||
i++
|
||||
}
|
||||
}
|
||||
|
||||
// 5. inner diff
|
||||
// - build key:index map
|
||||
// - loop through old and try to patch / remove
|
||||
// - if moved: apply minimal move w/ levenshtein distance
|
||||
// - no move: mount and insert new ones
|
||||
else {
|
||||
}
|
||||
}
|
||||
|
||||
function unmount(vnode: VNode, doRemove?: boolean) {
|
||||
const shouldRemoveChildren = vnode.type === Fragment && doRemove
|
||||
if (vnode.dynamicChildren != null) {
|
||||
unmountChildren(vnode.dynamicChildren)
|
||||
unmountChildren(vnode.dynamicChildren, shouldRemoveChildren)
|
||||
} else if (Array.isArray(vnode.children)) {
|
||||
unmountChildren(vnode.children as VNode[])
|
||||
unmountChildren(vnode.children as VNode[], shouldRemoveChildren)
|
||||
}
|
||||
if (doRemove) {
|
||||
if (vnode.type === Fragment) {
|
||||
// raw VNodeChildren is normalized to VNode[] when the VNode is patched
|
||||
unmountChildren(vnode.children as VNode[], 0, doRemove)
|
||||
}
|
||||
remove(vnode.el)
|
||||
if (vnode.anchor != null) remove(vnode.anchor)
|
||||
}
|
||||
}
|
||||
|
||||
function unmountChildren(
|
||||
children: VNode[],
|
||||
start: number = 0,
|
||||
doRemove?: boolean
|
||||
doRemove?: boolean,
|
||||
start: number = 0
|
||||
) {
|
||||
for (let i = start; i < children.length; i++) {
|
||||
unmount(children[i], doRemove)
|
||||
|
@ -14,6 +14,7 @@ export interface VNodeChildren extends Array<VNodeChildren | VNodeChild> {}
|
||||
|
||||
export interface VNode {
|
||||
el: any
|
||||
anchor: any // fragment anchor
|
||||
type: VNodeTypes
|
||||
props: { [key: string]: any } | null
|
||||
key: string | number | null
|
||||
@ -23,11 +24,11 @@ export interface VNode {
|
||||
dynamicChildren: VNode[] | null
|
||||
}
|
||||
|
||||
const blockStack: (VNode[])[] = []
|
||||
const blockStack: (VNode[] | null)[] = []
|
||||
|
||||
// open block
|
||||
export function openBlock() {
|
||||
blockStack.push([])
|
||||
export function openBlock(disableTrackng?: boolean) {
|
||||
blockStack.push(disableTrackng ? null : [])
|
||||
}
|
||||
|
||||
let shouldTrack = true
|
||||
@ -44,7 +45,9 @@ export function createBlock(
|
||||
shouldTrack = false
|
||||
const vnode = createVNode(type, props, children, patchFlag, dynamicProps)
|
||||
shouldTrack = true
|
||||
vnode.dynamicChildren = blockStack.pop() || null
|
||||
const trackedNodes = blockStack.pop()
|
||||
vnode.dynamicChildren =
|
||||
trackedNodes && trackedNodes.length ? trackedNodes : null
|
||||
// a block is always going to be patched
|
||||
trackDynamicNode(vnode)
|
||||
return vnode
|
||||
@ -59,11 +62,12 @@ export function createVNode(
|
||||
dynamicProps: string[] | null = null
|
||||
): VNode {
|
||||
const vnode: VNode = {
|
||||
el: null,
|
||||
type,
|
||||
props,
|
||||
key: props && props.key,
|
||||
children,
|
||||
el: null,
|
||||
anchor: null,
|
||||
patchFlag,
|
||||
dynamicProps,
|
||||
dynamicChildren: null
|
||||
@ -76,7 +80,7 @@ export function createVNode(
|
||||
|
||||
function trackDynamicNode(vnode: VNode) {
|
||||
const currentBlockDynamicNodes = blockStack[blockStack.length - 1]
|
||||
if (currentBlockDynamicNodes) {
|
||||
if (currentBlockDynamicNodes != null) {
|
||||
currentBlockDynamicNodes.push(vnode)
|
||||
}
|
||||
}
|
||||
|
@ -15,6 +15,7 @@ export const DOMRendererOptions: RendererOptions = {
|
||||
},
|
||||
|
||||
remove: (child: Node) => {
|
||||
if (!child) debugger
|
||||
const parent = child.parentNode
|
||||
if (parent != null) {
|
||||
parent.removeChild(child)
|
||||
|
Loading…
Reference in New Issue
Block a user