vue.js 雙向數據綁定的實現javascript
1.首先定義構造函數html
var Vue = function (params) { this.el = document.getElementById(params.el) this.data = params.data this.init() } Vue.prototype = { init: function () { this.updateView() this.bindData() this.bindModel() } }
2.在初始化方法中先定義一個視圖的更新方法。這樣一個簡單的單向綁定就已經實現了。vue
Vue.prototype.updateView = function () { // v-text 視圖更新 var doms = this.el.querySelectorAll('[v-text]') for (var i = 0; i < doms.length; i++) { var bindName = doms[i].getAttribute('v-text') doms[i].innerHTML = this.data[bindName] } // v-model 視圖更新 var modelDoms = this.el.querySelectorAll('[v-model]') for (var i = 0; i < modelDoms.length; i++) { var modelBindName = modelDoms[i].getAttribute('v-model') modelDoms[i].value = this.data[modelBindName] || '' } }
3.而後要創建數據層到視圖層的單向聯繫。java
Vue.prototype.bindData = function () { var data = this.data for (var key in data) { this.defineObject(data, key, data[key]) } } Vue.prototype.defineObject = function (obj, prop, value) { var value = value || '' var _that = this Object.defineProperty(obj, prop, { get: function () { return value }, set: function (newVal_) { value = newVal_ _that.updateView() } }) }
4.創建視圖層到數據層的聯繫。也就是v-model的實現。
dom
// model數據綁定 Vue.prototype.bindModel = function () { var data = this.data var _that = this var doms = this.el.querySelectorAll('[v-model]') for (var i = 0; i < doms.length; i++) { var bindName = doms[i].getAttribute('v-model') doms[i].value = data[bindName] || '' if (document.addEventListener) { doms[i].addEventListener('keyup', function (event) { e = event || window.event data[bindName] = e.target.value }, false) } else { doms[i].attachEvent('onkeyup', function (event) { e = event || window.event data[bindName] = e.target.value }, false) } } }
至此一個簡單的雙向數據綁定就已經實現了。函數
詳細demo。測試
<!DOCTYPE html> <html> <head> <title></title> </head> <body> <div id="vueTest"> <input type="text" name="cc" v-model="test1"> <div v-text="test1"></div> <div v-text="test1"></div> <div v-text="test2"></div> </div> </body> <script type="text/javascript"> var Vue = function (params) { this.el = document.getElementById(params.el) this.data = params.data this.init() } Vue.prototype = { init: function () { this.updateView() this.bindData() this.bindModel() }, // 更新視圖 updateView: function () { // v-text 視圖更新 var doms = this.el.querySelectorAll('[v-text]') for (var i = 0; i < doms.length; i++) { var bindName = doms[i].getAttribute('v-text') doms[i].innerHTML = this.data[bindName] } // v-model 視圖更新 var modelDoms = this.el.querySelectorAll('[v-model]') for (var i = 0; i < modelDoms.length; i++) { var modelBindName = modelDoms[i].getAttribute('v-model') modelDoms[i].value = this.data[modelBindName] || '' } }, // 數據綁定 bindData: function () { var data = this.data for (var key in data) { this.defineObject(data, key, data[key]) } }, // model數據綁定 bindModel: function () { var data = this.data var _that = this var doms = this.el.querySelectorAll('[v-model]') for (var i = 0; i < doms.length; i++) { var bindName = doms[i].getAttribute('v-model') doms[i].value = data[bindName] || '' if (document.addEventListener) { doms[i].addEventListener('keyup', function (event) { e = event || window.event data[bindName] = e.target.value }, false) } else { doms[i].attachEvent('onkeyup', function (event) { e = event || window.event data[bindName] = e.target.value }, false) } } }, // 數據劫持 defineObject: function (obj, prop, value) { var value = value || '' var _that = this Object.defineProperty(obj, prop, { get: function () { return value }, set: function (newVal_) { value = newVal_ _that.updateView() } }) }, } var vue = new Vue({ el: 'vueTest', data: { test1: 'this is a test', test2: 'this is a test2' } }) // 測試用 setTimeout(function () { vue.data.test1 = '5 second delay' }, 5000) </script> </html>