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 if (isReservedProp(key)) continue
hostPatchProp(el, key, props[key], null, isSVG) 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) { if (shapeFlag & ShapeFlags.TEXT_CHILDREN) {
hostSetElementText(el, vnode.children as string) hostSetElementText(el, vnode.children as string)
@ -263,8 +265,10 @@ export function createRenderer(options: RendererOptions) {
) )
} }
hostInsert(el, container, anchor) hostInsert(el, container, anchor)
if (props != null) { if (props != null && props.vnodeMounted != null) {
invokeDirectiveHook(props.vnodeMounted, parentComponent, vnode) queuePostFlushCb(() => {
invokeDirectiveHook(props.vnodeMounted, parentComponent, vnode)
})
} }
} }
@ -294,6 +298,10 @@ export function createRenderer(options: RendererOptions) {
const oldProps = (n1 && n1.props) || EMPTY_OBJ const oldProps = (n1 && n1.props) || EMPTY_OBJ
const newProps = n2.props || EMPTY_OBJ const newProps = n2.props || EMPTY_OBJ
if (newProps.vnodeBeforeUpdate != null) {
invokeDirectiveHook(newProps.vnodeBeforeUpdate, parentComponent, n2)
}
if (patchFlag) { if (patchFlag) {
// the presence of a patchFlag means this element's render code was // the presence of a patchFlag means this element's render code was
// generated by the compiler and can take the fast path. // generated by the compiler and can take the fast path.
@ -379,6 +387,12 @@ export function createRenderer(options: RendererOptions) {
// full diff // full diff
patchChildren(n1, n2, el, null, parentComponent, isSVG) patchChildren(n1, n2, el, null, parentComponent, isSVG)
} }
if (newProps.vnodeUpdated != null) {
queuePostFlushCb(() => {
invokeDirectiveHook(newProps.vnodeUpdated, parentComponent, n2)
})
}
} }
function patchProps( function patchProps(
@ -1017,27 +1031,37 @@ export function createRenderer(options: RendererOptions) {
parentComponent: ComponentInstance | null, parentComponent: ComponentInstance | null,
doRemove?: boolean doRemove?: boolean
) { ) {
const {
props,
ref,
type,
component,
children,
dynamicChildren,
shapeFlag,
anchor
} = vnode
// unset ref // unset ref
if (vnode.ref !== null && parentComponent !== null) { if (ref !== null && parentComponent !== null) {
setRef(vnode.ref, null, parentComponent, null) setRef(ref, null, parentComponent, null)
} }
const instance = vnode.component if (component != null) {
if (instance != null) { unmountComponent(component, doRemove)
unmountComponent(instance, doRemove)
return return
} }
const shouldRemoveChildren = vnode.type === Fragment && doRemove if (props != null && props.vnodeBeforeUnmount != null) {
if (vnode.dynamicChildren != 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( unmountChildren(
vnode.dynamicChildren, children as VNode[],
parentComponent,
shouldRemoveChildren
)
} else if (vnode.shapeFlag & ShapeFlags.ARRAY_CHILDREN) {
unmountChildren(
vnode.children as VNode[],
parentComponent, parentComponent,
shouldRemoveChildren shouldRemoveChildren
) )
@ -1045,7 +1069,13 @@ export function createRenderer(options: RendererOptions) {
if (doRemove) { if (doRemove) {
hostRemove(vnode.el) 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, instance: ComponentInstance | null,
vnode: VNode vnode: VNode
) { ) {
if (hook == null) {
return
}
const args = [vnode] const args = [vnode]
if (isArray(hook)) { if (isArray(hook)) {
for (let i = 0; i < hook.length; i++) { for (let i = 0; i < hook.length; i++) {

View File

@ -45,21 +45,22 @@ export const enum PatchFlags {
// exclusive with CLASS, STYLE and PROPS. // exclusive with CLASS, STYLE and PROPS.
FULL_PROPS = 1 << 4, 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 // Indicates a fragment or element with keyed or partially-keyed v-for
// children // children
KEYED = 1 << 5, KEYED = 1 << 6,
// Indicates a fragment or element that contains unkeyed v-for children // 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 // Indicates a component with dynamic slots (e.g. slot that references a v-for
// iterated value, or dynamic slot names). // iterated value, or dynamic slot names).
// Components with this flag are always force updated. // Components with this flag are always force updated.
DYNAMIC_SLOTS = 1 << 7, DYNAMIC_SLOTS = 1 << 8
// 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
} }
// runtime object for public consumption // runtime object for public consumption
@ -68,8 +69,8 @@ export const PublicPatchFlags = {
CLASS: PatchFlags.CLASS, CLASS: PatchFlags.CLASS,
STYLE: PatchFlags.STYLE, STYLE: PatchFlags.STYLE,
PROPS: PatchFlags.PROPS, PROPS: PatchFlags.PROPS,
NEED_PATCH: PatchFlags.NEED_PATCH,
FULL_PROPS: PatchFlags.FULL_PROPS, FULL_PROPS: PatchFlags.FULL_PROPS,
KEYED: PatchFlags.KEYED, KEYED: PatchFlags.KEYED,
UNKEYED: PatchFlags.UNKEYED, UNKEYED: PatchFlags.UNKEYED
REF: PatchFlags.REF
} }

View File

@ -157,8 +157,8 @@ export function createVNode(
normalizeChildren(vnode, children) normalizeChildren(vnode, children)
// presence of a patch flag indicates this node is dynamic // presence of a patch flag indicates this node needs patching on updates.
// component nodes also should always be tracked, because even if the // 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 // 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. // the next vnode so that it can be properly unmounted later.
if ( if (