]> git.ipfire.org Git - thirdparty/vuejs/core.git/commitdiff
refactor: tweak applyDirectives
authorEvan You <yyx990803@gmail.com>
Tue, 9 Oct 2018 22:55:16 +0000 (18:55 -0400)
committerEvan You <yyx990803@gmail.com>
Tue, 9 Oct 2018 22:55:16 +0000 (18:55 -0400)
packages/core/src/index.ts
packages/core/src/optional/directive.ts
packages/core/src/vdom.ts

index 5718252c8a6a74e8af2409460a1756d35eb9a419..f73ded1997e1a93eced7e9bfd9b9ae9f02c3fc00 100644 (file)
@@ -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'
index fc756b7a824e454239e7eefbd76b0d06efa779a0..7ee84bb7570ffd74bad2b9d5ed3538377180ff04 100644 (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 { EMPTY_OBJ } from '../utils'
 
 interface DirectiveBinding {
   instance: ComponentInstance
@@ -30,14 +46,13 @@ type DirectiveModifiers = Record<string, boolean>
 const valueCache = new WeakMap<Directive, WeakMap<any, any>>()
 
 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<VNode, any>
   if (!valueCacheForDir) {
     valueCacheForDir = new WeakMap<VNode, any>()
@@ -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
 }
index 989ce275361e49e9580300caf9e64f08a557bffe..d5dfd2ae0b84996e6e4e24bcf17533b0afdc8721 100644 (file)
@@ -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]
+          }
         }
       }
     }