vue mvvm原理与简单实现 -- 上篇
Object.defineProperty介绍-- let obj = {}; Object.defineProperty(obj,'school',{ configurable : true, // 属性能否被删除 //writable : true, // 属性能否被修改 enumerable : true, // 属性能否枚举 //value : 'zfpx', // 设置属性值 set : function(value){ console.log(value); // obj.school赋值时, 调用set() 方法 }, get : function(){ return 'zfpx'; // 获取 obj.school 的值时,调用 get() 方法 } })
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Document</title> </head> <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script> <body> <div id="app"> <p>{{a.a}}</p> <div>{{b}} <div>{{b}}</div> </div> </div> </body> <!-- mvvm 双向数据绑定 vue 数据劫持+发布订阅模式 不兼容低版本 Object.defineProperty --> <script> (function(window,document){ function ZF(options = {}){ this.$options = options; // 将所有的属性挂载在 $options 上 let data = this._data = this.$options.data; this.observe(data); for(let key in data){ // 把data属性通过Object.defineProperty的方式定义属性 // 数据代理 // this代理了this._data Object.defineProperty(this,key,{ enumerable : true, // 可枚举 get: function(){ return this._data[key]; }, set: function(newVal){ // 更改值的时候 this._data[key] = newVal; } }); } this.Compile(options.el,this); } // 编译 ZF.prototype.Compile = function(el,vm){ vm.$el = document.querySelector(el); let fragment = document.createDocumentFragment(); while(child = vm.$el.firstChild){ // 将app中的内容 移入内存中 fragment.appendChild(child); } // 循环每一层 Array.from(fragment.childNodes).forEach(function(node){ let text = node.textContent; let reg = /\{\{(.*)\}\}/; if( reg.test(text)){ let arr = RegExp.$1.split('.'); let val = vm; console.log(node.childNodes) console.log(arr) arr.forEach(function(k){ val = val[k]; }) // 替换 node.textContent = text.replace(/\{\{(.*)\}\}/,val) } //node.textContent.textContent(12) }) vm.$el.appendChild(fragment); } // 观察对象给对象增加ObjectDefineProperty; ZF.prototype.observe = function(data){ //console.log(data) return new Observe(data); } function Observe(data){ for(let key in data){ // 把data属性通过Object.defineProperty的方式定义属性 let val = data[key]; // 递归 if(typeof val === 'object'){ Observe(val); } Object.defineProperty(data,key,{ enumerable : true, // 可枚举 get: function(){ return val; }, // 数据劫持 set: function(newVal){ // 更改值的时候 if(newVal === val){ return; } if(typeof newVal === 'object'){ Observe(newVal); } val = newVal; // } }); } } window.ZF = ZF; })(window,document); let zf = new ZF({ el : "#app", data : {a:{a:'是a'},b:'是b'}, }) </script> </html>