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 {
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>

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 { 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)
}
}
}