refactor: tweak applyDirectives

This commit is contained in:
Evan You 2018-10-09 18:55:16 -04:00
parent 1a68bcb4a7
commit b527705928
3 changed files with 47 additions and 22 deletions

View File

@ -15,7 +15,7 @@ export { createComponentInstance } from './componentUtils'
// Optional APIs // Optional APIs
// these are imported on-demand and can be tree-shaken // 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 { Provide, Inject } from './optional/context'
export { createAsyncComponent } from './optional/asyncComponent' export { createAsyncComponent } from './optional/asyncComponent'
export { KeepAlive } from './optional/keepAlive' export { KeepAlive } from './optional/keepAlive'

View File

@ -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 { ComponentInstance } from '../component'
import { EMPTY_OBJ } from '../utils'
interface DirectiveBinding { interface DirectiveBinding {
instance: ComponentInstance instance: ComponentInstance
@ -30,14 +46,13 @@ type DirectiveModifiers = Record<string, boolean>
const valueCache = new WeakMap<Directive, WeakMap<any, any>>() const valueCache = new WeakMap<Directive, WeakMap<any, any>>()
export function applyDirective( export function applyDirective(
vnode: VNode, data: VNodeData,
instance: ComponentInstance, instance: ComponentInstance,
directive: Directive, directive: Directive,
value?: any, value?: any,
arg?: string, arg?: string,
modifiers?: DirectiveModifiers modifiers?: DirectiveModifiers
): VNode { ) {
const data = vnode.data || (vnode.data = {})
let valueCacheForDir = valueCache.get(directive) as WeakMap<VNode, any> let valueCacheForDir = valueCache.get(directive) as WeakMap<VNode, any>
if (!valueCacheForDir) { if (!valueCacheForDir) {
valueCacheForDir = new WeakMap<VNode, any>() valueCacheForDir = new WeakMap<VNode, any>()
@ -67,9 +82,10 @@ export function applyDirective(
) )
} }
const existing = data[hookKey] 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 = [ type DirectiveArguments = [
@ -84,8 +100,9 @@ export function applyDirectives(
instance: ComponentInstance, instance: ComponentInstance,
...directives: DirectiveArguments ...directives: DirectiveArguments
) { ) {
vnode = cloneVNode(vnode, EMPTY_OBJ)
for (let i = 0; i < directives.length; i++) { for (let i = 0; i < directives.length; i++) {
applyDirective(vnode, instance, ...directives[i]) applyDirective(vnode.data as VNodeData, instance, ...directives[i])
} }
return vnode return vnode
} }

View File

@ -5,7 +5,7 @@ import {
} from './component' } from './component'
import { VNodeFlags, ChildrenFlags } from './flags' import { VNodeFlags, ChildrenFlags } from './flags'
import { createComponentClassFromOptions } from './componentUtils' 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. // Vue core is platform agnostic, so we are not using Element for "DOM" nodes.
export interface RenderNode { export interface RenderNode {
@ -264,19 +264,27 @@ export function cloneVNode(vnode: VNode, extraData?: VNodeData): VNode {
clonedData[key] = data[key] clonedData[key] = data[key]
} }
} }
for (const key in extraData) { if (extraData !== EMPTY_OBJ) {
if (key === 'class') { for (const key in extraData) {
clonedData.class = normalizeClass([clonedData.class, extraData.class]) if (key === 'class') {
} else if (key === 'style') { clonedData.class = normalizeClass([
clonedData.style = normalizeStyle([clonedData.style, extraData.style]) clonedData.class,
} else if (handlersRE.test(key)) { extraData.class
// on*, nativeOn*, vnode* ])
const existing = clonedData[key] } else if (key === 'style') {
clonedData[key] = existing clonedData.style = normalizeStyle([
? [].concat(existing, extraData[key]) clonedData.style,
: extraData[key] extraData.style
} else { ])
clonedData[key] = extraData[key] } 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]
}
} }
} }
} }