Skip to content
This repository was archived by the owner on Jul 19, 2025. It is now read-only.

Commit b776f92

Browse files
Jevon617sxzz
andauthored
feat: v-once for component and v-for (#201)
* feat: v-once with v-for / v-once for component * refactor * refactor --------- Co-authored-by: 三咲智子 Kevin Deng <[email protected]>
1 parent f5f1150 commit b776f92

File tree

12 files changed

+96
-20
lines changed

12 files changed

+96
-20
lines changed

packages/compiler-vapor/__tests__/transforms/__snapshots__/vOnce.spec.ts.snap

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,21 @@ export function render(_ctx) {
3535
}"
3636
`;
3737

38+
exports[`compiler: v-once > on component 1`] = `
39+
"import { resolveComponent as _resolveComponent, createComponent as _createComponent, insert as _insert, template as _template } from 'vue/vapor';
40+
const t0 = _template("<div></div>")
41+
42+
export function render(_ctx) {
43+
const _component_Comp = _resolveComponent("Comp")
44+
const n1 = t0()
45+
const n0 = _createComponent(_component_Comp, [
46+
{ id: () => (_ctx.foo) }
47+
], null, null, null, true)
48+
_insert(n0, n1)
49+
return n1
50+
}"
51+
`;
52+
3853
exports[`compiler: v-once > on nested plain element 1`] = `
3954
"import { setDynamicProp as _setDynamicProp, template as _template } from 'vue/vapor';
4055
const t0 = _template("<div><div></div></div>")
@@ -47,6 +62,19 @@ export function render(_ctx) {
4762
}"
4863
`;
4964

65+
exports[`compiler: v-once > with v-for 1`] = `
66+
"import { createFor as _createFor, template as _template } from 'vue/vapor';
67+
const t0 = _template("<div></div>")
68+
69+
export function render(_ctx) {
70+
const n0 = _createFor(() => (_ctx.list), (_block) => {
71+
const n2 = t0()
72+
return [n2, () => {}]
73+
}, null, null, null, true)
74+
return n0
75+
}"
76+
`;
77+
5078
exports[`compiler: v-once > with v-if 1`] = `
5179
"import { createIf as _createIf, template as _template } from 'vue/vapor';
5280
const t0 = _template("<div></div>")

packages/compiler-vapor/__tests__/transforms/vOnce.spec.ts

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,25 @@ describe('compiler: v-once', () => {
131131
])
132132
})
133133

134-
test.todo('on component')
134+
test('on component', () => {
135+
const { ir, code } = compileWithOnce(`<div><Comp :id="foo" v-once /></div>`)
136+
expect(code).toMatchSnapshot()
137+
expect(ir.block.effect).lengthOf(0)
138+
expect(ir.block.operation).toMatchObject([
139+
{
140+
type: IRNodeTypes.CREATE_COMPONENT_NODE,
141+
id: 0,
142+
tag: 'Comp',
143+
once: true,
144+
},
145+
{
146+
type: IRNodeTypes.INSERT_NODE,
147+
elements: [0],
148+
parent: 1,
149+
},
150+
])
151+
})
152+
135153
test.todo('on slot outlet')
136154

137155
test('inside v-once', () => {
@@ -205,5 +223,16 @@ describe('compiler: v-once', () => {
205223
])
206224
})
207225

208-
test.todo('with v-for')
226+
test('with v-for', () => {
227+
const { ir, code } = compileWithOnce(`<div v-for="i in list" v-once />`)
228+
expect(code).toMatchSnapshot()
229+
expect(ir.block.effect).lengthOf(0)
230+
expect(ir.block.operation).toMatchObject([
231+
{
232+
type: IRNodeTypes.FOR,
233+
id: 0,
234+
once: true,
235+
},
236+
])
237+
})
209238
})

