insert,
prepend,
renderEffect,
+ setInsertionState,
template,
} from '../src'
import { currentInstance, nextTick, ref } from '@vue/runtime-dom'
await nextTick()
expect(host.innerHTML).toBe('<div><h1></h1><!--slot--></div>')
})
+
+ test('consecutive slots with insertion state', async () => {
+ const { component: Child } = define({
+ setup() {
+ const n2 = template('<div><div>baz</div></div>', true)() as any
+ setInsertionState(n2, 0)
+ createSlot('default', null)
+ setInsertionState(n2, 0)
+ createSlot('foo', null)
+ return n2
+ },
+ })
+
+ const { html } = define({
+ setup() {
+ return createComponent(Child, null, {
+ default: () => template('default')(),
+ foo: () => template('foo')(),
+ })
+ },
+ }).render()
+
+ expect(html()).toBe(
+ `<div>` +
+ `default<!--slot-->` +
+ `foo<!--slot-->` +
+ `<div>baz</div>` +
+ `</div>`,
+ )
+ })
})
})
export function insert(
block: Block,
- parent: ParentNode,
+ parent: ParentNode & { $anchor?: Node | null },
anchor: Node | null | 0 = null, // 0 means prepend
): void {
- anchor = anchor === 0 ? parent.firstChild : anchor
+ anchor = anchor === 0 ? parent.$anchor || parent.firstChild : anchor
if (block instanceof Node) {
if (!isHydrating) {
parent.insertBefore(block, anchor)
if (isOptimized) return
isOptimized = true
const proto = Element.prototype as any
- proto.$evtclick = undefined
+ proto.$anchor = proto.$evtclick = undefined
proto.$root = false
proto.$html =
proto.$txt =
* (component, slot outlet, if, for) is created. The state is used for actual
* insertion on client-side render, and used for node adoption during hydration.
*/
-export function setInsertionState(parent: ParentNode, anchor?: Node | 0): void {
+export function setInsertionState(
+ parent: ParentNode & { $anchor?: Node | null },
+ anchor?: Node | 0,
+): void {
+ // When setInsertionState(n3, 0) is called consecutively, the first prepend operation
+ // uses parent.firstChild as the anchor. However, after insertion, parent.firstChild
+ // changes and cannot serve as the anchor for subsequent prepends. Therefore, we cache
+ // the original parent.firstChild on the first call for subsequent prepend operations.
+ if (anchor === 0 && !parent.$anchor) {
+ parent.$anchor = parent.firstChild
+ }
+
insertionParent = parent
insertionAnchor = anchor
}