vue指令实现源码
Vue 指令实现源码解析
Vue 指令的核心实现位于 Vue 的源码中,主要涉及指令的注册、解析、绑定和更新逻辑。以下是关键实现部分的解析:
指令注册与初始化
Vue 指令通过 Vue.directive 方法注册,注册后的指令会存储在 Vue.options.directives 中。初始化时,Vue 会遍历模板中的指令,生成对应的指令对象。
// 指令注册示例
Vue.directive('my-directive', {
bind(el, binding, vnode) {},
inserted(el, binding, vnode) {},
update(el, binding, vnode, oldVnode) {},
componentUpdated(el, binding, vnode, oldVnode) {},
unbind(el, binding, vnode) {}
});
指令解析与绑定
在模板编译阶段,Vue 解析模板中的指令属性(如 v-model、v-if),生成 AST(抽象语法树)。随后,在 patch 过程中,指令会被实例化并绑定到 DOM 元素上。
// 指令解析逻辑(简化版)
function processDirectives(el, dirs, vm) {
dirs.forEach(dir => {
const def = vm.$options.directives[dir.name];
if (def) {
// 创建指令实例并调用 bind 钩子
const directive = {
...def,
def,
name: dir.name,
value: dir.value
};
callHook(directive, 'bind', el, vm);
}
});
}
指令更新逻辑
当响应式数据变化时,Vue 会触发指令的 update 钩子。对于需要 DOM 操作的指令(如 v-show),会在 componentUpdated 钩子中处理。
// 指令更新逻辑(简化版)
function updateDirectives(oldVnode, vnode) {
const oldDirs = oldVnode.data.directives;
const newDirs = vnode.data.directives;
// 对比新旧指令,触发 update 或 componentUpdated
for (const dir of newDirs) {
const oldDir = oldDirs.find(d => d.name === dir.name);
if (oldDir) {
dir.oldValue = oldDir.value;
callHook(dir, 'update', vnode.elm, vnode.context);
}
}
}
内置指令示例:v-show
v-show 的实现通过控制元素的 display 样式实现显隐:
Vue.directive('show', {
bind(el, { value }, vnode) {
el._originalDisplay = el.style.display;
updateDisplay(el, value);
},
update(el, { value, oldValue }) {
if (value !== oldValue) {
updateDisplay(el, value);
}
},
unbind(el) {
el.style.display = el._originalDisplay;
}
});
function updateDisplay(el, value) {
el.style.display = value ? el._originalDisplay : 'none';
}
自定义指令实现要点
- 钩子函数:自定义指令需实现
bind、update等钩子,用于初始化和响应式更新。 - 指令参数:通过
binding对象访问指令的值(value)、参数(arg)、修饰符(modifiers)。 - 清理逻辑:在
unbind钩子中移除事件监听或定时器,避免内存泄漏。
Vue.directive('focus', {
inserted(el) {
el.focus();
}
});
源码位置参考
- 指令注册:
src/core/global-api/index.js中的Vue.directive。 - 指令处理:
src/core/vdom/modules/directives.js。 - 内置指令:
src/platforms/web/runtime/directives。







