最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

vue視圖響應(yīng)式更新詳細介紹

 更新時間:2022年09月16日 09:42:18   作者:super_wanan  
這篇文章主要介紹了Vue響應(yīng)式原理,響應(yīng)式就是當對象本身(對象的增刪值)或者對象屬性(重新賦值)發(fā)生了改變的時候,就會運行一些函數(shù),最常見的示render函數(shù)

概述

前面兩篇文章已經(jīng)實現(xiàn)了對數(shù)據(jù)的變化的監(jiān)聽以及模板語法編譯初始化,但是當數(shù)據(jù)變化時,視圖還不能夠跟隨數(shù)據(jù)實時更新。本文就在之前的基礎(chǔ)上介紹下視圖響應(yīng)式更新部分。

思路

統(tǒng)一封裝更新函數(shù)

待數(shù)據(jù)發(fā)生改變時調(diào)用對應(yīng)的更新函數(shù)

這里思考個問題:

在何時注冊這個更新函數(shù)?

如何找到對應(yīng)的更新函數(shù)?

第一步統(tǒng)一封裝更新函數(shù)

基于上篇文章compile的部分,將數(shù)據(jù)初始化的部分統(tǒng)一封裝起來。

compileText (n) {
    // 獲取表達式
    // n.textContent = this.$vm[RegExp.$1]
    // n.textContent = this.$vm[RegExp.$1.trim()]
    this.update(n, RegExp.$1.trim(), 'text')
  }
  text (node, exp) {
    this.update(node, exp, 'text')
    // node.textContent = this.$vm[exp] || exp
  }
  html (node, exp) {
    this.update(node, exp, 'html')
    // node.innerHTML = this.$vm[exp]
  }

很容易寫出update方法:

每個指令都有對應(yīng)的[dir]Updater管理器,用于在公共的update函數(shù)里調(diào)用去在相應(yīng)視圖渲染數(shù)據(jù)。

  update (node, exp, dir) {
    // 第一步: 初始化值
    const fn = this[dir + 'Updater']
    fn && fn(node, this.$vm[exp])
  }
  textUpdater (node, val) {
    node.textContent = val
  }
  htmlUpdater (node, val) {
    node.innerHTML = val
  }

第二步監(jiān)聽并觸發(fā)視圖更新

分析可知,每個模板渲染初始化的過程都需要對數(shù)據(jù)進行監(jiān)聽,并注冊監(jiān)聽函數(shù),因此在上述的update函數(shù)中添加更新邏輯。

  update (node, exp, dir) {
    // 第一步: 初始化值
    const fn = this[dir + 'Updater']
    fn && fn(node, this.$vm[exp])
    // 第二步: 更新
    new Watcher(this.$vm, exp, val => {
      fn && fn(node, val)
    })
  }

創(chuàng)建Watcher類:

// 監(jiān)聽器:負責依賴更新
class Watcher {
  constructor (vm, key, updateFn) {
    this.vm = vm
    this.key = key
    this.updateFn = updateFn
  }
  update () {
    // 綁定作用域為this.vm,并且將this.vm[this.key]作為值傳進去
    this.updateFn.call(this.vm, this.vm[this.key])
  }
}

此時我們已經(jīng)完成了更新函數(shù)的功能,需要做的就是在數(shù)據(jù)發(fā)生改變的時候,主動調(diào)用下對應(yīng)的update函數(shù)。

簡單測試下:聲明一個全局的watchers數(shù)組。在每次Watcher的構(gòu)造函數(shù)中都往watchers中push一下,那么我們就可以再Object.defineProperty()的set方法中去遍歷所有的watchers,調(diào)用update方法。

淺試一下:

