feat: directives

This commit is contained in:
Evan You 2019-08-31 22:17:46 -04:00
parent 0f0ca4ae7c
commit 9b428c6d83
4 changed files with 60 additions and 32 deletions

View 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) {
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.dynamicChildren,
parentComponent,
shouldRemoveChildren
)
} else if (vnode.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)
})
}
}

View 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++) {

View 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
}

View 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 (