vue.js动态数据绑定学习笔记

2020-06-13 10:42:10易采站长站整理


function Hue(options) {
this.$options = options || {};
let data = this._data = this.$options.data,
self = this;

Object.keys(data).forEach(function(key) {
self._proxyData(key);
});

observe(data);

self.$compile = new Compile(self, options.el || document.body);
}

// 为 data 做了一个代理,
// 访问 vm.xxx 会触发 vm._data[xxx] 的getter,取得 vm._data[xxx] 的值,
// 为 vm.xxx 赋值则会触发 vm._data[xxx] 的setter
Hue.prototype._proxyData = function(key) {
let self = this;
Object.defineProperty(self, key, {
configurable: false,
enumerable: true,
get: function proxyGetter() {
return self._data[key];
},
set: function proxySetter(newVal) {
self._data[key] = newVal;
}
});
};

再往下看,最后一步 new 了一个 Compile,下面我们就来讲讲 Compile。

Compile

new Compile(self, options.el || document.body) 这一行代码中,第一个参数是当前 Hue 实例,第二个参数是绑定的元素,在上面的示例中为class为 .test 的div。

关于 Compile,这里只实现最简单的 textContent 的绑定。而 Compile 的代码没什么难点,很轻易就能读懂,所做的就是解析 DOM,并添加 Watcher 订阅。关于 DOM 的解析,先将根节点 el 转换成文档碎片 fragment 进行解析编译操作,解析完成后,再将 fragment 添加回原来的真实 DOM 节点中。来看看这部分的代码:


function Compile(vm, el) {
this.$vm = vm;
this.$el = this.isElementNode(el)
? el
: document.querySelector(el);

if (this.$el) {
this.$fragment = this.node2Fragment(this.$el);
this.init();
this.$el.appendChild(this.$fragment);
}
}

Compile.prototype.node2Fragment = function(el) {
let fragment = document.createDocumentFragment(),
child;

// 也许有同学不太理解这一步,不妨动手写个小例子观察一下他的行为
while (child = el.firstChild) {
fragment.appendChild(child);
}

return fragment;
};

Compile.prototype.init = function() {
// 解析 fragment
this.compileElement(this.$fragment);
};

以上面示例为例,此时若打印出 fragment,可观察到其包含两个p元素:


<p>{{user.name}}</p>
<p>{{user.age}}</p>

下一步就是解析 fragment,直接看代码及注释吧:


Compile.prototype.compileElement = function(el) {
let childNodes = Array.from(el.childNodes),
self = this;

childNodes.forEach(function(node) {
let text = node.textContent,
reg = /{{(.*)}}/;

// 若为 textNode 元素,且匹配 reg 正则