packages/compiler-vapor/src/generators/component.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ export function genCreateComponent(
3434
const { vaporHelper } = context
3535

3636
const tag = genTag()
37-
const { root, slots, dynamicSlots } = oper
37+
const { root, slots, dynamicSlots, once } = oper
3838
const rawProps = genRawProps(oper.props, context)
3939

4040
return [
@@ -46,7 +46,8 @@ export function genCreateComponent(
4646
rawProps,
4747
slots && genSlots(slots, context),
4848
dynamicSlots && genDynamicSlots(dynamicSlots, context),
49-
root && 'true',
49+
root ? 'true' : false,
50+
once && 'true',
5051
),
5152
...genDirectivesForElement(oper.id, context),
5253
]

packages/compiler-vapor/src/generators/for.ts

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ export function genFor(
1919
context: CodegenContext,
2020
): CodeFragment[] {
2121
const { vaporHelper, genEffects } = context
22-
const { source, value, key, index, render, keyProp } = oper
22+
const { source, value, key, index, render, keyProp, once } = oper
2323

2424
const rawValue = value && value.content
2525
const rawKey = key && key.content
@@ -67,11 +67,18 @@ export function genFor(
6767
}
6868

6969
genEffects.pop()
70-
7170
return [
7271
NEWLINE,
7372
`const n${oper.id} = `,
74-
...genCall(vaporHelper('createFor'), sourceExpr, blockFn, getKeyFn),
73+
...genCall(
74+
vaporHelper('createFor'),
75+
sourceExpr,
76+
blockFn,
77+
getKeyFn,
78+
false, // todo: getMemo
79+
false, // todo: hydrationNode
80+
once && 'true',
81+
),
7582
]
7683

7784
function genEffectInFor(effects: IREffect[]): CodeFragment[] {

packages/compiler-vapor/src/ir.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@ export interface ForIRNode extends BaseIRNode {
8282
index?: SimpleExpressionNode
8383
keyProp?: SimpleExpressionNode
8484
render: BlockIRNode
85+
once: boolean
8586
}
8687

8788
export interface IRProp extends Omit<DirectiveTransformResult, 'value'> {
@@ -224,6 +225,7 @@ export interface CreateComponentIRNode extends BaseIRNode {
224225

225226
asset: boolean
226227
root: boolean
228+
once: boolean
227229
}
228230

229231
export interface DeclareOldRefIRNode extends BaseIRNode {

packages/compiler-vapor/src/transforms/transformElement.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,7 @@ function transformComponentElement(
106106
root,
107107
slots: context.slots,
108108
dynamicSlots: context.dynamicSlots,
109+
once: context.inVOnce,
109110
})
110111
context.slots = undefined
111112
context.dynamicSlots = undefined

packages/compiler-vapor/src/transforms/vFor.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ export function processFor(
6363
index: index as SimpleExpressionNode | undefined,
6464
keyProp: keyProperty,
6565
render,
66+
once: context.inVOnce,
6667
})
6768
}
6869
}

packages/runtime-vapor/src/apiCreateComponent.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,15 @@ export function createComponent(
1414
slots: Slots | null = null,
1515
dynamicSlots: DynamicSlots | null = null,
1616
singleRoot: boolean = false,
17+
once: boolean = false,
1718
) {
1819
const current = currentInstance!
1920
const instance = createComponentInstance(
2021
comp,
2122
singleRoot ? withAttrs(rawProps) : rawProps,
2223
slots,
2324
dynamicSlots,
25+
once,
2426
)
2527
setupComponent(instance, singleRoot)
2628

packages/runtime-vapor/src/apiCreateFor.ts

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ export const createFor = (
2222
getKey?: (item: any, key: any, index?: number) => any,
2323
getMemo?: (item: any, key: any, index?: number) => any[],
2424
hydrationNode?: Node,
25+
once?: boolean,
2526
): Fragment => {
2627
let isMounted = false
2728
let oldBlocks: ForBlock[] = []
@@ -32,9 +33,12 @@ export const createFor = (
3233
nodes: oldBlocks,
3334
[fragmentKey]: true,
3435
}
35-
3636
const update = getMemo ? updateWithMemo : updateWithoutMemo
37-
renderEffect(() => {
37+
once ? renderList() : renderEffect(renderList)
38+
39+
return ref
40+
41+
function renderList() {
3842
const source = src()
3943
const newLength = getLength(source)
4044
const oldLength = oldBlocks.length
@@ -213,9 +217,7 @@ export const createFor = (
213217
}
214218

215219
ref.nodes = [(oldBlocks = newBlocks), parentAnchor]
216-
})
217-
218-
return ref
220+
}
219221

220222
function mount(
221223
source: any,

packages/runtime-vapor/src/apiCreateVaporApp.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ export function createVaporApp(
4747
rootProps,
4848
null,
4949
null,
50+
false,
5051
context,
5152
)
5253
setupComponent(instance)

0 commit comments

Comments
 (0)