從0開始探究vue-雙向綁定原理

理解

vue是一個很是優秀的框架,其優秀的雙向綁定原理,mvvm模型,組件,路由解析器等,很是的靈活方便,也使開發者可以着重於數據處理,讓開發者更清晰的設計本身的業務。html

雙向綁定,就是數據變化的時候,自動觸發視圖的變化。vue

實踐

咱們都理解,vue2.0中,雙向綁定的核心爲Object.defineProperty(obj, prop, descriptor),方法會直接在一個對象上定義一個新屬性,或者修改一個對象的現有屬性, 並返回這個對象git

參數obj要在其上定義屬性的對象。
參數prop要定義或修改的屬性的名稱。
參數descriptor將被定義或修改的屬性描述符。github

返回被傳遞給函數的對象。瀏覽器

嘗試Object.defineProperty攔截用戶對變量的設置

咱們能夠新建一個項目,用來模擬及學習vue雙向綁定的相關內容框架

+   vue相關
+       |- 雙向綁定原理
+           |- js
+               |- myVue.js
+           |- index.html

修改index.html中的內容,引入本身建立的myVue.js。mvvm

+   <!DOCTYPE html>
+   <html lang="en">
+   <head>
+       <meta charset="UTF-8">
+       <meta name="viewport" content="width=device-width, initial-scale=1.0">
+       <title>Document</title>
+   </head>
+   <body>
+
+      <script src="./js/myVue.js"></script>
+   </body>
+   </html>

編輯myVue.js的內容,來嘗試一下Object.defineProperty(obj, prop, descriptor)這個APIide

+   var data = {
+       a: 1
+   }
+   Object.defineProperty(data, 'a', {// 爲data中的a進行攔截,讀取a的時候返回本身新建的_a的值,設置a的值的時候,設置到_a上。這樣,開發者對a的操做,都會映射到咱們新建的虛擬的_a變量上
+       configurable: true, //  是否容許刪除屬性,默認true
+       enumerable: true, //  是否容許遍歷,默認true
+       get: function () {
+           console.log('我被讀取了,返回了_a的值', this._a)
+           return this._a
+       },
+       set(value) {
+           // this.a = value;
+           this._a = value;
+           console.log('我被設置了,被設置的值爲', this._a, '並放進了a的對象中')
+       }
+   })

在瀏覽器中,打開頁面,並查看控制檯,對data.a進行操做函數

data.a                                                              myVue.js:8 
我被讀取了,返回了_a的值 undefined
undefined
——————————————————————————————————————————————————————————————————————————————
data.a = 10                                                         myVue.js:14 
我被設置了,被設置的值爲 10 並放進了a的對象中
10
——————————————————————————————————————————————————————————————————————————————
data.a                                                              myVue.js:8
我被讀取了,返回了_a的值 10
10

能夠看到,咱們對data.a進行的操做,實際改變的變量是咱們已經攔截的_a變量。
目前出現的問題是,第一次讀取的時候,這個值沒有被設置上,在下面來模擬解決方案post

私有變量

聲明概念_開頭的變量一版爲私有變量,外部沒法訪問,可是咱們如今在控制檯中輸入並修改私有變量data._a

data._a
10
——————————————————————————————————————————————————————————————————————————————
data._a = 20
20
——————————————————————————————————————————————————————————————————————————————
data._a
20
——————————————————————————————————————————————————————————————————————————————
data.a                                                              myVue.js:8 
我被讀取了,返回了_a的值 20
20

卻能夠拿到私有變量中的_a的值,也能夠進行無攔截的修改,這顯然是咱們所不但願的

因此咱們能夠爲Object.defineProperty(obj, prop, descriptor)來進行封裝一次,把咱們理解的_a變成一個私有變量
修改myVue.js的內容爲以下內容,

var data = {
    a: 1
}
myDefineProperty(data, 'a')

function myDefineProperty(obj,key){//對Object.defineProperty進行一次攔截,使外界沒法訪問私有變量value
    var value = obj[key];
    Object.defineProperty(obj,key,{// 爲data增長
        configurable: true, //  是否容許刪除屬性,默認true
        enumerable: true, //  是否容許遍歷,默認true
        get: function () {
            console.log('我被讀取了,返回了value的值', value)
            return value
        },
        set(newValue) {
            value = newValue;
            console.log('我被設置了,被設置的值爲', newValue, '並放進了value的對象中')
        }
    })
}

而後再查看控制檯

data._a
undefined
——————————————————————————————————————————————————————————————————————————————
data.value
undefined
——————————————————————————————————————————————————————————————————————————————
data.a                                                             myVue.js:12
我被讀取了,返回了value的值 1
1
——————————————————————————————————————————————————————————————————————————————

開發者就沒法自行操做咱們設計的私有變量value的內容了

自此,咱們解決了,對一個對象屬性的攔截,而且阻止了用戶對咱們設計的私有變量進行操做

雙向綁定實踐

咱們知道了攔截屬性以後,那麼就進一步來實現,一個簡單的雙向綁定

咱們修改一下index.html中的內容

<!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Document</title>
+       <input type="text" @change='changeIpt'>
+       <p id='changeValue'></p>
    </head>
    <body>
        
        <script src="./js/myVue.js"></script>
    </body>
    </html>

並在myVue.js中,在set中添加雙向綁定的操做

var data = {
        a: 1
    }
    myDefineProperty(data, 'a')


+   var ipt = document.getElementById('ipt');
+   ipt.oninput =  function(e){
+       data.a = e.target.value
+   }

    function myDefineProperty(obj,key){
        var value = obj[key];
        Object.defineProperty(obj,key,{// 爲data增長
            configurable: true, //  是否容許刪除屬性,默認true
            enumerable: true, //  是否容許遍歷,默認true
            get: function () {
                console.log('我被讀取了,返回了value的值', value)
                return value
            },
            set(newValue) {
                value = newValue;
+               document.getElementById('iptValue').innerText = newValue;
+               ipt.value = newValue;
                console.log('我被設置了,被設置的值爲', newValue, '並放進了value的對象中')
            }
        })
    }

而後咱們在input框裏輸入內容,便表現出了雙向綁定的能力。

點擊查看demo

記得打開控制檯哦!~下方爲錄製的屏幕,可能沒法正常顯示,能夠點擊上方demo來查看

以爲好的話,能夠給個人 github點個star

相關文章
相關標籤/搜索