【總結】vue如何實現的數據控制視圖

前言

這篇主要講的就是vue很重要的一塊知識點,雙向數據綁定是如何實現的。一開始看這一塊的內容的時候比較迷茫,迷茫在如下幾個點:html

  • 這塊內容該從哪邊入手
  • 數據變化是如何驅動視圖層更新的
  • 作題深化知識點

從哪邊着手去看響應式原理

我這邊提供三個方向,從這三個方向,你均可以看到watcher的使用,而後watcher的使用過程當中,會摻雜到observer以及dep,而後以點帶面,對總體進行梳理vue

  • 初始化的render流程去看

在lifecycle這個文件中的mountComponent這個方法裏,建立了一個watcher。代碼以下:bash

new Watcher(vm, updateComponent, noop, {
    before () {
      if (vm._isMounted && !vm._isDestroyed) {
        callHook(vm, 'beforeUpdate')
      }
    }
}, true /* isRenderWatcher */)
複製代碼

能夠透過這個傳參,梳理出整一個app

  • 從watch的角度去看oop

  • 從computed的角度去看post

數據變化是如何驅動視圖層更新的

這個問題其實能夠分兩個方面去看:ui

  • 如何知道數據變化了
  • 如何知道某一塊視圖和數據有關,並更新他

如何知道數據變化了

答案:數據劫持 this

  • 數據劫持的兩種方式
    • Object.defineProperty
    • ES6中的proxy

Vue3.0中的數據劫持是用proxy來實現的,目前閱讀的源碼中,都是以Object.defineProperty這種方式來實現的。spa

如何知道某一塊視圖和數據有關,並更新他

答案:依賴收集以及訂閱更新 3d

詳細解讀過程:用圖告訴你響應式原理

這裏僅用一個簡單的例子和圖,來明確一下整個流程

<div id="app">
    {{ message }}
    {{ message1 }}
    <input type="text" v-model="message">
    <div @click="changeMessage">改變message</div>        
</div>
複製代碼
var app = new Vue({
    el: '#app',
    data: {
        message: '1',
        message1: '2',
    },
    methods: {
        changeMessage() {
            this.message = '2'
        }
    },
    watch: {
        message: function(val) {
            this.message1 = val
        }
    }
})
複製代碼
  • 依賴收集流程圖

  • 依賴收集的最終結果:

  • 訂閱更新流程圖:

作題深化知識點

題目以下:

一、簡述Vue的響應式原理

二、計算屬性和watch的區別

三、Vue中給data中的對象屬性添加一個新的屬性時會發生什麼,如何解決?

對於第一和第二在這裏就不花篇幅去說明。

Vue中給data中的對象屬性添加一個新的屬性時會發生什麼,如何解決?

咱們在作業務的時候常常會遇到這樣的狀況,我舉一個簡單的例子:

<template>
  <div>
    <ul>
      <li v-for="value in obj" :key="value">
        {{value}}
      </li>
    </ul>
    <button @click="addObjB">添加obj.b</button>
  </div>
</template>
<script>
export default {
  data () {
    return {
      obj: {
        a: 'obj.a'
      }
    }
  },
  methods: {
    addObjB () {
      this.obj.b = 'obj.b'
      console.log(this.obj)
    }
  }
}
</script>
<style></style>
複製代碼

依賴收集流程:

從中咱們能夠發現,renderWatch是有收集Dep(obj)Dep(Obj.a)的,可是當咱們改變Obj的時候,並無觸發視圖的更新。由於咱們在改變obj的值的時候,並無去觸發Dep(obj)。

產生問題的本質緣由:

一、vue會在state.js文件的initData的方法中,將data屬性中的每個key都變成響應式屬性。

二、視圖在渲染過程當中,會將renderWatcher收集到用到的值的dep中,方便依賴更新(不懂的在回過去看一下依賴收集流程)

三、當你額外添加一個屬性的時候,該屬性並非響應式屬性。

那如何去改變:

addObjB () {
  // this.obj.b = 'obj.b'
  this.$set(this.obj, 'b', 'obj.b')
  console.log(this.obj)
}
複製代碼

總結

這篇文章是年度總結的開篇,後續會繼續總結初始化部分、render部分和patch部分。

相關文章
相關標籤/搜索