【Vue原理】VModel - 白話版

寫文章不容易,點個讚唄兄弟
專一 Vue 源碼分享,文章分爲白話版和 源碼版,白話版助於理解工做原理,源碼版助於瞭解內部詳情,讓咱們一塊兒學習吧
研究基於 Vue版本 【2.5.17】

若是你以爲排版難看,請點擊 下面連接 或者 拉到 下面關注公衆號也能夠吧dom

【Vue原理】VModel - 白話版函數

說到 Vue,感受第一印象就是雙向綁定,因此v-model鍵值是Vue印象的半壁江山啊,這麼重要的東西,你好歹要知道是怎麼實現的吧學習

咱們今天就來說解雙向綁定的工做原理,你應該知道,雙向綁定就是經過綁定 dom 事件來實現的,但是,怎麼綁定的事件,綁定什麼事件?this

首先,雙向綁定,我我的認爲應該分爲 初始化綁定 和 雙向更新 兩part。spa

初始化綁定,就是初始化時給表單元素綁定值,綁定事件,爲雙向更新作準備3d

雙向更新,就是任意一邊變化,同時能讓另外一個邊更新雙向綁定

雙向更新那是後話,只有一開始時成功執行綁定操做纔會有以後 雙向更新這個東西,因此,今天按順序來了解兩個part,從四個問題開始code

一、v-model 怎麼給表單綁定數據對象

二、v-model 綁定什麼事件token

三、v-model 怎麼綁定事件

四、v-model 如何進行雙向更新

TIP

v-model 還能夠用在 自定義組件上,可是很明顯,此次咱們先不講這一塊,而是先將正常的表單使用


先看結論

咱們先以 input text 類型講解,對於其餘的表單元素,流程都差很少,只是中間涉及的內容不一樣。因此就先講個例子,而後具體在源碼版所有一塊兒說

一、怎麼賦值?v-model 綁定的數據賦值給表單元素的 value 屬性

二、怎麼綁定事件?解析不一樣表單元素,配置相應的事件名和事件回調,在插入dom以前,addEventListener 綁定上事件

三、怎麼雙綁?外部變化,觸發事件回調,event.target.value 賦值給model綁定的數據;內部變化,修改表單元素屬性 value

看完結論,有點懵?咱們來看看具體的內容,結果導向來進行學習

下面的講解如下面這個爲例

image

image

v-model 怎麼給表單綁定數據

獲取值流程

首先,上面例子解析後的渲染函數是下面這樣(已簡化,只保留表單值相關)

(function(){    
    with(this){  
        return _c('div',[
            _c('input',
                domProps:{"value":name}
            )
        ])
    }
})

一、這個渲染函數是沒有執行的 匿名函數。執行的時候,會綁定上下文對象爲 組件實例

二、因而 with(this) 中的 this 就能取到 組件實例自己,with 的代碼塊 頂層做用域 就綁定爲了 組件實例

三、因而 with 內部變量的訪問,就會首先訪問到 組件實例上。其中 name 的 獲取,就會先從 組件實例上獲取,至關於 vm.name。賦值完成後,domProps 就是下面這樣

{ domProps:{value:111} }

四、上面的 value 是 v-model 解析成的原生屬性,保存在屬於該節點 input 的 domProps 對象存儲器中

綁定值流程

建立dom input 以後,插入dom input 以前,遍歷該 input 的 domProps ,逐個添加給 input dom

簡化後的代碼像下面這樣進行賦值

for(var i in domProps){
    input[i]=domProps[i]
}

其中給節點賦值就是這樣

input.value = 111

v-model 綁定什麼事件

不一樣的表單元素使用v-model,會綁定不一樣的 事件

change 事件

select,checkbox,radio

input 事件

這是默認事件,當不是上面三種表單元素時,會解析成 input 事件

好比 text、number 等 input 元素和 textarea

TIP

實際上關於 input 和 textarea 綁定的事件遠不止 input 一個事件,可是涉及內容太多,打算放在源碼版說明,這裏先簡單默認是 input 事件


v-model 怎麼綁定事件

上面例子解析成下面的渲染函數(已簡化,只保留事件相關)

with(this) {    
    return _c('div', [
        _c('input', {        
            on: {            
              "input": function($event) {
                  name = $event.target.value
              }
            }
        }
    )])
}

解析事件流程

1解析不一樣表單元素,配置不一樣的事件

2拼裝 事件回調函數,不一樣表單元素,回調不同

3把 事件名和拼裝回調 配套 保存給相應的表單元素的 on 事件存儲器

何時綁定事件

生成 input dom 以後,插入input dom 以前

怎麼綁

使用以前保存的 事件名和 事件回調,給 input dom 像下面這樣綁定上事件

input.addEventListener("input",function($event) {    
    name = $event.target.value 
})

v-model 如何進行雙向更新

雙向,指的是 外部和內部

外部變化:用戶手動改變表單值,輸入或者選擇

內部變化:從內部修改綁定值

內部變化

一、v-model 綁定了 name ,name 會收集到 本組件的 watcher

a. 下面渲染函數執行時,會綁定自己組件實例爲上下文對象

b. name 訪問的是 組件實例的 name

c. name 此時便收集到了 當前正在渲染的組件實例,當前渲染的實例是本身,因而收集到了自身的 watcher

(function(){    
  with(this){  
    return _c('div',[_c('input',
        domProps:{"value":(name)})
    ])
  }
})

若是你不懂 收集 watcher 什麼意思,建議看下個人另外一篇文章

【Vue原理】響應式原理 - 白話版

二、內部修改 name 變化,通知收集器內的 watcher 更新,因此本組件會更新,上面的渲染函數從新執行,便 從新從實例讀取 name

image

三、從新給 input dom 的 value 賦值,因而 頁面就更新了

怎麼賦值?那是回到第一個問題了,兄弟

外部變化

手動改變表單,事件觸發,執行事件回調(下面這個),更新組件數據 name

function($event) {    
    name = $event.target.value 
}

更新內部數據流程

一、當事件觸發的時候,會把 表單的值 賦值給 name

二、name 是從 組件實例上訪問的

三、因此此次賦值會 直接改變組件實例的 name

回調怎麼賦值給組件實例的name

一開始不懂,因此不理解,也沒查到,寫了個例子,大概理解了意思

一、由於事件回調 在 with 裏面聲明

二、因而事件回調的 做用域鏈最頂層 就加上了一層 with 綁定的做用域

三、就算事件回調不在 with 中執行,事件回調中的 變量訪問,也會先訪問以前 with 綁定過的做用域,由於做用域鏈的最頂層

with舉栗子

var name=22
var a={name:"a"}
with(a){    
    var fn=function(){        
        console.log(name)
    }
}
fn()

你認爲 fn 執行的時候,會打印出什麼呢?行了,給你看結果了

image

好吧,再一次深入認識到一個知識點,with 綁定做用域原來這麼強,離開with執行,仍是先訪問他的做用域,脫離不出魔爪啊,強盜做用域

image

回來總結

因而當事件回調執行的時候,會 直接賦值 給 組件實例的name,這樣便經過外部改變了內部數據

TIP

外部變化,原本可能會存在一種狀況

a、手動修改表單後, 回調內會更新組件的值

b、組件的值更新以後,會通知組件更新,組件更新時,便又會從新把input 賦值一遍

很是多餘的一步操做,因此這裏,Vue作一個判斷,判斷舊值和 新值是否相等,不等才更新,關於舊值,會保存在 dom 的 _value 屬性


總結

v-model 三要素

一、綁定屬性

二、綁定事件

三、屬性+事件組合完成雙向更新

公衆號

相關文章
相關標籤/搜索