feat(directives): add support for function directives (#252)
This commit is contained in:
committed by
Evan You
parent
a72652f6e6
commit
0bac763f5a
@@ -144,4 +144,58 @@ describe('directives', () => {
|
||||
expect(beforeUnmount).toHaveBeenCalled()
|
||||
expect(unmounted).toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('should work with a function directive', async () => {
|
||||
const count = ref(0)
|
||||
|
||||
function assertBindings(binding: DirectiveBinding) {
|
||||
expect(binding.value).toBe(count.value)
|
||||
expect(binding.arg).toBe('foo')
|
||||
expect(binding.instance).toBe(_instance && _instance.renderProxy)
|
||||
expect(binding.modifiers && binding.modifiers.ok).toBe(true)
|
||||
}
|
||||
|
||||
const fn = jest.fn(((el, binding, vnode, prevVNode) => {
|
||||
expect(el.tag).toBe('div')
|
||||
expect(el.parentNode).toBe(root)
|
||||
|
||||
assertBindings(binding)
|
||||
|
||||
expect(vnode).toBe(_vnode)
|
||||
expect(prevVNode).toBe(_prevVnode)
|
||||
}) as DirectiveHook)
|
||||
|
||||
let _instance: ComponentInternalInstance | null = null
|
||||
let _vnode: VNode | null = null
|
||||
let _prevVnode: VNode | null = null
|
||||
const Comp = {
|
||||
setup() {
|
||||
_instance = currentInstance
|
||||
},
|
||||
render() {
|
||||
_prevVnode = _vnode
|
||||
_vnode = applyDirectives(h('div', count.value), [
|
||||
[
|
||||
fn,
|
||||
// value
|
||||
count.value,
|
||||
// argument
|
||||
'foo',
|
||||
// modifiers
|
||||
{ ok: true }
|
||||
]
|
||||
])
|
||||
return _vnode
|
||||
}
|
||||
}
|
||||
|
||||
const root = nodeOps.createElement('div')
|
||||
render(h(Comp), root)
|
||||
|
||||
expect(fn).toHaveBeenCalledTimes(1)
|
||||
|
||||
count.value++
|
||||
await nextTick()
|
||||
expect(fn).toHaveBeenCalledTimes(2)
|
||||
})
|
||||
})
|
||||
|
||||
@@ -34,7 +34,7 @@ export type DirectiveHook<T = any> = (
|
||||
prevVNode: VNode<any, T> | null
|
||||
) => void
|
||||
|
||||
export interface Directive<T = any> {
|
||||
export interface ObjectDirective<T = any> {
|
||||
beforeMount?: DirectiveHook<T>
|
||||
mounted?: DirectiveHook<T>
|
||||
beforeUpdate?: DirectiveHook<T>
|
||||
@@ -43,6 +43,10 @@ export interface Directive<T = any> {
|
||||
unmounted?: DirectiveHook<T>
|
||||
}
|
||||
|
||||
export type FunctionDirective<T = any> = DirectiveHook<T>
|
||||
|
||||
export type Directive<T = any> = ObjectDirective<T> | FunctionDirective<T>
|
||||
|
||||
type DirectiveModifiers = Record<string, boolean>
|
||||
|
||||
const valueCache = new WeakMap<Directive, WeakMap<any, any>>()
|
||||
@@ -60,8 +64,16 @@ function applyDirective(
|
||||
valueCacheForDir = new WeakMap<VNode, any>()
|
||||
valueCache.set(directive, valueCacheForDir)
|
||||
}
|
||||
|
||||
if (isFunction(directive)) {
|
||||
directive = {
|
||||
mounted: directive,
|
||||
updated: directive
|
||||
} as ObjectDirective
|
||||
}
|
||||
|
||||
for (const key in directive) {
|
||||
const hook = directive[key as keyof Directive]!
|
||||
const hook = directive[key as keyof ObjectDirective]!
|
||||
const hookKey = `vnode` + key[0].toUpperCase() + key.slice(1)
|
||||
const vnodeHook = (vnode: VNode, prevVNode: VNode | null) => {
|
||||
let oldValue
|
||||
|
||||
@@ -81,6 +81,8 @@ export {
|
||||
Directive,
|
||||
DirectiveBinding,
|
||||
DirectiveHook,
|
||||
ObjectDirective,
|
||||
FunctionDirective,
|
||||
DirectiveArguments
|
||||
} from './directives'
|
||||
export { SuspenseBoundary } from './suspense'
|
||||
|
||||
Reference in New Issue
Block a user