v-model
很多同学在理解 Vue 的时候都把 Vue 的数据响应原理理解为双向绑定,但实际上这是不准确的,我们之前提到的数据响应,都是通过数据的改变去驱动 DOM 视图的变化,而双向绑定除了数据驱动 DOM 外, DOM 的变化反过来影响数据,是一个双向关系,在 Vue 中,我们可以通过 来实现双向绑定。
即可以作用在普通表单元素上,又可以作用在组件上,它其实是一个语法糖,接下来我们就来分析 的实现原理。
表单元素
为了更加直观,我们还是结合示例来分析:
这是一个非常简单 demo,我们在 元素上设置了 属性,绑定了 ,当我们在 上输入了内容, 也会同步变化。接下来我们就来分析 Vue 是如何实现这一效果的,其实非常简单。
也是先从编译阶段分析,首先是 阶段, 被当做普通的指令解析到 中,然后在 阶段,执行 的时候,会执行 ,它的定义在 中:
方法就是遍历 ,然后获取每一个指令对应的方法 ,这个指令方法实际上是在实例化 的时候通过 传入的,这个 就是编译相关的配置,它在不同的平台下配置不同,在 环境下的定义在 下:
定义在 中:
那么对于 而言,对应的 函数是在 中定义的 函数:
也就是说我们执行 就是在执行 函数,它会根据 AST 元素节点的不同情况去执行不同的逻辑,对于我们这个 case 而言,它会命中 的逻辑,稍后我们也会介绍组件的处理,其它分支同学们可以自行去看。我们来看一下 的实现:
函数先处理了 ,它的不同主要影响的是 和 的值,对于我们的例子, 为 , 为 。然后去执行 去生成代码,它的定义在 中:
该方法首先对 对应的 做了解析,它处理了非常多的情况,对我们的例子, 就是 ,所以返回的 为 ,然后我们就得到 ,也就是 。然后我们又命中了 为 true 的逻辑,所以最终的 为 。 生成完后,又执行了 2 句非常关键的代码:
这实际上就是 实现 的精髓,通过修改 AST 元素,给 添加一个 ,相当于我们在 上动态绑定了 ,又给 添加了事件处理,相当于在 上绑定了 事件,其实转换成模板如下:
其实就是动态绑定了 的 指向了 变量,并且在触发 事件的时候去动态把 设置为目标值,这样实际上就完成了数据双向绑定了,所以说 实际上就是语法糖。
再回到 ,它接下来的逻辑就是根据指令生成一些 的代码:
对我们的例子而言,最终生成的 代码如下:
关于事件的处理我们之前的章节已经分析过了,所以对于 的 而言,完全就是语法糖,并且对于其它表单元素套路都是一样,区别在于生成的事件代码会略有不同。 除了作用在表单元素上,新版的 Vue 还把这一语法糖用在了组件上,接下来我们来分析它的实现。
组件
为了更加直观,我们也是通过一个例子分析:
可以看到,父组件引用 子组件的地方使用了 关联了数据 ;而子组件定义了一个 的 ,并且在 事件的回调函数中,通过 派发了一个事件,为了让 生效,这两点是必须的。接着我们从源码角度分析实现原理,还是从编译阶段说起,对于父组件而言,在编译阶段会解析 指令,依然会执行 函数中的 函数,接着执行 中定义的 函数,并命中如下逻辑:
函数定义在 中:
的逻辑很简单,对我们的例子而言,生成的 的值为:
那么在 之后, 函数中有一段逻辑如下:
那么父组件最终生成的 代码如下:
然后在创建子组件 阶段,会执行 函数,它的定义在 中:
其中会对 的情况做处理,执行 方法:
逻辑很简单,给 添加 ,并且给 添加 ,对我们的例子而言,扩展结果如下:
其实就相当于我们在这样编写父组件:
子组件传递的 绑定到当前父组件的 ,同时监听自定义 事件,当子组件派发 事件的时候,父组件会在事件回调函数中修改 的值,同时 也会发生变化,子组件的 值被更新。这就是典型的 Vue 的父子组件通讯模式,父组件通过 把数据传递到子组件,子组件修改了数据后把改变通过 事件的方式通知父组件,所以说组件上的 也是一种语法糖。另外我们注意到组件 的实现,子组件的 以及派发的 事件名是可配的,可以看到 中对这部分的处理:
也就是说可以在定义子组件的时候通过 选项配置子组件接收的 名以及派发的事件名,举个例子:
子组件修改了接收的 名以及派发的事件名,然而这一切父组件作为调用方是不用关心的,这样做的好处是我们可以把 这个 作为其它的用途。
总结
那么至此, 的实现就分析完了,我们了解到它是 Vue 双向绑定的真正实现,但本质上就是一种语法糖,它即可以支持原生表单元素,也可以支持自定义组件。在组件的实现中,我们是可以配置子组件接收的 名称,以及派发的事件名称。
领取专属 10元无门槛券
私享最新 技术干货