一、数据代理
我们封装的代码中,进行数据访问是myVue.data.name
,而实际Vue中的如果要获取数据肯定不需要添加data
选项即 myVue.name
、myVue.skill
。
此时就可以通过代理,将data数据选项绑定在Vue对象中,修改时同步到data。
function Vue(options){
this.el = options.el // 元素
this.data = options.data // 数据
this.watcher = {} // 属性、数据、元素 的关联
var self = this
Object.keys(this.data).forEach(function(key){ // 遍历所有key
self.proxyKeys(key); // 添加代理(data项的处理)
self.defineProperty(self.data, key, self.data[key])
})
// 解析DOM
this.compile()
}
Vue.prototype = {
proxyKeys(key){
var self = this
Object.defineProperty(this, key, {
enumerable: false,
configurable: true,
get(){
return self.data[key]
},
set(newVal){
self.data[key] = newVal
}
})
},
// defineProperty、compile保持不变
// ...
}
二、createDocumentFragment
对于DOM节点我们采取的是遍历操作,直接操作DOM,影响页面的性能。
createDocumentFragment
创建一个新的空白的文档片段(DocumentFragment
)。
DocumentFragments
是DOM节点。它们不是主DOM树的一部分。通常的用例是创建文档片段,将元素附加到文档片段,然后将文档片段附加到DOM树。在DOM树中,文档片段被其所有的子元素所代替。因为文档片段存在于内存中,并不在DOM树中,因此使用文档片段通常会带来更好的性能。
Vue.prototype = {
// ....
compile(){ // 解析DOM即更新数据
// 获取到对象绑定的元素
var ele = document.querySelector(this.el);
// 所有子元素
var childEls = ele.childNodes;
// 创建fragment
var fragment = document.createDocumentFragment();
// 获取到第一个子元素
var child = ele.firstChild;
while (child) {
// 将Dom元素移入fragment中
// appendChild: 如果被插入的节点已经存在于当前文档的文档树中,则那个节点会首先从原先的位置移除,然后再插入到新的位置
fragment.appendChild(child)
// 再获取第一个(其实就是下一个下一个的操作)
child = ele.firstChild
}
// 遍历所有子元素
[].slice.call(fragment.childNodes).forEach(el => {
var reg = /\{\{(.*)\}\}/;
var text = el.textContent;
if(reg.test(text)){
var key = reg.exec(text)[1];
el.textContent = this.data[key];
this.watcher[key] = function(newVal){
el.textContent = newVal
}
}
})
// 添加
ele.appendChild(fragment)
}
}