这是我参与更文挑战的第16天,活动详情查看: 更文挑战。
前言
指令(directive)是 Vue.js 提供的带有 v- 前缀的特殊特性。指令属性的值预期是单个 JavaScript 表达式。指令的职责是,当表达式的值改变时,将其产生的连带影响响应式地作用于 DOM。
指令原理概述
在模板解析阶段,我们在将指令解析到 AST,然后使用 AST 生成代码字符串的过程中实现某些内置指令的功能,最后在虚拟DOM渲染的过程中触发自定义指令的钩子函数使指令生效。
- 在模板解析阶段,会将节点上的指令解析出来并添加到 AST 的
directives
属性中。 - 随后
directives
数据会传递到VNode中,接着就可以通过vnode.data.directives
获取一个节点所绑定的指令 - 当虚拟DOM进行修补时,会根据节点的对比结果触发一些钩子函数。更新指令的程序会监听
create
、update
和destroy
钩子函数,并在这三个钩子函数触发时对 VNode 和 oldVNode 进行对比,最终根据对比结果触发指令的钩子函数。
v-if 指令的原理概述
<li v-if="has">if></li>
<li v-else>else</li>
在模板编译的代码生成阶段会生成这样的代码字符串:
(has)
? _c('li', [_v('if')])
: _c('li', [_v('else')])
v-for 指令的原理概述
<li v-for="(item, index) in list">v-for {{index}}</li>
在模板编译阶段会生成这样的代码字符串:
_l(list, function(item, index){
return _c('li', [
_v('v-for ' + _s(index))
])
})
_l
是函数 renderList
的别名。当执行这段代码字符串时,_l函数会循环变量 list 并依次调用第二个参数所传递的函数。同时,会传递两个参数:item 和 index。此外,当 _c
函数被调用时,会执行 _v
函数创建一个文本节点。
v-on 指令
v-on
指令的作用是绑定事件监听器,事件类型由参数指定。它用在普通元素上时,可以监听原生DOM事件;用在自定义元素组件上时,可以监听子组件触发的自定义事件。
从模板解析到生成VNode,最终事件会被保存在VNode中,然后可以通过 vnode.data.on
得到一个节点注册的所有事件。
<buttton v-on:click="doSomething"></button>
在最终生成的VNode中,我们可以通过vnode.data.on读出下面的事件对象:
{
click: function(){}
}
件绑定相关的处理逻辑分别设置了 create
与 update
钩子函数,也就是说在修补的过程中,每当一个DOM元素被创建或更新时,都会触发事件绑定相关的处理逻辑。事件绑定相关的处理逻辑是一个叫 updateDOMListeners
的函数,而 create 与 update 钩子函数执行的都是这个函数。其代码如下:
let target
function updateDOMListeners(oldVnode, vnode) {
if (isUndef(oldVnode.data.on) && isUndef(vnode.data.on)){
return;
}
const on = vnode.data.on || {};
const oldOn = oldVnode.data.on || {};
target = vnode.elm
normalizeEvents(on)
updateListeners(on, oldOn, add, remove, vnode.context)
target = undefined
}
未完待续...