对于vue.js
的动态数据绑定,经过反复地看源码和博客讲解,总算能够理解它的实现了,心累~ 分享一下学习成果,同时也算是做个记录。完整代码GitHub地址:https://github.com/hanrenguang/Dynamic-data-binding。也可以到仓库的 README
阅读本文,容我厚脸皮地求 star
,求 follow
。
整体思路
不知道有没有同学和我一样,看着vue
的源码却不知从何开始,真叫人头大。硬生生地看了observer
, watcher
, compile
这几部分的源码,只觉得一脸懵逼。最终,从这里得到启发,作者写得很好,值得一读。
关于动态数据绑定呢,需要搞定的是 Dep
, Observer
, Watcher
, Compile
这几个类,他们之间有着各种联系,想要搞懂源码,就得先了解他们之间的联系。下面来理一理:
Observer
所做的就是劫持监听所有属性,当有变动时通知Dep
Watcher
向Dep
添加订阅,同时,属性有变化时,Observer
通知Dep
,Dep
则通知Watcher
Watcher
得到通知后,调用回调函数更新视图Compile
则是解析所绑定元素的DOM
结构,对所有需要绑定的属性添加Watcher
订阅
由此可以看出,当属性发生变化时,是由Observer
-> Dep
-> Watcher
-> update view
,Compile
在最开始解析 DOM
并添加 Watcher
订阅后就功成身退了。
从程序执行的顺序来看的话,即 new Vue({})
之后,应该是这样的:先通过 Observer
劫持所有属性,然后 Compile
解析 DOM
结构,并添加 Watcher
订阅,再之后就是属性变化 -> Observer
-> Dep
-> Watcher
-> update view
,接下来就说说具体的实现。
从new一个实例开始谈起
网上的很多源码解读都是从 Observer
开始的,而我会从 new
一个MVVM实例开始,按照程序执行顺序去解释或许更容易理解。先来看一个简单的例子:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>test</title>
</head>
<body>
<div class="test">
<p>{
{user.name}}</p>
<p>{
{user.age}}</p>
</div>
<script type="text/javascript" src="hue.js"></script>
<script type="text/javascript">
let vm = new Hue({
el: '.test',
data: {
user: {
name: 'Jack',
age: '18'
}
}
});
</script>
</body>
</html>
接下来都将以其为例来分析。下面来看一个简略的 MVVM
的实现,在此将其命名为 hue
。为了方便起见,为 data
属性设置了一个代理,通过 vm._data
来访问 data
的属性显得麻烦且冗余,通过代理,可以很好地解决这个问题,在注释中也有说明。添加完属性代理后,调用了一个 observe
函数,这一步做的就是 Observer
的属性劫持了,这一步具体怎么实现,暂时先不展开。先记住他为 data
的属性添加了 getter
和 setter
。
function Hue(options) {
this.$options = options || {};
let data = this._data = this.$options.data,
self = this;
Object.keys(data).forEach(function(key) {
self._proxyData(ke