context: CodegenContext,
): CodeFragment[] {
const { helper } = context
- const { source, value, key, index, render, keyProp, once, id, component } =
- oper
+ const {
+ source,
+ value,
+ key,
+ index,
+ render,
+ keyProp,
+ once,
+ id,
+ component,
+ onlyChild,
+ } = oper
let rawValue: string | null = null
const rawKey = key && key.content
genCallback(keyProp),
component && 'true',
once && 'true',
+ onlyChild && `true`,
// todo: hydrationNode
),
]
return (): void => {
exitBlock()
+
+ const { parent } = context
+
+ // if v-for is the only child of a parent element, it can go the fast path
+ // when the entire list is emptied
+ const isOnlyChild =
+ parent &&
+ parent.block.node !== parent.node &&
+ parent.node.children.length === 1
+
context.registerOperation({
type: IRNodeTypes.FOR,
id,
render,
once: context.inVOnce,
component: isComponent,
+ onlyChild: !!isOnlyChild,
})
}
}
*/
isComponent = false,
once?: boolean,
+ canUseFastRemove?: boolean,
// hydrationNode?: Node,
): VaporFragment => {
let isMounted = false
mount(source, i)
}
} else if (!newLength) {
- // fast path for clearing
+ // fast path for clearing all
+ const doRemove = !canUseFastRemove
for (let i = 0; i < oldLength; i++) {
- unmount(oldBlocks[i])
+ unmount(oldBlocks[i], doRemove)
+ }
+ if (canUseFastRemove) {
+ parent!.textContent = ''
+ parent!.appendChild(parentAnchor)
}
} else if (!getKey) {
// unkeyed fast path
}
}
- const unmount = ({ nodes, scope }: ForBlock) => {
+ const unmount = ({ nodes, scope }: ForBlock, doRemove = true) => {
scope && scope.stop()
- removeBlock(nodes, parent!)
+ doRemove && removeBlock(nodes, parent!)
}
once ? renderList() : renderEffect(renderList)