mirror of https://github.com/vuejs/core.git
feat: append & prepend multiple elements
This commit is contained in:
parent
6ff8b1bf0d
commit
71cf732d6d
|
@ -110,7 +110,7 @@ export function render() {
|
|||
`;
|
||||
|
||||
exports[`comile > directives > v-once > basic 1`] = `
|
||||
"import { template, children, createTextNode, setText, setAttr, insert } from 'vue/vapor';
|
||||
"import { template, children, createTextNode, setText, setAttr, prepend } from 'vue/vapor';
|
||||
const t0 = template('<div> <span></span></div>');
|
||||
export function render() {
|
||||
const n0 = t0();
|
||||
|
@ -118,14 +118,14 @@ export function render() {
|
|||
0: [
|
||||
n3,
|
||||
{
|
||||
2: [n2],
|
||||
1: [n2],
|
||||
},
|
||||
],
|
||||
} = children(n0);
|
||||
const n1 = createTextNode(msg.value);
|
||||
setText(n1, undefined, msg.value);
|
||||
setAttr(n2, 'class', undefined, clz.value);
|
||||
insert(n1, n3, 0 /* InsertPosition.FIRST */);
|
||||
prepend(n3, n1);
|
||||
return n0;
|
||||
}
|
||||
"
|
||||
|
@ -197,19 +197,49 @@ export function render() {
|
|||
|
||||
exports[`comile > static + dynamic root 1`] = `
|
||||
"import { watchEffect } from 'vue';
|
||||
import { template, createTextNode, insert, setText } from 'vue/vapor';
|
||||
const t0 = template('2');
|
||||
import { template, children, createTextNode, prepend, insert, append, setText } from 'vue/vapor';
|
||||
const t0 = template('3<!>6<!>9');
|
||||
export function render() {
|
||||
const n0 = t0();
|
||||
const {
|
||||
1: [n9],
|
||||
3: [n10],
|
||||
} = children(n0);
|
||||
const n1 = createTextNode(1);
|
||||
const n2 = createTextNode(3);
|
||||
insert(n1, n0, 0 /* InsertPosition.FIRST */);
|
||||
insert(n2, n0);
|
||||
const n2 = createTextNode(2);
|
||||
const n3 = createTextNode(4);
|
||||
const n4 = createTextNode(5);
|
||||
const n5 = createTextNode(7);
|
||||
const n6 = createTextNode(8);
|
||||
const n7 = createTextNode('A');
|
||||
const n8 = createTextNode('B');
|
||||
prepend(n0, n1, n2);
|
||||
insert([n3, n4], n0, n9);
|
||||
insert([n5, n6], n0, n10);
|
||||
append(n0, n7, n8);
|
||||
watchEffect(() => {
|
||||
setText(n1, undefined, 1);
|
||||
});
|
||||
watchEffect(() => {
|
||||
setText(n2, undefined, 3);
|
||||
setText(n2, undefined, 2);
|
||||
});
|
||||
watchEffect(() => {
|
||||
setText(n3, undefined, 4);
|
||||
});
|
||||
watchEffect(() => {
|
||||
setText(n4, undefined, 5);
|
||||
});
|
||||
watchEffect(() => {
|
||||
setText(n5, undefined, 7);
|
||||
});
|
||||
watchEffect(() => {
|
||||
setText(n6, undefined, 8);
|
||||
});
|
||||
watchEffect(() => {
|
||||
setText(n7, undefined, 'A');
|
||||
});
|
||||
watchEffect(() => {
|
||||
setText(n8, undefined, 'B');
|
||||
});
|
||||
return n0;
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
exports[`fixtures 1`] = `
|
||||
"import { defineComponent as _defineComponent } from 'vue'
|
||||
import { watchEffect } from 'vue'
|
||||
import { template, children, createTextNode, insert, setText, on, setHtml } from 'vue/vapor'
|
||||
import { template, children, createTextNode, append, setText, on, setHtml } from 'vue/vapor'
|
||||
const t0 = template(\\"<h1 id=\\\\\\"title\\\\\\">Counter</h1><p>Count: </p><p>Double: </p><button>Increment</button><div></div><input type=\\\\\\"text\\\\\\"><p>once: </p><p>{{ count }}</p>\\")
|
||||
import { ref, computed } from 'vue'
|
||||
|
||||
|
@ -22,12 +22,12 @@ return (() => {
|
|||
const n0 = t0()
|
||||
const { 1: [n2], 2: [n4], 3: [n5], 4: [n6], 6: [n8],} = children(n0)
|
||||
const n1 = createTextNode(count.value)
|
||||
insert(n1, n2)
|
||||
append(n2, n1)
|
||||
const n3 = createTextNode(double.value)
|
||||
insert(n3, n4)
|
||||
append(n4, n3)
|
||||
const n7 = createTextNode(count.value)
|
||||
setText(n7, undefined, count.value)
|
||||
insert(n7, n8)
|
||||
append(n8, n7)
|
||||
watchEffect(() => {
|
||||
setText(n1, undefined, count.value)
|
||||
})
|
||||
|
|
|
@ -34,7 +34,9 @@ describe('comile', () => {
|
|||
})
|
||||
|
||||
test('static + dynamic root', async () => {
|
||||
const code = await compile(`{{ 1 }}2{{ 3 }}`)
|
||||
const code = await compile(
|
||||
`{{ 1 }}{{ 2 }}3{{ 4 }}{{ 5 }}6{{ 7 }}{{ 8 }}9{{ 'A' }}{{ 'B' }}`,
|
||||
)
|
||||
expect(code).matchSnapshot()
|
||||
})
|
||||
|
||||
|
|
|
@ -119,16 +119,20 @@ export function generate(
|
|||
}
|
||||
|
||||
case IRNodeTypes.INSERT_NODE: {
|
||||
let anchor = ''
|
||||
if (typeof oper.anchor === 'number') {
|
||||
anchor = `, n${oper.anchor}`
|
||||
} else if (oper.anchor === 'first') {
|
||||
anchor = `, 0 /* InsertPosition.FIRST */`
|
||||
}
|
||||
code = `insert(n${oper.element}, n${oper.parent}${anchor})\n`
|
||||
const elements = ([] as number[]).concat(oper.element)
|
||||
let element = elements.map((el) => `n${el}`).join(', ')
|
||||
if (elements.length > 1) element = `[${element}]`
|
||||
code = `insert(${element}, n${oper.parent}${`, n${oper.anchor}`})\n`
|
||||
vaporHelpers.add('insert')
|
||||
break
|
||||
}
|
||||
case IRNodeTypes.PREPEND_NODE: {
|
||||
code = `prepend(n${oper.parent}, ${oper.elements
|
||||
.map((el) => `n${el}`)
|
||||
.join(', ')})\n`
|
||||
vaporHelpers.add('prepend')
|
||||
break
|
||||
}
|
||||
case IRNodeTypes.APPEND_NODE: {
|
||||
code = `append(n${oper.parent}, ${oper.elements
|
||||
.map((el) => `n${el}`)
|
||||
|
@ -148,11 +152,12 @@ function genChildren(children: DynamicChildren) {
|
|||
let code = ''
|
||||
// TODO
|
||||
let offset = 0
|
||||
|
||||
for (const [index, child] of Object.entries(children)) {
|
||||
const childrenLength = Object.keys(child.children).length
|
||||
if (child.ghost && child.placeholder === null && childrenLength === 0)
|
||||
if (child.ghost && child.placeholder === null && childrenLength === 0) {
|
||||
offset--
|
||||
continue
|
||||
}
|
||||
|
||||
code += ` ${Number(index) + offset}: [`
|
||||
|
||||
|
|
|
@ -11,6 +11,7 @@ export const enum IRNodeTypes {
|
|||
SET_HTML,
|
||||
|
||||
INSERT_NODE,
|
||||
PREPEND_NODE,
|
||||
APPEND_NODE,
|
||||
CREATE_TEXT_NODE,
|
||||
}
|
||||
|
@ -72,12 +73,17 @@ export interface CreateTextNodeIRNode extends IRNode {
|
|||
value: string
|
||||
}
|
||||
|
||||
export type InsertAnchor = number | 'first' | 'last'
|
||||
export interface InsertNodeIRNode extends IRNode {
|
||||
type: IRNodeTypes.INSERT_NODE
|
||||
element: number
|
||||
element: number | number[]
|
||||
parent: number
|
||||
anchor: number
|
||||
}
|
||||
|
||||
export interface PrependNodeIRNode extends IRNode {
|
||||
type: IRNodeTypes.PREPEND_NODE
|
||||
elements: number[]
|
||||
parent: number
|
||||
anchor: InsertAnchor
|
||||
}
|
||||
|
||||
export interface AppendNodeIRNode extends IRNode {
|
||||
|
@ -93,6 +99,7 @@ export type OperationNode =
|
|||
| SetHtmlIRNode
|
||||
| CreateTextNodeIRNode
|
||||
| InsertNodeIRNode
|
||||
| PrependNodeIRNode
|
||||
| AppendNodeIRNode
|
||||
|
||||
export interface DynamicInfo {
|
||||
|
|
|
@ -15,7 +15,6 @@ import {
|
|||
type RootIRNode,
|
||||
IRNodeTypes,
|
||||
DynamicInfo,
|
||||
InsertAnchor,
|
||||
} from './ir'
|
||||
import { isVoidTag } from '@vue/shared'
|
||||
|
||||
|
@ -170,41 +169,46 @@ function transformChildren(
|
|||
const childrenTemplate: string[] = []
|
||||
children.forEach((child, i) => walkNode(child, i))
|
||||
|
||||
const dynamicChildren = Object.values(ctx.dynamic.children)
|
||||
const dynamicCount = dynamicChildren.reduce(
|
||||
(prev, child) => prev + (child.ghost ? 1 : 0),
|
||||
0,
|
||||
)
|
||||
if (dynamicCount === children.length) {
|
||||
// all dynamic node
|
||||
ctx.registerOpration({
|
||||
type: IRNodeTypes.APPEND_NODE,
|
||||
loc: ctx.node.loc,
|
||||
elements: dynamicChildren.map((child) => child.id!),
|
||||
parent: ctx.reference(),
|
||||
})
|
||||
} else if (dynamicCount > 0 && dynamicCount < children.length) {
|
||||
// mixed
|
||||
for (const [indexString, child] of Object.entries(ctx.dynamic.children)) {
|
||||
if (!child.ghost) continue
|
||||
let prevChildren: DynamicInfo[] = []
|
||||
let hasStatic = false
|
||||
|
||||
const index = Number(indexString)
|
||||
let anchor: InsertAnchor
|
||||
if (index === 0) {
|
||||
anchor = 'first'
|
||||
} else if (index === children.length - 1) {
|
||||
anchor = 'last'
|
||||
} else {
|
||||
childrenTemplate[index] = `<!>`
|
||||
anchor = child.placeholder = ctx.incraseId()
|
||||
}
|
||||
for (let index = 0; index < children.length; index++) {
|
||||
const child = ctx.dynamic.children[index]
|
||||
|
||||
if (!child || !child.ghost) {
|
||||
if (prevChildren.length)
|
||||
if (hasStatic) {
|
||||
childrenTemplate[index - prevChildren.length] = `<!>`
|
||||
const anchor = (prevChildren[0].placeholder = ctx.incraseId())
|
||||
|
||||
ctx.registerOpration({
|
||||
type: IRNodeTypes.INSERT_NODE,
|
||||
loc: ctx.node.loc,
|
||||
element: prevChildren.map((child) => child.id!),
|
||||
parent: ctx.reference(),
|
||||
anchor,
|
||||
})
|
||||
} else {
|
||||
ctx.registerOpration({
|
||||
type: IRNodeTypes.PREPEND_NODE,
|
||||
loc: ctx.node.loc,
|
||||
elements: prevChildren.map((child) => child.id!),
|
||||
parent: ctx.reference(),
|
||||
})
|
||||
}
|
||||
hasStatic = true
|
||||
prevChildren = []
|
||||
continue
|
||||
}
|
||||
|
||||
prevChildren.push(child)
|
||||
|
||||
if (index === children.length - 1) {
|
||||
ctx.registerOpration({
|
||||
type: IRNodeTypes.INSERT_NODE,
|
||||
type: IRNodeTypes.APPEND_NODE,
|
||||
loc: ctx.node.loc,
|
||||
element: child.id!,
|
||||
elements: prevChildren.map((child) => child.id!),
|
||||
parent: ctx.reference(),
|
||||
anchor,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -58,6 +58,14 @@ export function insert(
|
|||
// }
|
||||
}
|
||||
|
||||
export function prepend(parent: ParentBlock, ...nodes: Node[]) {
|
||||
if (parent instanceof Node) {
|
||||
parent.prepend(...nodes)
|
||||
} else if (isArray(parent)) {
|
||||
parent.unshift(...nodes)
|
||||
}
|
||||
}
|
||||
|
||||
export function append(parent: ParentBlock, ...nodes: Node[]) {
|
||||
if (parent instanceof Node) {
|
||||
parent.append(...nodes)
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
<template>
|
||||
{{ 1 }}{{ 2 }}3{{ 4 }}{{ 5 }}6{{ 7 }}{{ 8 }}9{{ 'A' }}{{ 'B' }}
|
||||
</template>
|
Loading…
Reference in New Issue