diff --git a/packages/core/src/index.ts b/packages/core/src/index.ts index 5718252c..f73ded19 100644 --- a/packages/core/src/index.ts +++ b/packages/core/src/index.ts @@ -15,7 +15,7 @@ export { createComponentInstance } from './componentUtils' // Optional APIs // these are imported on-demand and can be tree-shaken -export { applyDirective } from './optional/directive' +export { applyDirectives } from './optional/directive' export { Provide, Inject } from './optional/context' export { createAsyncComponent } from './optional/asyncComponent' export { KeepAlive } from './optional/keepAlive' diff --git a/packages/core/src/optional/directive.ts b/packages/core/src/optional/directive.ts index fc756b7a..7ee84bb7 100644 --- a/packages/core/src/optional/directive.ts +++ b/packages/core/src/optional/directive.ts @@ -1,5 +1,21 @@ -import { VNode } from '../vdom' +/** +Runtime helper for applying directives to a vnode. Example usage: + +const comp = resolveComponent(this, 'comp') +const foo = resolveDirective(this, 'foo') +const bar = resolveDirective(this, 'bar') + +return applyDirectives( + h(comp), + this, + [foo, this.x], + [bar, this.y] +) +*/ + +import { VNode, cloneVNode, VNodeData } from '../vdom' import { ComponentInstance } from '../component' +import { EMPTY_OBJ } from '../utils' interface DirectiveBinding { instance: ComponentInstance @@ -30,14 +46,13 @@ type DirectiveModifiers = Record const valueCache = new WeakMap>() export function applyDirective( - vnode: VNode, + data: VNodeData, instance: ComponentInstance, directive: Directive, value?: any, arg?: string, modifiers?: DirectiveModifiers -): VNode { - const data = vnode.data || (vnode.data = {}) +) { let valueCacheForDir = valueCache.get(directive) as WeakMap if (!valueCacheForDir) { valueCacheForDir = new WeakMap() @@ -67,9 +82,10 @@ export function applyDirective( ) } const existing = data[hookKey] - data[hookKey] = existing ? [].concat(existing, vnodeHook as any) : vnodeHook + data[hookKey] = existing + ? [].concat(existing as any, vnodeHook as any) + : vnodeHook } - return vnode } type DirectiveArguments = [ @@ -84,8 +100,9 @@ export function applyDirectives( instance: ComponentInstance, ...directives: DirectiveArguments ) { + vnode = cloneVNode(vnode, EMPTY_OBJ) for (let i = 0; i < directives.length; i++) { - applyDirective(vnode, instance, ...directives[i]) + applyDirective(vnode.data as VNodeData, instance, ...directives[i]) } return vnode } diff --git a/packages/core/src/vdom.ts b/packages/core/src/vdom.ts index 989ce275..d5dfd2ae 100644 --- a/packages/core/src/vdom.ts +++ b/packages/core/src/vdom.ts @@ -5,7 +5,7 @@ import { } from './component' import { VNodeFlags, ChildrenFlags } from './flags' import { createComponentClassFromOptions } from './componentUtils' -import { normalizeClass, normalizeStyle, handlersRE } from './utils' +import { normalizeClass, normalizeStyle, handlersRE, EMPTY_OBJ } from './utils' // Vue core is platform agnostic, so we are not using Element for "DOM" nodes. export interface RenderNode { @@ -264,19 +264,27 @@ export function cloneVNode(vnode: VNode, extraData?: VNodeData): VNode { clonedData[key] = data[key] } } - for (const key in extraData) { - if (key === 'class') { - clonedData.class = normalizeClass([clonedData.class, extraData.class]) - } else if (key === 'style') { - clonedData.style = normalizeStyle([clonedData.style, extraData.style]) - } else if (handlersRE.test(key)) { - // on*, nativeOn*, vnode* - const existing = clonedData[key] - clonedData[key] = existing - ? [].concat(existing, extraData[key]) - : extraData[key] - } else { - clonedData[key] = extraData[key] + if (extraData !== EMPTY_OBJ) { + for (const key in extraData) { + if (key === 'class') { + clonedData.class = normalizeClass([ + clonedData.class, + extraData.class + ]) + } else if (key === 'style') { + clonedData.style = normalizeStyle([ + clonedData.style, + extraData.style + ]) + } else if (handlersRE.test(key)) { + // on*, nativeOn*, vnode* + const existing = clonedData[key] + clonedData[key] = existing + ? [].concat(existing, extraData[key]) + : extraData[key] + } else { + clonedData[key] = extraData[key] + } } } }