Skip to content

Commit

Permalink
fix: handle v-for + custom directive
Browse files Browse the repository at this point in the history
  • Loading branch information
linzhe141 committed Dec 18, 2024
1 parent 11f7674 commit a6a88b2
Show file tree
Hide file tree
Showing 4 changed files with 67 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,26 @@ return function render(_ctx, _cache) {
}"
`;

exports[`compiler: v-for > codegen > template w/ v-for + custom directive should not be STABLE_FRAGMENT 1`] = `
"const _Vue = Vue
return function render(_ctx, _cache) {
with (_ctx) {
const { renderList: _renderList, Fragment: _Fragment, openBlock: _openBlock, createElementBlock: _createElementBlock, resolveDirective: _resolveDirective, withDirectives: _withDirectives, createCommentVNode: _createCommentVNode } = _Vue
const _directive_focus = _resolveDirective("focus")
return show
? (_openBlock(true), _createElementBlock(_Fragment, { key: 0 }, _renderList(arr, (i) => {
return _withDirectives((_openBlock(), _createElementBlock("h1", { key: i })), [
[_directive_focus]
])
}), 128 /* KEYED_FRAGMENT */))
: _createCommentVNode("v-if", true)
}
}"
`;

exports[`compiler: v-for > codegen > v-for on <slot/> 1`] = `
"const _Vue = Vue
Expand Down
7 changes: 7 additions & 0 deletions packages/compiler-core/__tests__/transforms/vFor.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1073,5 +1073,12 @@ describe('compiler: v-for', () => {
},
})
})

test('template w/ v-for + custom directive should not be STABLE_FRAGMENT', () => {
const { root } = parseWithForTransform(
'<template v-if="show"><h1 v-for="i in arr" :key="i" v-focus></h1></template>',
)
expect(generate(root).code).toMatchSnapshot()

Check failure on line 1081 in packages/compiler-core/__tests__/transforms/vFor.spec.ts

View workflow job for this annotation

GitHub Actions / test / unit-test

packages/compiler-core/__tests__/transforms/transformElement.spec.ts > compiler: v-for > codegen > template w/ v-for + custom directive should not be STABLE_FRAGMENT

Error: Snapshot `compiler: v-for > codegen > template w/ v-for + custom directive should not be STABLE_FRAGMENT 1` mismatched ❯ packages/compiler-core/__tests__/transforms/vFor.spec.ts:1081:35

Check failure on line 1081 in packages/compiler-core/__tests__/transforms/vFor.spec.ts

View workflow job for this annotation

GitHub Actions / test / unit-test-windows

packages/compiler-core/__tests__/transforms/transformElement.spec.ts > compiler: v-for > codegen > template w/ v-for + custom directive should not be STABLE_FRAGMENT

Error: Snapshot `compiler: v-for > codegen > template w/ v-for + custom directive should not be STABLE_FRAGMENT 1` mismatched ❯ packages/compiler-core/__tests__/transforms/vFor.spec.ts:1081:35
})
})
})
10 changes: 8 additions & 2 deletions packages/compiler-core/src/transforms/vFor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -105,10 +105,16 @@ export const transformFor: NodeTransform = createStructuralDirectiveTransform(
)
}
}

const maybeRuntimeDir = findDir(
node,
/^(?!if$|else$|else-if$|bind$|for$|memo$|on$|once$|slot$|model$).*$/,
true,
)
const isStableFragment =
forNode.source.type === NodeTypes.SIMPLE_EXPRESSION &&
forNode.source.constType > ConstantTypes.NOT_CONSTANT
forNode.source.constType > ConstantTypes.NOT_CONSTANT &&
!maybeRuntimeDir

const fragmentFlag = isStableFragment
? PatchFlags.STABLE_FRAGMENT
: keyProp
Expand Down
32 changes: 32 additions & 0 deletions packages/vue/__tests__/index.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -276,6 +276,38 @@ describe('compiler + runtime integration', () => {
expect(container.innerHTML).toBe(`<div>false<div>true</div></div>`)
})

it('should trigger custom directive unmounted hook with v-for', async () => {
const mounted = vi.fn()
const unmounted = vi.fn()
const visible = ref(true)
const App = {
directives: {
foo: {
mounted,
unmounted,
},
},
setup() {
const arr = [1, 2, 3]
return {
arr,
visible,
}
},
template: `<template v-if="visible">
<h1 v-for="i in arr" :key="i" v-foo></h1>
</template>`,
}

const container = document.createElement('div')
createApp(App).mount(container)
await nextTick()
expect(mounted).toHaveBeenCalledTimes(3)
visible.value = false
await nextTick()
expect(unmounted).toHaveBeenCalledTimes(3)
})

test('v-for + v-once', async () => {
const list = reactive([1])
const App = {
Expand Down

0 comments on commit a6a88b2

Please sign in to comment.