Evan You 6 лет назад
Родитель
Сommit
0f0ca4ae7c

+ 5 - 0
packages/runtime-core/src/createRenderer.ts

@@ -35,6 +35,7 @@ import { resolveSlots } from './componentSlots'
 import { PatchFlags } from './patchFlags'
 import { ShapeFlags } from './shapeFlags'
 import { pushWarningContext, popWarningContext, warn } from './warning'
+import { invokeDirectiveHook } from './directives'
 
 const prodEffectOptions = {
   scheduler: queueJob
@@ -248,6 +249,7 @@ export function createRenderer(options: RendererOptions) {
         if (isReservedProp(key)) continue
         hostPatchProp(el, key, props[key], null, isSVG)
       }
+      invokeDirectiveHook(props.vnodeBeforeMount, parentComponent, vnode)
     }
     if (shapeFlag & ShapeFlags.TEXT_CHILDREN) {
       hostSetElementText(el, vnode.children as string)
@@ -261,6 +263,9 @@ export function createRenderer(options: RendererOptions) {
       )
     }
     hostInsert(el, container, anchor)
+    if (props != null) {
+      invokeDirectiveHook(props.vnodeMounted, parentComponent, vnode)
+    }
   }
 
   function mountChildren(

+ 25 - 1
packages/runtime-core/src/directives.ts

@@ -13,13 +13,14 @@ return applyDirectives(
 */
 
 import { VNode, cloneVNode } from './vnode'
-import { extend } from '@vue/shared'
+import { extend, isArray, isFunction } from '@vue/shared'
 import { warn } from './warning'
 import {
   ComponentInstance,
   currentRenderingInstance,
   ComponentRenderProxy
 } from './component'
+import { callWithAsyncErrorHandling, ErrorTypes } from './errorHandling'
 
 interface DirectiveBinding {
   instance: ComponentRenderProxy | null
@@ -120,3 +121,26 @@ export function resolveDirective(name: string): Directive {
   // TODO
   return {} as any
 }
+
+export function invokeDirectiveHook(
+  hook: Function | Function[],
+  instance: ComponentInstance | null,
+  vnode: VNode
+) {
+  if (hook == null) {
+    return
+  }
+  const args = [vnode]
+  if (isArray(hook)) {
+    for (let i = 0; i < hook.length; i++) {
+      callWithAsyncErrorHandling(
+        hook[i],
+        instance,
+        ErrorTypes.DIRECTIVE_HOOK,
+        args
+      )
+    }
+  } else if (isFunction(hook)) {
+    callWithAsyncErrorHandling(hook, instance, ErrorTypes.DIRECTIVE_HOOK, args)
+  }
+}

+ 2 - 0
packages/runtime-core/src/errorHandling.ts

@@ -12,6 +12,7 @@ export const enum ErrorTypes {
   WATCH_CLEANUP,
   NATIVE_EVENT_HANDLER,
   COMPONENT_EVENT_HANDLER,
+  DIRECTIVE_HOOK,
   SCHEDULER
 }
 
@@ -36,6 +37,7 @@ export const ErrorTypeStrings: Record<number | string, string> = {
   [ErrorTypes.WATCH_CLEANUP]: 'watcher cleanup function',
   [ErrorTypes.NATIVE_EVENT_HANDLER]: 'native event handler',
   [ErrorTypes.COMPONENT_EVENT_HANDLER]: 'component event handler',
+  [ErrorTypes.DIRECTIVE_HOOK]: 'directive hook',
   [ErrorTypes.SCHEDULER]:
     'scheduler flush. This may be a Vue internals bug. ' +
     'Please open an issue at https://new-issue.vuejs.org/?repo=vuejs/vue'

+ 2 - 3
packages/shared/src/index.ts

@@ -3,8 +3,6 @@ export const EMPTY_ARR: [] = []
 
 export const NOOP = () => {}
 
-export const reservedPropRE = /^(?:key|ref|slots)$|^vnode/
-
 export const isOn = (key: string) => key[0] === 'o' && key[1] === 'n'
 
 export const extend = <T extends object, U extends object>(
@@ -24,8 +22,9 @@ export const isString = (val: any): val is string => typeof val === 'string'
 export const isObject = (val: any): val is Record<any, any> =>
   val !== null && typeof val === 'object'
 
+const vnodeHooksRE = /^vnode/
 export const isReservedProp = (key: string): boolean =>
-  key === 'key' || key === 'ref'
+  key === 'key' || key === 'ref' || vnodeHooksRE.test(key)
 
 const camelizeRE = /-(\w)/g
 export const camelize = (str: string): string => {