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
|
// patching & not same type, unmount old tree
|
||||||
if (n1 != null && !isSameType(n1, n2)) {
|
if (n1 != null && !isSameType(n1, n2)) {
|
||||||
anchor = hostNextSibling(n1.el)
|
anchor = hostNextSibling(n1.anchor || n1.el)
|
||||||
unmount(n1, true)
|
unmount(n1, true)
|
||||||
n1 = null
|
n1 = null
|
||||||
}
|
}
|
||||||
@ -304,13 +304,17 @@ export function createRenderer(options: RendererOptions) {
|
|||||||
anchor?: HostNode,
|
anchor?: HostNode,
|
||||||
optimized?: boolean
|
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) {
|
if (n1 == null) {
|
||||||
insert(fragmentAnchor, container, anchor)
|
insert(fragmentStartAnchor, container, anchor)
|
||||||
|
insert(fragmentEndAnchor, container, anchor)
|
||||||
// a fragment can only have array children
|
// a fragment can only have array children
|
||||||
mountChildren(n2.children as VNodeChildren, container, fragmentAnchor)
|
mountChildren(n2.children as VNodeChildren, container, fragmentEndAnchor)
|
||||||
} else {
|
} 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)
|
patchKeyedChildren(c1 as VNode[], c2, container, anchor, optimized)
|
||||||
} else {
|
} else {
|
||||||
// c2 is null in this case
|
// 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) {
|
if (oldLength > newLength) {
|
||||||
// remove old
|
// remove old
|
||||||
unmountChildren(c1, commonLength, true)
|
unmountChildren(c1, true, commonLength)
|
||||||
} else {
|
} else {
|
||||||
// mount new
|
// mount new
|
||||||
mountChildren(c2, container, anchor, commonLength)
|
mountChildren(c2, container, anchor, commonLength)
|
||||||
@ -409,29 +413,98 @@ export function createRenderer(options: RendererOptions) {
|
|||||||
anchor?: HostNode,
|
anchor?: HostNode,
|
||||||
optimized?: boolean
|
optimized?: boolean
|
||||||
) {
|
) {
|
||||||
// TODO
|
let i = 0
|
||||||
patchUnkeyedChildren(c1, c2, container, anchor, optimized)
|
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) {
|
function unmount(vnode: VNode, doRemove?: boolean) {
|
||||||
|
const shouldRemoveChildren = vnode.type === Fragment && doRemove
|
||||||
if (vnode.dynamicChildren != null) {
|
if (vnode.dynamicChildren != null) {
|
||||||
unmountChildren(vnode.dynamicChildren)
|
unmountChildren(vnode.dynamicChildren, shouldRemoveChildren)
|
||||||
} else if (Array.isArray(vnode.children)) {
|
} else if (Array.isArray(vnode.children)) {
|
||||||
unmountChildren(vnode.children as VNode[])
|
unmountChildren(vnode.children as VNode[], shouldRemoveChildren)
|
||||||
}
|
}
|
||||||
if (doRemove) {
|
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)
|
remove(vnode.el)
|
||||||
|
if (vnode.anchor != null) remove(vnode.anchor)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function unmountChildren(
|
function unmountChildren(
|
||||||
children: VNode[],
|
children: VNode[],
|
||||||
start: number = 0,
|
doRemove?: boolean,
|
||||||
doRemove?: boolean
|
start: number = 0
|
||||||
) {
|
) {
|
||||||
for (let i = start; i < children.length; i++) {
|
for (let i = start; i < children.length; i++) {
|
||||||
unmount(children[i], doRemove)
|
unmount(children[i], doRemove)
|
||||||
|
@ -14,6 +14,7 @@ export interface VNodeChildren extends Array<VNodeChildren | VNodeChild> {}
|
|||||||
|
|
||||||
export interface VNode {
|
export interface VNode {
|
||||||
el: any
|
el: any
|
||||||
|
anchor: any // fragment anchor
|
||||||
type: VNodeTypes
|
type: VNodeTypes
|
||||||
props: { [key: string]: any } | null
|
props: { [key: string]: any } | null
|
||||||
key: string | number | null
|
key: string | number | null
|
||||||
@ -23,11 +24,11 @@ export interface VNode {
|
|||||||
dynamicChildren: VNode[] | null
|
dynamicChildren: VNode[] | null
|
||||||
}
|
}
|
||||||
|
|
||||||
const blockStack: (VNode[])[] = []
|
const blockStack: (VNode[] | null)[] = []
|
||||||
|
|
||||||
// open block
|
// open block
|
||||||
export function openBlock() {
|
export function openBlock(disableTrackng?: boolean) {
|
||||||
blockStack.push([])
|
blockStack.push(disableTrackng ? null : [])
|
||||||
}
|
}
|
||||||
|
|
||||||
let shouldTrack = true
|
let shouldTrack = true
|
||||||
@ -44,7 +45,9 @@ export function createBlock(
|
|||||||
shouldTrack = false
|
shouldTrack = false
|
||||||
const vnode = createVNode(type, props, children, patchFlag, dynamicProps)
|
const vnode = createVNode(type, props, children, patchFlag, dynamicProps)
|
||||||
shouldTrack = true
|
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
|
// a block is always going to be patched
|
||||||
trackDynamicNode(vnode)
|
trackDynamicNode(vnode)
|
||||||
return vnode
|
return vnode
|
||||||
@ -59,11 +62,12 @@ export function createVNode(
|
|||||||
dynamicProps: string[] | null = null
|
dynamicProps: string[] | null = null
|
||||||
): VNode {
|
): VNode {
|
||||||
const vnode: VNode = {
|
const vnode: VNode = {
|
||||||
el: null,
|
|
||||||
type,
|
type,
|
||||||
props,
|
props,
|
||||||
key: props && props.key,
|
key: props && props.key,
|
||||||
children,
|
children,
|
||||||
|
el: null,
|
||||||
|
anchor: null,
|
||||||
patchFlag,
|
patchFlag,
|
||||||
dynamicProps,
|
dynamicProps,
|
||||||
dynamicChildren: null
|
dynamicChildren: null
|
||||||
@ -76,7 +80,7 @@ export function createVNode(
|
|||||||
|
|
||||||
function trackDynamicNode(vnode: VNode) {
|
function trackDynamicNode(vnode: VNode) {
|
||||||
const currentBlockDynamicNodes = blockStack[blockStack.length - 1]
|
const currentBlockDynamicNodes = blockStack[blockStack.length - 1]
|
||||||
if (currentBlockDynamicNodes) {
|
if (currentBlockDynamicNodes != null) {
|
||||||
currentBlockDynamicNodes.push(vnode)
|
currentBlockDynamicNodes.push(vnode)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -15,6 +15,7 @@ export const DOMRendererOptions: RendererOptions = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
remove: (child: Node) => {
|
remove: (child: Node) => {
|
||||||
|
if (!child) debugger
|
||||||
const parent = child.parentNode
|
const parent = child.parentNode
|
||||||
if (parent != null) {
|
if (parent != null) {
|
||||||
parent.removeChild(child)
|
parent.removeChild(child)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user