深入理解 Vue 的指令系统

Vue 作为一款 MVVM 框架,其双向绑定实际上是:JS 数据变化=》DOM 变化,这快的变化大家都知道了,主要是通过劫持对象属性的Object.defindProprotys(Vue3 中改为 Proxy)。 那从 DOM 变化=》JS 数据变化的过程是怎么样的呢?这就是今天研究的内容————Vue 的指令系统

指令是如何工作的?

比如常见的 v-modal、v-bind、v-on、v-if、v-for 等。不同的指令有不同的效果,具体可以去官网查看Vue 指令open in new window

Vue2.x 的双向绑定原理及实现中可以知道,其实是获取每个元素的属性,然后找出带有v-标示的指令进行解析,将对应的属性或方法设置上去。

对应到代码,其实也很简单。

<div id="app">
    <h1 v-color="red">Hello World</h1>
    <h1 v-color="blue">Hello World</h1>
</div>

<script>
    let app = document.getElementById('app');
    let child = app.children;
    [...child].forEach(el => {
        el.style.color = el.attributes['v-color'].value
    });
<script>
1
2
3
4
5
6
7
8
9
10
11
12

自定义指令

Vue 除了提供内置指令外,为了更大的扩展性,还提供了自定义指令的功能,让使用这根据实际需要开发自己需要的指令。

当然也分全局指令和局部指令,但是他们所需传递的参数是一样的。

let Opt = {
  // 指令被绑定到元素时调用
  bind: function (el, binding, vnode) {},
  // 元素插入父节点时调用
  inserted: function (el, binding, vnode) {},
  // VNode 更新时(前)调用
  update: function (el, binding, vnode) {},
  // VNode 更新后调用
  componentUpdated: function (el, binding, vnode) {},
  // 指令和元素解绑时调用
  unbind: function (el, binding, vnode) {},
};
1
2
3
4
5
6
7
8
9
10
11
12

参数

  • el:指令所绑定的元素
  • binding
    • name:指令名,不包括 v- 前缀。
    • value:指令的绑定值,例如:v-my-directive="1 + 1" 中,绑定值为 2
    • oldValue:指令绑定的前一个值,仅在 updatecomponentUpdated 钩子中可用。无论值是否改变都可用。
    • expression:字符串形式的指令表达式。例如 v-my-directive="1 + 1" 中,表达式为 "1 + 1"
    • arg:传给指令的参数,可选。例如 v-my-directive:foo 中,参数为 "foo"
    • modifiers:一个包含修饰符的对象。例如:v-my-directive.foo.bar 中,修饰符对象为 { foo: true, bar: true }
  • Vnode:Vue 的虚拟节点

自定义全局指令

定义全局指令的话,范围是全局可用的。

比如最官方的示例:

// 注册一个全局自定义指令 `v-focus`
Vue.directive("focus", {
  // 当被绑定的元素插入到 DOM 中时……
  inserted: function (el) {
    // 聚焦元素
    el.focus();
  },
});
1
2
3
4
5
6
7
8

自定义局部指令

实现一个v-blink指令,使用在元素上就会有一闪一闪的效果.

HTML:

<h1 v-blink="700">Hello Wrold</h1>
1

JavaScript:

    directives: {
        blink: {
        bind(el, binding, vnode) {
            setInterval(()=>{
                el.style.visibility = el.style.visibility === 'inherit' ? 'hidden' : 'inherit'
            }, binding.expression)
        }
    }
1
2
3
4
5
6
7
8

参考

上次更新: 5/12/2022, 11:57:22 AM
Contributors: 九旬