首頁 > 軟體

Vue雙向資料繫結與響應式原理深入探究

2022-08-05 14:01:50

一、雙向資料繫結和資料響應式是相同的嗎

不相同,原因如下:

響應式是指通過資料區驅動DOM檢視的變化,是單向的過程。

雙向資料繫結就是無論使用者更新View還是Model,另一個都能跟著自動更新。

  • 例如:當用戶填寫表單時,View的狀態就被更新了,如果此時可以自動更新Model的狀態,那就相當於我們把Model和View做了雙向繫結。
  • 雙向資料繫結的資料和DOM是一個雙向的關係。
  • 響應式是雙向繫結的一環。

二、雙向資料繫結的原理

雙向繫結由三個重要部分(MVVM)構成:

  • 資料層(Model):應用的資料及業務邏輯;
  • 檢視層(View):應用的展示效果,各類UI元件;
  • 業務邏輯層(ViewModel):框架封裝的核心,它負責將資料與檢視關聯起來。

ViewModel的主要職責是:資料變化後更新檢視;檢視變化後更新資料。

ViewModel有兩個主要組成部分:

  • 監聽器(Observer):對所有資料的屬性進行監聽;
  • 解析器(Compiler):對每個元素節點的指令進行掃描跟解析,根據指令模板替換資料,以及繫結響應的更新函數。

Vue中體現出的雙向繫結有兩種方式:v-model屬性和.sync修飾符

v-model屬性:v-model也有兩種使用場景,一是作用在表單元素上,二是作用在元件上

(1)作用在表單元素上:動態繫結了input的value指向了變數,並且在觸發input事件的時候動態的把變數設定為目標值:

<input type="text" v-model="message">
//相當於
<input type="text" v-bind:value="message" v-on:input="message=$event.target.value">

(2)作用在元件上:在自定義元件中,v-model 預設會利用名為 value 的 prop和名為 input 的事件。通過子元件中的 $emit 方法派發 input 事件,父元件監聽 input 事件中傳遞的 value 值,並儲存在父元件 data 中;然後父元件再通過 prop 的形式傳遞給子元件 value 值,再子元件中繫結 input 的 value 屬性即可。

<child :value="message" @input="function(e){message = e}"></child>

.sync修飾符:父元件向子元件傳遞資料的方式有很多種,props是其中的一種,但是它只能單向傳遞,使用.sync可以實現子元件修改父元件的資料。

<!-- 父元件給子元件傳入一個setNum函數 -->
<child :num.sync="numParent">
<script>
//子元件通過呼叫這個函數來實現修改父元件的狀態
methods: {
    changNum(){
      this.$emit('update:num',666)
}
</script>

三、資料響應式的原理與實現

流程:

  1. new Vue()首先執行初始化,對data執行響應化處理,這個過程發生Observe中;
  2. 同時對模板執行編譯,找到其中動態繫結的資料,從data中獲取並初始化檢視,這個過程發生在Complie中;
  3. 同時定義一個更新函數和Watcher,將來對應資料變化時Watcher會呼叫更新函數;
  4. 由於data的某個key在一個檢視中可能出現多次,所以每個key都需要一個管家Dep來管理多個Watcher;
  5. 將來data中資料一旦發生變化,會首先找到對應的Dep,通知所有Watcher執行更新函數。

主要解決兩個問題

1. app.message修改資料,Vue內部是如何監聽message資料的改變的;

——Object.defineProperty ->監聽物件屬性的改變

2. 當資料傳送改變,Vue是如何知道要通知哪些人,介面發生重新整理

——釋出訂閱者模式

實現:

原始碼:

<body>
    <div id="app">
        {{message}}
        {{message}}
        {{message}}
        {{name}}
    </div>
</body>
<script>
    const app = new Vue({
        el:'#app',
        data:{
            message:'哈哈哈',
            name:'fanafan'
        }
    })
</script>

問題1:app.message修改資料,Vue內部是如何監聽message資料的改變的

const obj = {
    message:'哈哈哈',
    name:'fanafan'
}
Object.keys(obj).forEach(key => {
    let value = obj[key]
    Object.defineProperty(obj,key,{
        set(newValue){
            console.log("監聽" + key +"的改變");
            value = newValue
        },
        get(){
            console.log("獲取" + key + "對應的值");
            return value
        }
    })
})

問題2:當資料傳送改變,Vue是如何知道要通知哪些人,介面發生重新整理

// 釋出者訂閱者
class Dep{
    constructor(){
        this.subs = []
    }
    addSub(watcher){
        this.subs.push(watcher)
    }
    notify(){
        this.subs.forEach(item=>{
            item.update()
        })
    }
}
class Watcher {
    constructor(name){
        this.name = name;
    }
    update(){
        console.log(this.name + '發生update');
    }
}
const dep = new Dep()
const w1 = new Watcher('張三')
dep.addSub(w1)
const w2 = new Watcher('李四')
dep.addSub(w2)
const w3 = new Watcher('王五')
dep.addSub(w3)
dep.notify()

到此這篇關於Vue雙向資料繫結與響應式原理深入探究的文章就介紹到這了,更多相關Vue雙向資料繫結內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!


IT145.com E-mail:sddin#qq.com