]> git.ipfire.org Git - thirdparty/vuejs/core.git/commitdiff
feat: directives
authorEvan You <yyx990803@gmail.com>
Sun, 1 Sep 2019 02:17:46 +0000 (22:17 -0400)
committerEvan You <yyx990803@gmail.com>
Sun, 1 Sep 2019 02:17:46 +0000 (22:17 -0400)
packages/runtime-core/src/createRenderer.ts
packages/runtime-core/src/directives.ts
packages/runtime-core/src/patchFlags.ts
packages/runtime-core/src/vnode.ts

index 7870299ad2b1ab9f9ab32672267b858dd9c0e52b..7a1dc92d4def208e308e2dd647107fd980e2d81f 100644 (file)
@@ -249,7 +249,9 @@ export function createRenderer(options: RendererOptions) {
         if (isReservedProp(key)) continue
         hostPatchProp(el, key, props[key], null, isSVG)
       }
-      invokeDirectiveHook(props.vnodeBeforeMount, parentComponent, vnode)
+      if (props.vnodeBeforeMount != null) {
+        invokeDirectiveHook(props.vnodeBeforeMount, parentComponent, vnode)
+      }
     }
     if (shapeFlag & ShapeFlags.TEXT_CHILDREN) {
       hostSetElementText(el, vnode.children as string)
@@ -263,8 +265,10 @@ export function createRenderer(options: RendererOptions) {
       )
     }
     hostInsert(el, container, anchor)
-    if (props != null) {
-      invokeDirectiveHook(props.vnodeMounted, parentComponent, vnode)
+    if (props != null && props.vnodeMounted != null) {
+      queuePostFlushCb(() => {
+        invokeDirectiveHook(props.vnodeMounted, parentComponent, vnode)
+      })
     }
   }
 