const watchers = []
class Watcher {
  constructor (vm, key, updateFn) {
    this.vm = vm
    this.key = key
    this.updateFn = updateFn
    watchers.push(this)
  }
  update () {
    this.updateFn.call(this.vm, this.vm[this.key])
  }
}
function defineReactive (obj, key, val) {
  // 遞歸
  // val如果是個對象,就需要遞歸處理
  observe(val)
  const dep = new Dep()
  Object.defineProperty(obj, key, {
    get () {
      Dep.target && dep.addDep(Dep.target)
      return val
    },
    set (newVal) {
      if (newVal !== val) {
        val = newVal
        // 新值如果是對象,仍然需要遞歸遍歷處理
        observe(newVal)
        //暴力的寫法,讓一個人干事指揮所有人動起來(不管你需不需要更新,全給我更新一遍)
        watchers.forEach(watch => {
           watch.update()
        })
      }
    }
  })
}

此時頁面視圖已經(jīng)可以根據(jù)數(shù)據(jù)的變而發(fā)生相應(yīng)的更新了。

引入Dep管家

只觸發(fā)需要更新的函數(shù)

上述的寫法過于暴力,數(shù)據(jù)量一旦稍微大點就會嚴重影響性能。vue內(nèi)部引入了Dep這個大管家的概念來進行依賴收集,統(tǒng)一管理所有的watcher。只讓需要干活的watcher去update。

class Dep {
  constructor () {
    this.deps = []
  }
  addDep (dep) {
    this.deps.push(dep)
  }
  notify () {
    this.deps.forEach(dep => dep.update())
  }
}

每個data中的key對應(yīng)一個dep就行,所以選擇在Object.defineProperty的getter函數(shù)中進行依賴收集。在watcher中觸發(fā)依賴收集

class Watcher {
  constructor (vm, key, updateFn) {
    this.vm = vm
    this.key = key
    this.updateFn = updateFn
    // 觸發(fā)依賴收集,使用一個靜態(tài)變量target去保存對應(yīng)的Watcher
    Dep.target = this
    // 主動訪問vm[key],觸發(fā)一下getter
    this.vm[this.key]
    Dep.target = null
  }
  update () {
    // 綁定作用域為this.vm,并且將this.vm[this.key]作為值傳進去
    this.updateFn.call(this.vm, this.vm[this.key])
  }
}

收集依賴,創(chuàng)建Dep實例

function defineReactive (obj, key, val) {
  observe(val)
  const dep = new Dep()
  Object.defineProperty(obj, key, {
    get () {
      Dep.target && dep.addDep(Dep.target)
      return val
    },
    set (newVal) {
      if (newVal !== val) {
        val = newVal
        observe(newVal)
        dep.notify()
      }
    }
  })
}

至此,我們一個簡版的Vue就實現(xiàn)了。這里還沒有涉及到虛擬dom得概念,以后介紹。

實現(xiàn)下語法糖v-model

v-model雖然很像使用了雙向數(shù)據(jù)綁定的 Angular 的 ng-model,但是 Vue 是單項數(shù)據(jù)流,v-model 只是語法糖而已。

// 最簡形式,省略了value的顯式綁定,省略了oninput的顯式事件監(jiān)聽,是第二句代碼的語法糖形式
<input v-model="sth" />
<input v-bind:value="sth" v-on:input="sth = $event.target.value" />
//第二句代碼的簡寫形式
<input :value="sth" @input="sth = $event.target.value" />

分析一下其就是在內(nèi)部實現(xiàn)了v-bind:value=“” 和@input。

 model (node, exp) {
   node.value = this.$vm[exp]
   node.addEventListener('input', (e) => {
     this.$vm[exp] = e.target.value
   })
 }

到此這篇關(guān)于vue視圖響應(yīng)式更新詳細介紹的文章就介紹到這了,更多相關(guān)vue響應(yīng)式更新內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

最新評論

宿松县| 宜川县| 新余市| 康马县| 兴隆县| 香河县| 双柏县| 太原市| 金山区| 林甸县| 增城市| 图木舒克市| 尚志市| 资中县| 镇远县| 石河子市| 诏安县| 惠水县| 区。| 商南县| 固始县| 贞丰县| 南漳县| 古田县| 安庆市| 普兰店市| 原平市| 温泉县| 襄汾县| 景洪市| 合阳县| 榆中县| 伊金霍洛旗| 绥宁县| 鄂托克旗| 井研县| 花莲市| 宜春市| 格尔木市| 通河县| 霍州市|