From a6a88b207205693a70595782109dee6d1542abe4 Mon Sep 17 00:00:00 2001 From: linzhe141 <1572213544@qq.com> Date: Wed, 18 Dec 2024 11:48:32 +0800 Subject: [PATCH] fix: handle v-for + custom directive --- .../__snapshots__/vFor.spec.ts.snap | 20 ++++++++++++ .../__tests__/transforms/vFor.spec.ts | 7 ++++ packages/compiler-core/src/transforms/vFor.ts | 10 ++++-- packages/vue/__tests__/index.spec.ts | 32 +++++++++++++++++++ 4 files changed, 67 insertions(+), 2 deletions(-) diff --git a/packages/compiler-core/__tests__/transforms/__snapshots__/vFor.spec.ts.snap b/packages/compiler-core/__tests__/transforms/__snapshots__/vFor.spec.ts.snap index 3da778eb675..225861919da 100644 --- a/packages/compiler-core/__tests__/transforms/__snapshots__/vFor.spec.ts.snap +++ b/packages/compiler-core/__tests__/transforms/__snapshots__/vFor.spec.ts.snap @@ -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 1`] = ` "const _Vue = Vue diff --git a/packages/compiler-core/__tests__/transforms/vFor.spec.ts b/packages/compiler-core/__tests__/transforms/vFor.spec.ts index fead2476ac5..8ad5fba9999 100644 --- a/packages/compiler-core/__tests__/transforms/vFor.spec.ts +++ b/packages/compiler-core/__tests__/transforms/vFor.spec.ts @@ -1073,5 +1073,12 @@ describe('compiler: v-for', () => { }, }) }) + + test('template w/ v-for + custom directive should not be STABLE_FRAGMENT', () => { + const { root } = parseWithForTransform( + '', + ) + expect(generate(root).code).toMatchSnapshot() + }) }) }) diff --git a/packages/compiler-core/src/transforms/vFor.ts b/packages/compiler-core/src/transforms/vFor.ts index 0dca0ba9ab4..ec32ef41438 100644 --- a/packages/compiler-core/src/transforms/vFor.ts +++ b/packages/compiler-core/src/transforms/vFor.ts @@ -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 diff --git a/packages/vue/__tests__/index.spec.ts b/packages/vue/__tests__/index.spec.ts index 0c969f15981..ee54042ad51 100644 --- a/packages/vue/__tests__/index.spec.ts +++ b/packages/vue/__tests__/index.spec.ts @@ -276,6 +276,38 @@ describe('compiler + runtime integration', () => { expect(container.innerHTML).toBe(`
false
true
`) }) + 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: ``, + } + + 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 = {