wip(vapor): new impl + test for vapor custom directive

This commit is contained in:
Evan You 2025-02-12 17:18:58 +08:00
parent 1b50febfe9
commit c6fe9f9417
No known key found for this signature in database
GPG Key ID: 00E9AB7A6704CE0A
3 changed files with 48 additions and 12 deletions

View File

@ -2,11 +2,9 @@
import { import {
reactive, reactive,
computed, computed,
watchEffect,
onMounted, onMounted,
onUnmounted, onUnmounted,
next, watchPostEffect,
nextTick,
} from 'vue' } from 'vue'
const STORAGE_KEY = 'todos-vuejs-3.x' const STORAGE_KEY = 'todos-vuejs-3.x'
@ -72,7 +70,7 @@ const state = reactive({
}), }),
}) })
watchEffect(() => { watchPostEffect(() => {
todoStorage.save(state.todos) todoStorage.save(state.todos)
}) })
@ -138,8 +136,8 @@ function removeCompleted() {
} }
// vapor custom directive // vapor custom directive
const vTodoFocus = (el, value) => () => { const vTodoFocus = (el, value) => {
if (value()) nextTick(() => el.focus()) watchPostEffect(() => value() && el.focus())
} }
</script> </script>

View File

@ -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')
})
})

View 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 type { VaporComponentInstance } from '../component'
import { renderEffect } from '../renderEffect'
// !! vapor directive is different from vdom directives // !! vapor directive is different from vdom directives
export type VaporDirective = ( export type VaporDirective = (
@ -13,11 +12,11 @@ export type VaporDirective = (
type VaporDirectiveArguments = Array< type VaporDirectiveArguments = Array<
| [VaporDirective | undefined] | [VaporDirective | undefined]
| [VaporDirective | undefined, () => any] | [VaporDirective | undefined, () => any]
| [VaporDirective | undefined, () => any, argument: string] | [VaporDirective | undefined, (() => any) | undefined, argument: string]
| [ | [
VaporDirective | undefined, VaporDirective | undefined,
value: () => any, value: (() => any) | undefined,
argument: string, argument: string | undefined,
modifiers: DirectiveModifiers, modifiers: DirectiveModifiers,
] ]
> >
@ -30,7 +29,7 @@ export function withVaporDirectives(
for (const [dir, value, argument, modifiers] of dirs) { for (const [dir, value, argument, modifiers] of dirs) {
if (dir) { if (dir) {
const ret = dir(node, value, argument, modifiers) const ret = dir(node, value, argument, modifiers)
if (ret) renderEffect(ret) if (ret) onScopeDispose(ret)
} }
} }
} }