赞
踩
监听Vue实例中的data选项,我们以下用一个普通的js对象模拟data,用Object.defineProperty进行定义属性值的getter和setter方法。当data选择项中的key进行获取和修改时,Vue内部会调用相应的方法。
主要考虑以下两点:
响应式原理实现代码: class Vue{ constructor(options){ //1.保存数据 this.$options = options; this.$data = options.data; this.$el = options.el; //2.将data添加到响应式系统中 new Observer(this.$data) //3.处理el new Complier(this.$el, this) //4.代理this.$data的数据 Object.keys(this.$data).forEach(key=>{ this._proxy(key) }) } _proxy(key){ Object.defineProperty(this, key, { configurable: true, enumerable: true, set(newValue){ this.$data[key] = newValue }, get(){ return this.$data[key] } }) } } //将data中的属性加入到相应模式中 class Observer{ constructor(data){ this.data = data Object.keys(data).forEach(key=>{ this.defineReactive(this.data, key, data[key]) }) } defineReactive(data, key, val){ //一个属性(key)对应一个发布者对象 const dep = new Dep() Object.defineProperty(data, key, { enumerable: true, configurable: true, //将订阅者加入到subs数组中 get(){ if(Dep.target){ dep.addSub(Dep.target) } return val }, //数据修改时,通知订阅者 set(newValue){ if(newValue === val) return val = newValue dep.notify() } }) } } //定义发布者:添加、通知订阅者 class Dep{ constructor(){ this.subs = [] } // addSub(sub){ this.subs.push(sub) } //订阅者更新时,调用watcher中的update()修改视图中的节点值 notify(){ this.subs.forEach(sub=>{ sub.update() }) } } //订阅者 class Watcher{ constructor(node, name, vm){ this.node = node; this.name = name; this.vm = vm; Dep.target = this; this.update() Dep.target = null } update(){ this.node.nodeValue = this.vm[this.name] } } //template编译 const reg = /\{\{(.+)\}\}/ class Complier{ constructor(el, vm){ this.el = document.querySelector(el) this.vm = vm this.frag = this._createFragment() this.el.appendChild(this.frag) } _createFragment(){ const frag = document.createDocumentFragment() let child; while(child = this.el.firstChild){ this._compile(child) frag.appendChild(child) } return frag } _compile(node){ if(node.nodeType === 1){ const attrs = node.attributes if(attrs.hasOwnProperty('v-model')){ const name = attrs['v-model'].nodeValue node.addEventListener('input',e=>{ this.vm[name] = e.target.value }) } } //节点编译时,name为订阅者名字,创建对应的watcher实例 if(node.nodeType === 3){ if(reg.test(node.nodeValue)){ const name = RegExp.$1.trim() new Watcher(node, name, this.vm) } } } }
如果感觉文章对你有帮助,别忘了点个赞哦!!!!!!!!!
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。