Description
- Start Date: 2019-04-09
- Target Major Version: 3.x
- Reference Issues: N/A
- Implementation PR: N/A
Summary
-
Re-design custom directive API so that it better aligns with component lifecycle
-
Custom directives usage on components will follow the same rules as discussed in the Attribute Fallthrough Behavior RFC. It will be controlled by the child component via
v-bind="$attrs"
.
Basic example
Before
const MyDirective = {
bind(el, binding, vnode, prevVnode) {},
inserted() {},
update() {},
componentUpdated() {},
unbind() {}
}
After
const MyDirective = {
beforeMount(el, binding, vnode, prevVnode) {},
mounted() {},
beforeUpdate() {},
updated() {},
beforeUnmount() {}, // new
unmounted() {}
}
Motivation
Make custom directive hook names more consistent with the component lifecycle.
Detailed design
Hooks Renaming
Existing hooks are renamed to map better to the component lifecycle, with some timing adjustments. Arguments passed to the hooks remain unchanged.
bind
->beforeMount
inserted
->mounted
beforeUpdate
new, called before the element itself is updatedremoved, useupdate
updated
insteadcomponentUpdated
->updated
beforeUnmount
newunbind
->unmounted
Usage on Components
In 3.0, with fragments support, components can potentially have more than one root nodes. This creates an issue when a custom directive is used on a component with multiple root nodes.
To explain the details of how custom directives will work on components in 3.0, we need to first understand how custom directives are compiled in 3.0. For a directive like this:
<div v-foo="bar"></div>
Will roughly compile into this:
const vFoo = resolveDirective('foo')
return applyDirectives(h('div'), this, [
[vFoo, bar]
])
Where vFoo
will be the directive object written by the user, which contains hooks like mounted
and updated
.
applyDirective
returns a cloned VNode with the user hooks wrapped and injected as vnode lifecycle hooks (see Render Function API Changes for more details):
{
vnodeMounted(vnode, prevVNode) {
// call vFoo.mounted(...)
}
}
As a result, custom directives are fully included as part of a VNode's data. When a custom directive is used on a component, these vnodeXXX
hooks are passed down to the component as extraneous props and end up in this.$attrs
.
This is consistent with the attribute fallthrough behavior discussed in vuejs/rfcs#26. So, the rule for custom directives on a component will be the same as other extraneous attributes: it is up to the child component to decide where and whether to apply it. When the child component uses v-bind="$attrs"
on an inner element, it will apply any custom directives used on it as well.
Drawbacks
N/A
Alternatives
N/A
Adoption strategy
- The renaming should be easy to support in the compat build
- Codemod should also be straightforward
- For directives used on components, the warning on unused
$attrs
as discussed in Attribute Fallthrough Behavior should apply as well.
Unresolved questions
N/A