v-model双向绑定原理
//Vue.js文件
class Vue { constructor(el, data) { this.el = document.querySelector(el); // this._data = data; this.data = data; this.domPool = {} this.init(); } init() { this.initData(); this.initDom() } initDom() { this.bindDom(this.el) this.bindInput(this.el) console.log(this.domPool) } //初始数据 设置Object.defineProperty() initData() { const _this = this; // this.data = {} // for (let key in this._data) { // Object.defineProperty(this.data, key, { // get() { // console.log('获取数据' + key) // return _this._data[key] // }, // set(newValue) { // console.log('设置数据:', key, newValue) // _this.domPool[key].innerHTML = newValue; // _this._data[key] = newValue; // } // }) // } //特殊,使用proxy this.data = new Proxy(this.data, { set(target, key, value, receiver) { _this.domPool[key].innerHTML = value; return Reflect.set(target, key, value) }, get(target, key, receiver) { return Reflect.get(target, key); } }) } bindDom(el) { const childNodes = el.childNodes; childNodes.forEach(item => { if (item.nodeType === 3) { const _value = item.nodeValue; if (_value.trim().length) { //去空格 let _isValid = /\{\{(.+?)\}\}/.test(_value) if (_isValid) { // console.log(item) const _key = _value.match(/\{\{(.+?)\}\}/)[1].trim(); this.domPool[_key] = item.parentNode; item.parentNode.innerText = this.data[_key] || undefined; // console.log(item.nodeValue) // console.log(_key) } } } item.childNodes && this.bindDom(item) }) } bindInput(el) { const _allInputs = el.querySelectorAll('input'); _allInputs.forEach(input => { const _vModel = input.getAttribute('v-model'); console.log(_vModel) if (_vModel) { input.addEventListener('keyup', this.handleInput.bind(this, _vModel, input), false) } }) } handleInput(key, input) { const _value = input.value; this.data[key] = _value; console.log(this.data) } setData(key, value) { this.data[key] = value; } }
//index.html文件
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>数据的双向绑定01</title> </head> <body> <div id="app"> <div> 姓名: <input type="text" v-model="name" name="name" id="name"> 性别: <input type="text" v-model="gender" name="gender" id="gender"> 邮箱: <input type="email" v-model="email" name="email" id="email"> </div> <div> <p>姓名:<span>{{name}}</span></p> <p>性别:<span>{{gender}}</span></p> <p>邮箱:<span>{{email}}</span></p> </div> <button id="btn">改变按钮</button> </div> </body> <script src="mvvm.js"></script> <script> const app = new Vue('#app', { name: '', gender: '', email: '', }) document.querySelector('#btn').addEventListener('click', function () { app.setData('name', '臭豆腐'); }) </script> </html>