Vue 数据绑定之数据劫持
vue 的数据绑定 = 数据劫持 + 发布者-订阅者模式
数据劫持会使用到一个 Object.defineProperty()
来劫持 data 中的各个属性的 getter
、setter
如果不了解 Object.defineProperty()
请查看 https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty
let zhaosir = new Zhaosir({
el: '#app',
data: {
a: {
a: '是a'
},
b: "是b",
msg: 'hello world',
}
})
function Zhaosir(options = {}){ // 生成的一个实例对象
this.$options = options; // 将传递过来的对象绑定到this.$options上
let data = this._data = this.$options.data;
observe(data);
for (let key in data) {
Object.defineProperty(this,key,{
enumerable: true,
configurable: true,
get(){
return this._data[key];
},
set(newVal){
this._data[key] = newVal;
}
})
}
new Compile(this.$options.el,this);
}
function Observe(data){ // 生成一个getter、setter 函数
for (let key in data) {
let val = data[key];
observe(val);
Object.defineProperty(data,key,{
enumerable: true,
configurable: true,
get(){
return val;
},
set(newVal) {
if (val === newVal) return;
val = newVal;
observe(val);
}
});
}
}
function Compile(el,vm) { // 将数据渲染到页面上
vm.$el = document.querySelector(el);
let fragment = document.createDocumentFragment();
while (child = vm.$el.firstChild) {
fragment.appendChild(child);
}
replace(fragment)
function replace(fragment){
Array.from(fragment.childNodes).forEach(function(node){
let text = node.textContent;
let reg = /\{\{(.*)\}\}/;
if (node.nodeType === 3 && reg.test(text)){
let arr = RegExp.$1.split('.');
let val = vm;
arr.forEach(function(k){
val = val[k]
})
node.textContent = text.replace(/\{\{(.*)\}\}/,val);
}
if (node.childNodes) {
replace(node);
}
})
}
vm.$el.appendChild(fragment);
}
function observe (data) { // 实现数据劫持
if (typeof data !== 'object') return;
return new Observe(data);
}
参考资料:
-
JavaScript 高级程序编程(红宝书)
-
MDN 文档