@@ -294,6 +298,10 @@ export function createRenderer(options: RendererOptions) {
     const oldProps = (n1 && n1.props) || EMPTY_OBJ
     const newProps = n2.props || EMPTY_OBJ
 
+    if (newProps.vnodeBeforeUpdate != null) {
+      invokeDirectiveHook(newProps.vnodeBeforeUpdate, parentComponent, n2)
+    }
+
     if (patchFlag) {
       // the presence of a patchFlag means this element's render code was
       // generated by the compiler and can take the fast path.
@@ -379,6 +387,12 @@ export function createRenderer(options: RendererOptions) {
       // full diff
       patchChildren(n1, n2, el, null, parentComponent, isSVG)
     }
+
+    if (newProps.vnodeUpdated != null) {
+      queuePostFlushCb(() => {
+        invokeDirectiveHook(newProps.vnodeUpdated, parentComponent, n2)
+      })
+    }
   }
 
   function patchProps(
@@ -1017,27 +1031,37 @@ export function createRenderer(options: RendererOptions) {
     parentComponent: ComponentInstance | null,
     doRemove?: boolean
   ) {
+    const {
+      props,
+      ref,
+      type,
+      component,
+      children,
+      dynamicChildren,
+      shapeFlag,
+      anchor
+    } = vnode
+
     // unset ref
-    if (vnode.ref !== null && parentComponent !== null) {
-      setRef(vnode.ref, null, parentComponent, null)
+    if (ref !== null && parentComponent !== null) {
+      setRef(ref, null, parentComponent, null)
     }
 
-    const instance = vnode.component
-    if (instance != null) {
-      unmountComponent(instance, doRemove)
+    if (component != null) {
+      unmountComponent(component, doRemove)
       return
     }
 
-    const shouldRemoveChildren = vnode.type === Fragment && doRemove
-    if (vnode.dynamicChildren != null) {
-      unmountChildren(
-        vnode.dynamicChildren,
-        parentComponent,
-        shouldRemoveChildren
-      )
-    } else if (vnode.shapeFlag & ShapeFlags.ARRAY_CHILDREN) {
+    if (props != null && props.vnodeBeforeUnmount != null) {
+      invokeDirectiveHook(props.vnodeBeforeUnmount, parentComponent, vnode)
+    }
+
+    const shouldRemoveChildren = type === Fragment && doRemove
+    if (dynamicChildren != null) {
+      unmountChildren(dynamicChildren, parentComponent, shouldRemoveChildren)
+    } else if (shapeFlag & ShapeFlags.ARRAY_CHILDREN) {
       unmountChildren(
-        vnode.children as VNode[],
+        children as VNode[],
         parentComponent,
         shouldRemoveChildren
       )
@@ -1045,7 +1069,13 @@ export function createRenderer(options: RendererOptions) {
 
     if (doRemove) {
       hostRemove(vnode.el)
-      if (vnode.anchor != null) hostRemove(vnode.anchor)
+      if (anchor != null) hostRemove(anchor)
+    }
+
+    if (props != null && props.vnodeUnmounted != null) {
+      queuePostFlushCb(() => {
+        invokeDirectiveHook(props.vnodeUnmounted, parentComponent, vnode)
+      })
     }
   }
 
index bb799aa82eeab02d785c6e3af5ce66fe6fe9a90c..8e3bd6f2d98e1cc8947546fb7e9cd47e2fee7cdd 100644 (file)
@@ -127,9 +127,6 @@ export function invokeDirectiveHook(
   instance: ComponentInstance | null,
   vnode: VNode
 ) {
-  if (hook == null) {
-    return
-  }
   const args = [vnode]
   if (isArray(hook)) {
     for (let i = 0; i < hook.length; i++) {
index 279a00194f34f310ca3073ea5484d61af62449dd..9061107c7d73aa85e8a2d0240c804e0165f186b3 100644 (file)
@@ -45,21 +45,22 @@ export const enum PatchFlags {
   // exclusive with CLASS, STYLE and PROPS.
   FULL_PROPS = 1 << 4,
 
+  // Indicates an element that only needs non-props patching, e.g. ref or
+  // directives (vnodeXXX hooks). It simply marks the vnode as "need patch",
+  // since every pathced vnode checks for refs and vnodeXXX hooks.
+  NEED_PATCH = 1 << 5,
+
   // Indicates a fragment or element with keyed or partially-keyed v-for
   // children
-  KEYED = 1 << 5,
+  KEYED = 1 << 6,
 
   // Indicates a fragment or element that contains unkeyed v-for children
-  UNKEYED = 1 << 6,
+  UNKEYED = 1 << 7,
 
   // Indicates a component with dynamic slots (e.g. slot that references a v-for
   // iterated value, or dynamic slot names).
   // Components with this flag are always force updated.
-  DYNAMIC_SLOTS = 1 << 7,
-
-  // Indicates an element with ref. This includes static string refs because the
-  // refs object is refreshed on each update and all refs need to set again.
-  REF = 1 << 8
+  DYNAMIC_SLOTS = 1 << 8
 }
 
 // runtime object for public consumption
@@ -68,8 +69,8 @@ export const PublicPatchFlags = {
   CLASS: PatchFlags.CLASS,
   STYLE: PatchFlags.STYLE,
   PROPS: PatchFlags.PROPS,
+  NEED_PATCH: PatchFlags.NEED_PATCH,
   FULL_PROPS: PatchFlags.FULL_PROPS,
   KEYED: PatchFlags.KEYED,
-  UNKEYED: PatchFlags.UNKEYED,
-  REF: PatchFlags.REF
+  UNKEYED: PatchFlags.UNKEYED
 }
index 3a79c1953ca639b8d9fcc279d00cd433fd14a6a3..1fa122f58e4abb60d27527dd4364886668fc920b 100644 (file)
@@ -157,8 +157,8 @@ export function createVNode(
 
   normalizeChildren(vnode, children)
 
-  // presence of a patch flag indicates this node is dynamic
-  // component nodes also should always be tracked, because even if the
+  // presence of a patch flag indicates this node needs patching on updates.
+  // component nodes also should always be patched, because even if the
   // component doesn't need to update, it needs to persist the instance on to
   // the next vnode so that it can be properly unmounted later.
   if (