class myVue { constructor(options) { 初始数据(options是实例传的数据) this._init(options) } _init(options) { this.$options = options this.$el = document.querySelector(options.el) this.$data = options.data this.$methods = options.methods this._watchers = {} this._proxy(this, '$data') //this为vue实例 this._observer(this.$data) this._complie(this.$el) } //代理 _proxy(vm, strKey) { Object.keys(vm[strKey]).map((key) => { Object.defineProperty(vm, key, { enumerable: true, configurable: true, get() { console.log(vm[strKey][key]) return vm[strKey][key] }, set(val) { console.log(vm[strKey][key], val) vm[strKey][key] = val } }) }) } //劫持 _observer(obj, objKey) { for (const key in obj) { let value if (obj.hasOwnProperty(key)) { let watchers if(objKey) { watchers = this._watchers[objKey][key] = [] } else { watchers = this._watchers[key] = [] } value = obj[key] if(typeof value === 'object') { this._observer(value, key); } Object.defineProperty(obj, key, { enumerable: true, configurable: true, get() { console.log(`获取${value}`) return value }, set(newVal) { console.log(`更新${value}`) if (value !== newVal) { value = newVal; //通知watcher watchers.forEach(function (item) { item.update(); }) } } }) } } } //解析指令 _complie(root) { let nodes = root.children for(let i = 0, l = nodes.length; i < l; i++) { let childNodes = nodes[i] if(childNodes.length) { this._complie(childNodes) } if(childNodes.hasAttribute('v-click')) { let attrVal = childNodes.getAttribute('v-click') childNodes.onclick = getExpArr(this.$methods, attrVal).bind(this) } if(childNodes.hasAttribute('v-model') && (childNodes.tagName == 'INPUT' || childNodes.tagName == 'TEXTAREA')) { let attrVal = childNodes.getAttribute('v-model') childNodes.addEventListener('input',(() => { getExpArr(this._watchers, attrVal).push(new Watcher( 'input', childNodes, this, attrVal, 'value' )) return () => { getExpArr(this, attrVal) = childNodes.value } })()) } if(childNodes.hasAttribute('v-text')) { let attrVal = childNodes.getAttribute('v-text') getExpArr(this._watchers, attrVal).push(new Watcher( 'text', childNodes, this, attrVal, 'innerHTML' )) } } } } //将obj['a.b']变为obj['a']['b'] function getExpArr(obj, attrVal) { return attrVal.split('.').reduce((pre, cur) => { return pre[cur] }, obj) } class Watcher { constructor(name, el, vm, expression, attr) { this.name = name; //指令名称,例如文本节点,该值设为"text" this.el = el; //指令对应的DOM元素 this.vm = vm; //指令所属myVue实例 this.expression = expression; //指令对应的值,本例如"number" this.attr = attr; //绑定的属性值,本例为"innerHTML" this.update() } //更新 update() { let val = getExpArr(this.vm, this.expression) this.el[this.attr] = this.name === 'text' ? JSON.stringify(val) : val } }
vue 双向数据绑定
最新推荐文章于 2024-10-14 09:18:13 发布