mirror of https://github.com/vuejs/core.git
feat: add next helper for sibilings
This commit is contained in:
parent
2075042956
commit
2c15171dcf
|
@ -0,0 +1,19 @@
|
|||
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
||||
|
||||
exports[`compiler: children transform > children & sibling references 1`] = `
|
||||
"import { next as _next, setText as _setText, createTextNode as _createTextNode, insert as _insert, template as _template } from 'vue/vapor';
|
||||
const t0 = _template("<div><p></p> <!><p></p></div>")
|
||||
|
||||
export function render(_ctx) {
|
||||
const n4 = t0()
|
||||
const n0 = n4.firstChild
|
||||
const n3 = _next(n0, 2)
|
||||
const n2 = n3.nextSibling
|
||||
_setText(n0, 'first')
|
||||
const n1 = _createTextNode()
|
||||
_setText(n1, 'second', " ", 'third', " ")
|
||||
_setText(n2, 'forth')
|
||||
_insert(n1, n4, n3)
|
||||
return n4
|
||||
}"
|
||||
`;
|
|
@ -12,12 +12,12 @@ export function render(_ctx) {
|
|||
`;
|
||||
|
||||
exports[`compiler: v-once > basic 1`] = `
|
||||
"import { children as _children, createTextNode as _createTextNode, setText as _setText, setClass as _setClass, prepend as _prepend, template as _template } from 'vue/vapor';
|
||||
"import { createTextNode as _createTextNode, setText as _setText, setClass as _setClass, prepend as _prepend, template as _template } from 'vue/vapor';
|
||||
const t0 = _template("<div><span></span></div>")
|
||||
|
||||
export function render(_ctx) {
|
||||
const n2 = t0()
|
||||
const n1 = _children(n2, 0)
|
||||
const n1 = n2.firstChild
|
||||
const n0 = _createTextNode()
|
||||
_setText(n0, _ctx.msg, " ")
|
||||
_setClass(n1, _ctx.clz)
|
||||
|
@ -37,12 +37,12 @@ export function render(_ctx) {
|
|||
`;
|
||||
|
||||
exports[`compiler: v-once > on nested plain element 1`] = `
|
||||
"import { children as _children, setDynamicProp as _setDynamicProp, template as _template } from 'vue/vapor';
|
||||
"import { setDynamicProp as _setDynamicProp, template as _template } from 'vue/vapor';
|
||||
const t0 = _template("<div><div></div></div>")
|
||||
|
||||
export function render(_ctx) {
|
||||
const n1 = t0()
|
||||
const n0 = _children(n1, 0)
|
||||
const n0 = n1.firstChild
|
||||
_setDynamicProp(n0, "id", _ctx.foo)
|
||||
return n1
|
||||
}"
|
||||
|
|
|
@ -1,3 +1,39 @@
|
|||
import { makeCompile } from './_utils'
|
||||
import {
|
||||
transformChildren,
|
||||
transformElement,
|
||||
transformText,
|
||||
transformVIf,
|
||||
} from '../../src'
|
||||
|
||||
const compileWithElementTransform = makeCompile({
|
||||
nodeTransforms: [
|
||||
transformText,
|
||||
transformVIf,
|
||||
transformElement,
|
||||
transformChildren,
|
||||
],
|
||||
})
|
||||
|
||||
describe('compiler: children transform', () => {
|
||||
test.todo('basic')
|
||||
|
||||
test('children & sibling references', () => {
|
||||
const { code, vaporHelpers } = compileWithElementTransform(
|
||||
`<div>
|
||||
<p>{{'first'}}</p>
|
||||
{{'second'}}
|
||||
{{'third'}}
|
||||
<p>{{'forth'}}</p>
|
||||
</div>`,
|
||||
)
|
||||
expect(code).toMatchSnapshot()
|
||||
expect(Array.from(vaporHelpers)).containSubset([
|
||||
'next',
|
||||
'setText',
|
||||
'createTextNode',
|
||||
'insert',
|
||||
'template',
|
||||
])
|
||||
})
|
||||
})
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import type { CodegenContext } from '../generate'
|
||||
import { DynamicFlag, type IRDynamicInfo } from '../ir'
|
||||
import { NEWLINE, buildCodeFragment, genCall } from './utils'
|
||||
import { type CodeFragment, NEWLINE, buildCodeFragment, genCall } from './utils'
|
||||
|
||||
export function genTemplates(
|
||||
templates: string[],
|
||||
|
@ -19,7 +19,7 @@ export function genChildren(
|
|||
context: CodegenContext,
|
||||
from: number,
|
||||
paths: number[] = [],
|
||||
) {
|
||||
): CodeFragment[] {
|
||||
const { vaporHelper } = context
|
||||
const [frag, push] = buildCodeFragment()
|
||||
let offset = 0
|
||||
|
@ -29,6 +29,7 @@ export function genChildren(
|
|||
push(NEWLINE, `const n${id} = t${template}()`)
|
||||
}
|
||||
|
||||
let prev: [id: number, elementIndex: number] | undefined
|
||||
for (const [index, child] of children.entries()) {
|
||||
if (child.flags & DynamicFlag.NON_TEMPLATE) {
|
||||
offset--
|
||||
|
@ -44,20 +45,34 @@ export function genChildren(
|
|||
const elementIndex = Number(index) + offset
|
||||
const newPaths = [...paths, elementIndex]
|
||||
|
||||
if (id !== undefined) {
|
||||
push(
|
||||
NEWLINE,
|
||||
`const n${id} = `,
|
||||
...genCall(
|
||||
vaporHelper('children'),
|
||||
`n${from}`,
|
||||
...newPaths.map(String),
|
||||
),
|
||||
)
|
||||
push(...genChildren(child, context, id, []))
|
||||
} else {
|
||||
if (id === undefined) {
|
||||
push(...genChildren(child, context, from, newPaths))
|
||||
continue
|
||||
}
|
||||
|
||||
push(NEWLINE, `const n${id} = `)
|
||||
if (prev) {
|
||||
const offset = elementIndex - prev[1]
|
||||
if (offset === 1) {
|
||||
push(`n${prev[0]}.nextSibling`)
|
||||
} else {
|
||||
push(...genCall(vaporHelper('next'), `n${prev[0]}`, String(offset)))
|
||||
}
|
||||
} else {
|
||||
if (newPaths.length === 1 && newPaths[0] === 0) {
|
||||
push(`n${from}.firstChild`)
|
||||
} else {
|
||||
push(
|
||||
...genCall(
|
||||
vaporHelper('children'),
|
||||
`n${from}`,
|
||||
...newPaths.map(String),
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
prev = [id, elementIndex]
|
||||
push(...genChildren(child, context, id, []))
|
||||
}
|
||||
|
||||
return frag
|
||||
|
|
|
@ -21,7 +21,6 @@ export const transformChildren: NodeTransform = (node, context) => {
|
|||
|
||||
if (!isFragment && node.type !== NodeTypes.ELEMENT) return
|
||||
|
||||
let referencedCount = 0
|
||||
for (const [i, child] of node.children.entries()) {
|
||||
const childContext = createContext(
|
||||
child,
|
||||
|
@ -42,18 +41,12 @@ export const transformChildren: NodeTransform = (node, context) => {
|
|||
}
|
||||
} else {
|
||||
context.childrenTemplate.push(childContext.template)
|
||||
if (childContext.dynamic.flags & DynamicFlag.REFERENCED) {
|
||||
referencedCount++
|
||||
}
|
||||
}
|
||||
|
||||
context.dynamic.children[i] = childContext.dynamic
|
||||
}
|
||||
|
||||
if (!isFragment) {
|
||||
if (referencedCount > 1) {
|
||||
context.reference()
|
||||
}
|
||||
processDynamicChildren(context as TransformContext<ElementNode>)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
import { isArray } from '@vue/shared'
|
||||
|
||||
/*! #__NO_SIDE_EFFECTS__ */
|
||||
export function template(html: string) {
|
||||
let node: ChildNode
|
||||
|
@ -13,15 +11,19 @@ export function template(html: string) {
|
|||
}
|
||||
|
||||
/*! #__NO_SIDE_EFFECTS__ */
|
||||
export function children(node: Node | Node[], ...paths: number[]): Node {
|
||||
export function children(node: Node, ...paths: number[]): Node {
|
||||
for (const idx of paths) {
|
||||
if (isArray(node)) {
|
||||
node = node[idx]
|
||||
} else {
|
||||
for (let i = 0; i <= idx; i++) {
|
||||
node = (node as Node)[i === 0 ? 'firstChild' : 'nextSibling']!
|
||||
}
|
||||
for (let i = 0; i <= idx; i++) {
|
||||
node = (node as Node)[i === 0 ? 'firstChild' : 'nextSibling']!
|
||||
}
|
||||
}
|
||||
return node as Node
|
||||
}
|
||||
|
||||
/*! #__NO_SIDE_EFFECTS__ */
|
||||
export function next(node: Node, offset: number): Node {
|
||||
for (let i = 0; i < offset; i++) {
|
||||
node = (node as Node).nextSibling!
|
||||
}
|
||||
return node as Node
|
||||
}
|
||||
|
|
|
@ -73,7 +73,7 @@ export {
|
|||
type DirectiveModifiers,
|
||||
} from './directives'
|
||||
|
||||
export { template, children } from './dom/template'
|
||||
export { template, children, next } from './dom/template'
|
||||
export { insert, prepend, remove, createTextNode } from './dom/element'
|
||||
export { setStyle } from './dom/style'
|
||||
export {
|
||||
|
|
Loading…
Reference in New Issue