五十行javascript代碼實現簡單的雙向數據綁定

五十行javascript代碼實現簡單的雙向數據綁定

Vue框架想必從事前端開發的同窗都使用過,它的雙向數據綁定機制能給咱們帶來很大的方便。今天閒着沒事,嘗試着實現一下雙向數據綁定,接下來給你們分享一下。javascript

Object.defineProperty(obj, prop, descriptor)

Object.defineProperty 方法容許精確添加或修改對象的屬性。它的第一個參數 obj 是要在其上定義屬性的對象,第二個參數 prop 是要定義或修改的屬性的名稱,第三個參數 descriptor 是一個將被定義或修改的屬性的描述符。html

返回值: 被傳遞給函數的對象。前端

來舉個例子:java

var o = Object.defineProperty({}, 'name', { value: 1 }); console.log(o) // {name: 1}

這是最基本的定義一個對象的方式。對於屬性描述符,還有不少其餘屬性:git

數據描述符和存取描述符均具備如下可選鍵值:github

  • configurable當且僅當該屬性的 configurable 爲 true 時,該屬性描述符纔可以被改變,也可以被刪除。默認爲 false。
  • enumerable當且僅當該屬性的 enumerable 爲 true 時,該屬性纔可以出如今對象的枚舉屬性中。默認爲 false。

數據描述符同時具備如下可選鍵值:api

  • value該屬性對應的值。能夠是任何有效的 JavaScript 值(數值,對象,函數等)。默認爲 undefined。
  • writable當且僅當該屬性的 writable 爲 true 時,該屬性才能被賦值運算符改變。默認爲 false。

存取描述符同時具備如下可選鍵值:瀏覽器

  • get一個給屬性提供 getter 的方法,若是沒有 getter 則爲 undefined。該方法返回值被用做屬性值。默認爲 undefined。
  • set一個給屬性提供 setter 的方法,若是沒有 setter 則爲 undefined。該方法將接受惟一參數,並將該參數的新值分配給屬性。默認爲 undefined。

 

這裏只說一下 get 和 set
看一下這個例子:markdown

var o = Object.defineProperty({}, 'name', { get: function () { return this._name_; }, set: function (value) { this._name_ = value * 2; } }); o.name = 1; console.log(o.name); // 2

給屬性 name 定義了一個 get 和 set ,爲何使用 _name_而不是name呢?由於name是正在被定義的屬性,若是在get或者set中使用name無形之中就會發生遞歸,致使棧溢出。_name_這個是本身自定義的,你徹底能夠設置爲$name__name__等等。框架

另外,使用對象的字面量形式也能夠設置getset

var o = { get name(){ return this._name_; }, set name(value){ this._name_ = value * 2; } }; o.name = 1; console.log(o.name); // 2

實現雙向數據綁定

要實現雙向數據綁定,確定要從 get 與 set 下手,在 set 的函數中從新渲染相關的數據,因此一開始應該是這樣的:

var o = { get name(){ return this._name_; }, set name(value){ this._name_ = value; this.render('name'); }, render: function(pro){ document.write(this[pro]); } };

在瀏覽器控制檯修改一下o.name 試試:

如何實現表單控件到數據的綁定呢?在 Vue 中,表單元素經過 v-model 綁定一個變量,類型這樣:

<input type="text" v-model="name">

其實 v-model 的元素是綁定了一個 input的自定義事件,咱們不考慮那麼多,就使用原生的 oninput 事件來模擬下。

var o = { get name(){ return this._name_; }, set name(value){ this._name_ = value; console.log(this._name_); }, inputInit: function () { var self = this; var vModels = document.querySelectorAll('[v-model]'); for (let i = 0; i < vModels.length; i++) { vModels[i].addEventListener('input', function () { var property = this.getAttribute('v-model'); var value = this.value; self.name = value; }) } } }.inputInit();

至此一個簡單的雙向數據綁定就差很少了,咱們模仿一下 Vue 的api格式,再將代碼封裝一下:

html:

<input type="text" v-model="name"> <p v-text="name"></p>

javascript:

function Vue(options) { var data = options.data || {}; var dKeys = Object.keys(data); var _this = this; this.vData = {}; // 根據data中的變量數量動態的綁定 get 與 set for (let i = 0; i < dKeys.length; i++) { Object.defineProperty(this.vData, dKeys[i], { get: function () { return this['__' + dKeys[i] + '__']; }, set: function (value) { this['__' + dKeys[i] + '__'] = value; _this.render(dKeys[i]); // 從新渲染相關數據 } }) } for(let i in data) { // 初始化時設置一變vData,觸發一遍 set this.vData[i] = data[i]; } this.inputInit(); // 給表單組件綁定事件監聽 } Vue.prototype.render = function (pro) { var vModels = document.querySelectorAll('[v-model=' + pro + ']'); var vText = document.querySelectorAll('[v-text=' + pro + ']'); for (var i = 0; i < vModels.length; i++) { vModels[i].value = this.vData[pro]; } for (var j = 0; j < vText.length; j++) { vText[j].innerText = this.vData[pro]; } }; Vue.prototype.inputInit = function () { var self = this; var vModels = document.querySelectorAll('[v-model]'); for (let i = 0; i < vModels.length; i++) { vModels[i].addEventListener('input', function () { var property = this.getAttribute('v-model'); var value = this.value; self.vData[property] = value; }) } }; var vm = new Vue({ data: { name: 1 } })

愛寫代碼的孩子運氣不會太差。 github:http://github.com/lavyun 新浪微博:http://weibo.com/u/5921186675
相關文章
相關標籤/搜索