Vue.set()和this.$set()應(yīng)用的場(chǎng)景

背景:在vue中改變對(duì)象的屬性值或者通過(guò)索引改變數(shù)組時(shí),對(duì)應(yīng)修改的字段不會(huì)重新在頁(yè)面渲染。

例如:

const vueInstance = new Vue({
  data: {
    arr: [1, 2],
    obj1: {
        a: 3
    }
  }
});

vueInstance.$data.arr[0] = 3;  // 頁(yè)面不會(huì)重新渲染
vueInstance.$data.obj1.b = 3;  // 頁(yè)面不會(huì)重新渲染

經(jīng)過(guò)查看官方文檔發(fā)現(xiàn)這部分說(shuō)明如下:

Vue.set()向響應(yīng)式對(duì)象中添加一個(gè)屬性,并確保這個(gè)新屬性同樣是響應(yīng)式的,且觸發(fā)視圖更新。它必須用于向響應(yīng)式對(duì)象上添加新屬性,因?yàn)?Vue 無(wú)法探測(cè)普通的新增屬性 (比如 this.myObject.newProperty = 'hi')


所以按照官方的寫法應(yīng)該是:

Vue.set(vueInstance.$data.arr, 0, 3);  // 這樣操作數(shù)組可以讓頁(yè)面重新渲染
vueInstance.$set(vueInstance.$data.arr, 0, 3); // 這樣操作數(shù)組也可以讓頁(yè)面重新渲染
Vue.set(vueInstance.$data.obj1, b, 3);  // 這樣操作對(duì)象可以讓頁(yè)面重新渲染
vueInstance.$set(vueInstance.$data.obj1, b, 3); // 這樣操作對(duì)象也可以讓頁(yè)面重新渲染
Vue.set()和this.$set()實(shí)現(xiàn)原理

是時(shí)候看一波這兩個(gè)api的源碼了,我們先來(lái)看看Vue.set()的源碼:

import { set } from '../observer/index'

...
Vue.set = set
...

再來(lái)看看this.$set()的源碼:

import { set } from '../observer/index'

...
Vue.prototype.$set = set
...

發(fā)現(xiàn)這兩個(gè)api的實(shí)現(xiàn)原理基本一模一樣,都是使用了set函數(shù)。set函數(shù)是從 ../observer/index 文件中導(dǎo)出的,區(qū)別在于Vue.set()是將set函數(shù)綁定在Vue構(gòu)造函數(shù)上,this.$set()是將set函數(shù)綁定在Vue原型上。

數(shù)組的實(shí)現(xiàn)原理

繼續(xù)源碼:

if (Array.isArray(target) && isValidArrayIndex(key)) {
    target.length = Math.max(target.length, key)
    target.splice(key, 1, val)
    return val
  }

首先if判斷當(dāng)前target是不是數(shù)組,并且key的值是有效的數(shù)組索引。然后將target數(shù)組的長(zhǎng)度設(shè)置為target.length和key中的最大值,這里為什么要這樣做呢?是因?yàn)槲覀兛赡軙?huì)進(jìn)行下面這種騷操作:

arr1 = [1,3];
Vue.set(arr1,10,1)  // 如果不那樣做,這種情況就會(huì)出問(wèn)題

接著向下看,我們發(fā)現(xiàn)這里直接調(diào)用了target.splice(key, 1, val),在前面我們說(shuō)過(guò)調(diào)用arrayMethods提供的push、pop等7個(gè)方法可以導(dǎo)致頁(yè)面重新渲染,剛好splice也是屬性arrayMethods提供的7個(gè)方法中的一種。

總結(jié)一下Vue.set數(shù)組實(shí)現(xiàn)的原理:
其實(shí)Vue.set()對(duì)于數(shù)組的處理其實(shí)就是調(diào)用了splice方法,是不是發(fā)現(xiàn)其實(shí)很簡(jiǎn)單~~

對(duì)象的實(shí)現(xiàn)原理

繼續(xù)看源碼:

if (key in target && !(key in Object.prototype)) {
    target[key] = val
    return val
  }

這里先判斷如果key本來(lái)就是對(duì)象中的一個(gè)屬性,并且key不是Object原型上的屬性。說(shuō)明這個(gè)key本來(lái)就在對(duì)象上面已經(jīng)定義過(guò)了的,直接修改值就可以了,可以自動(dòng)觸發(fā)響應(yīng)。
注意:對(duì)于新增的對(duì)象屬性不會(huì)重新渲染,這也剛好解釋了我們使用 vueInstance.$data.obj1.b = 3; 的時(shí)候?yàn)槭裁错?yè)面不會(huì)重新渲染,因?yàn)檫@里的屬性b不是對(duì)象的已有屬性,也就是說(shuō)屬性b沒(méi)有進(jìn)行過(guò)依賴收集,所以才會(huì)導(dǎo)致修改屬性b的值頁(yè)面不會(huì)重新渲染。

繼續(xù)看源碼:

defineReactive(ob.value, key, val)
  ob.dep.notify()
  return val

這里其實(shí)才是vue.set()真正處理對(duì)象的地方。defineReactive(ob.value, key, val)的意思是給新加的屬性添加依賴,以后再直接修改這個(gè)新的屬性的時(shí)候就會(huì)觸發(fā)頁(yè)面渲染。
ob.dep.notify()這句代碼的意思是觸發(fā)當(dāng)前的依賴(這里的依賴依然可以理解成渲染函數(shù)),所以頁(yè)面就會(huì)進(jìn)行重新渲染。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 主要還是自己看的,所有內(nèi)容來(lái)自官方文檔。 介紹 Vue.js 是什么 Vue (讀音 /vju?/,類似于 vie...
    Leonzai閱讀 3,540評(píng)論 0 25
  • Swift1> Swift和OC的區(qū)別1.1> Swift沒(méi)有地址/指針的概念1.2> 泛型1.3> 類型嚴(yán)謹(jǐn) 對(duì)...
    cosWriter閱讀 11,675評(píng)論 1 32
  • 第3章 基本概念 3.1 語(yǔ)法 3.2 關(guān)鍵字和保留字 3.3 變量 3.4 數(shù)據(jù)類型 5種簡(jiǎn)單數(shù)據(jù)類型:Unde...
    RickCole閱讀 5,527評(píng)論 0 21
  • vue概述sd 在官方文檔中,有一句話對(duì)Vue的定位說(shuō)的很明確:Vue.js 的核心是一個(gè)允許采用簡(jiǎn)潔的模板語(yǔ)法來(lái)...
    去年的牛肉閱讀 4,234評(píng)論 0 1
  • VUE介紹 Vue的特點(diǎn)構(gòu)建用戶界面,只關(guān)注View層簡(jiǎn)單易學(xué),簡(jiǎn)潔、輕量、快速漸進(jìn)式框架 框架VS庫(kù)庫(kù),是一封裝...
    多多醬_DuoDuo_閱讀 2,859評(píng)論 1 17

友情鏈接更多精彩內(nèi)容