]> git.ipfire.org Git - thirdparty/vuejs/core.git/commitdiff
wip(vapor): new impl + test for vapor custom directive
authorEvan You <evan@vuejs.org>
Wed, 12 Feb 2025 09:18:58 +0000 (17:18 +0800)
committerEvan You <evan@vuejs.org>
Wed, 12 Feb 2025 09:27:04 +0000 (17:27 +0800)
packages-private/vapor-e2e-test/todomvc/App.vue
packages/runtime-vapor/__tests__/directives/customDirective.spec.ts [new file with mode: 0644]
packages/runtime-vapor/src/directives/custom.ts

index e7f97968b2f779c0c2eea567bc029d3302325499..910ada51093228763f95482f4fef6c2b74aeb635 100644 (file)
@@ -2,11 +2,9 @@
 import {
   reactive,
   computed,
-  watchEffect,
   onMounted,
   onUnmounted,
-  next,
-  nextTick,
+  watchPostEffect,
 } from 'vue'
 
 const STORAGE_KEY = 'todos-vuejs-3.x'
@@ -72,7 +70,7 @@ const state = reactive({
   }),
 })
 
-watchEffect(() => {
+watchPostEffect(() => {
   todoStorage.save(state.todos)
 })
 
@@ -138,8 +136,8 @@ function removeCompleted() {
 }
 
 // vapor custom directive
-const vTodoFocus = (el, value) => () => {
-  if (value()) nextTick(() => el.focus())
+const vTodoFocus = (el, value) => {
+  watchPostEffect(() => value() && el.focus())
 }
 </script>
 
diff --git a/packages/runtime-vapor/__tests__/directives/customDirective.spec.ts b/packages/runtime-vapor/__tests__/directives/customDirective.spec.ts
new file mode 100644 (file)
index 0000000..1fd5f95
--- /dev/null
@@ -0,0 +1,39 @@
+import { effectScope, ref } from '@vue/reactivity'
+import { type VaporDirective, withVaporDirectives } from '../../src'
+import { nextTick, watchEffect } from '@vue/runtime-dom'
+
+describe('custom directive', () => {
+  it('should work', async () => {
+    const teardown = vi.fn()
+    const dir: VaporDirective = vi.fn((el, source) => {
+      watchEffect(() => {
+        el.textContent = source()
+      })
+      return teardown
+    })
+    const scope = effectScope()
+    const el = document.createElement('div')
+    const n = ref(1)
+    const source = () => n.value
+    const modifiers = { mod: true }
+    scope.run(() => {
+      withVaporDirectives(el, [[dir, source, undefined, modifiers]])
+    })
+    expect(dir).toHaveBeenCalledWith(el, source, undefined, modifiers)
+    expect(teardown).not.toHaveBeenCalled()
+
+    expect(el.textContent).toBe('1')
+
+    n.value = 2
+    await nextTick()
+    expect(el.textContent).toBe('2')
+
+    scope.stop()
+    expect(teardown).toHaveBeenCalled()
+
+    n.value = 3
+    await nextTick()
+    // should be stopped and not update
+    expect(el.textContent).toBe('2')
+  })
+})
index 008caa74631dac82a43cb16b00701864985fa5fc..32cfe968b50f93b1b292ad0eddb9033fe1aa6097 100644 (file)
@@ -1,6 +1,5 @@
-import type { DirectiveModifiers } from '@vue/runtime-dom'
+import { type DirectiveModifiers, onScopeDispose } from '@vue/runtime-dom'
 import type { VaporComponentInstance } from '../component'
-import { renderEffect } from '../renderEffect'
 
 // !! vapor directive is different from vdom directives
 export type VaporDirective = (
@@ -13,11 +12,11 @@ export type VaporDirective = (
 type VaporDirectiveArguments = Array<
   | [VaporDirective | undefined]
   | [VaporDirective | undefined, () => any]
-  | [VaporDirective | undefined, () => any, argument: string]
+  | [VaporDirective | undefined, (() => any) | undefined, argument: string]
   | [
       VaporDirective | undefined,
-      value: () => any,
-      argument: string,
+      value: (() => any) | undefined,
+      argument: string | undefined,
       modifiers: DirectiveModifiers,
     ]
 >
@@ -30,7 +29,7 @@ export function withVaporDirectives(
   for (const [dir, value, argument, modifiers] of dirs) {
     if (dir) {
       const ret = dir(node, value, argument, modifiers)
-      if (ret) renderEffect(ret)
+      if (ret) onScopeDispose(ret)
     }
   }
 }