vue中Vue.set()的使用以及對(duì)其進(jìn)行深入解析
Vue.set()使用
vue 在實(shí)例上添加新的屬性的時(shí)候,該屬性,并不是響應(yīng)式的。同樣刪除某一屬性的時(shí)候,也不會(huì)實(shí)時(shí)渲染到頁(yè)面上。
比如:
<p> 年齡:{{obj.age? obj.age: "無(wú)"}}</p>
···········
data() {
return {
obj:{ name:"Lena", id:1 },
}
}
頁(yè)面上 顯示的是 年齡:無(wú) 現(xiàn)在需要添加一個(gè)響應(yīng)式的屬性 age 。
<template> <div class="app"> <ul> <li> 年齡:{{obj.age? obj.age: "無(wú)"}}</li> </ul> <button @click="add()">添加年齡屬性</button> <button @click="show()">打印</button> </div> </template> <script> import Vue from 'vue' export default { component:{}, data() { return { obj:{ name:"Lena", id:1 }, } }, methods: { add(){ this.obj.age= 20 }, show(){ console.log('obj',this.obj) } } } </script>
效果:
通過(guò) this.obj.age= 20 ,控制臺(tái)打印已經(jīng)有了該屬性,并沒(méi)有渲染到頁(yè)面上。 可見(jiàn),這種方式添加的屬性 age 并不是響應(yīng)式的。
使用Vue.set() ,更改add()方法:
add(){ Vue.set(this.obj,'age', '20') },
效果:
因?yàn)関ue不能檢測(cè)到對(duì)象屬性的添加或者刪除,只有在data對(duì)象上存在的屬性是響應(yīng)式的,所以要使用Vue.set()方法將響應(yīng)式屬性添加到對(duì)象上。同樣的道理,刪除對(duì)象 Vue.delete也是如此。
Vue.delete()的使用
<template> <div class="app"> <ul> <li> 年齡:{{obj.age? obj.age: "無(wú)"}}</li> </ul> <button @click="add()">添加年齡屬性</button> <button @click="del()">刪除年齡屬性</button> <button @click="show()">打印</button> </div> </template> <script> import Vue from 'vue' export default { component:{ }, data() { return { obj:{ name:"Lena", id:1 }, } }, methods: { add(){ Vue.set(this.obj,'age', '20') }, del(){ Vue.delete(this.obj,'age') }, show(){ console.log('obj',this.obj) } } } </script>
效果:
del() 方法如果是下面兩種,同樣不是響應(yīng)式的。
del(){
delete this.obj.age
},
或者:
del(){
this.obj = { name:"Lena", id:1 }
},
Vue.set()方法原理解析
我們找到封裝set方法的地方:.........\node_modules\vue\src\core\observer\index.js
找到封裝的set方法:
export function set (target: Array<any> | Object, key: any, val: any): any { if (process.env.NODE_ENV !== 'production' && (isUndef(target) || isPrimitive(target)) ) { warn(`Cannot set reactive property on undefined, null, or primitive value: ${(target: any)}`) } if (Array.isArray(target) && isValidArrayIndex(key)) { target.length = Math.max(target.length, key) target.splice(key, 1, val) return val } if (key in target && !(key in Object.prototype)) { target[key] = val return val } const ob = (target: any).__ob__ if (target._isVue || (ob && ob.vmCount)) { process.env.NODE_ENV !== 'production' && warn( 'Avoid adding reactive properties to a Vue instance or its root $data ' + 'at runtime - declare it upfront in the data option.' ) return val } if (!ob) { target[key] = val return val } defineReactive(ob.value, key, val) ob.dep.notify() return val }
對(duì)象調(diào)用:Vue.set( target ,'age', 20 )
數(shù)組調(diào)用:Vue.set( array , 0, 20 ) //數(shù)組對(duì)象,索引,值
首先是判斷是否是開(kāi)發(fā)環(huán)境并且 對(duì)象是否被定義isUndef(target)或者是否是基礎(chǔ)類(lèi)型isPrimitive(target),否則會(huì)報(bào)錯(cuò):
`Cannot set reactive property on undefined, null, or primitive value: ${(target: any)}`
if (process.env.NODE_ENV !== 'production' &&
(isUndef(target) || isPrimitive(target))
)
如果是數(shù)組的話,調(diào)用重寫(xiě)的splice()方法,可以更新視圖。
isValidArrayIndex(key)方法用來(lái)驗(yàn)證是否是一個(gè)有效的數(shù)組索引, 其實(shí)就是驗(yàn)證是否是一個(gè)非無(wú)窮大的正整數(shù)。
if (Array.isArray(target) && isValidArrayIndex(key)) { ? ? target.length = Math.max(target.length, key) ? ? target.splice(key, 1, val) ? ? return val ? }
如果對(duì)象本身就有所要添加的屬性,那只需要直接賦值就可以。
if (key in target && !(key in Object.prototype)) { ? ? target[key] = val ? ? return val ? }
如果是Vue實(shí)例,或者是根數(shù)據(jù)data的時(shí)候,就會(huì)報(bào)錯(cuò)。
如果本身就不是響應(yīng)式的,只需要直接賦值即可。
const ob = (target: any).__ob__ //如果是Vue實(shí)例,或者是根數(shù)據(jù)data的時(shí)候,就會(huì)報(bào)錯(cuò)。 if (target._isVue || (ob && ob.vmCount)) { process.env.NODE_ENV !== 'production' && warn( 'Avoid adding reactive properties to a Vue instance or its root $data '+ 'at runtime - declare it upfront in the data option.' ) return val } //如果本身就不是響應(yīng)式的,只需要直接賦值即可。 if (!ob) { target[key] = val return val } defineReactive(ob.value, key, val) ob.dep.notify() return val
排除各種不合適的,最后給當(dāng)前對(duì)象定義一個(gè)屬性:defineReactive(ob.value, key, val) 相當(dāng)于用了 Object.defineProperty 重新定義了一下。
最后,手動(dòng)通知視圖更新:ob.dep.notify()
總結(jié)
這個(gè) set方法,對(duì)于數(shù)組來(lái)說(shuō),調(diào)用的就是splice,對(duì)于對(duì)象來(lái)說(shuō),使用的就是defineReactive,再添加了一個(gè)手動(dòng)的視圖更新。這就是set的原理。
到此這篇關(guān)于vue中Vue.set()的使用以及對(duì)其進(jìn)行深入解析的文章就介紹到這了,更多相關(guān)vue Vue.set()的使用內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
vue-cli 打包后提交到線上出現(xiàn) "Uncaught SyntaxError:Unexpected token" 報(bào)
這篇文章主要介紹了vue-cli 打包后提交到線上出現(xiàn) "Uncaught SyntaxError:Unexpected token" 報(bào)錯(cuò),小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-11-11elementUI同一頁(yè)面展示多個(gè)Dialog的實(shí)現(xiàn)
這篇文章主要介紹了elementUI同一頁(yè)面展示多個(gè)Dialog的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-11-11vue中的this.$refs,this.$emit,this.$store,this.$nextTick的使用方式
這篇文章主要介紹了vue中的this.$refs,this.$emit,this.$store,this.$nextTick的使用方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-04-04深入理解Vue響應(yīng)式原理及其實(shí)現(xiàn)方式
Vue的響應(yīng)式原理是Vue最核心的特性之一,也是Vue能夠?yàn)殚_(kāi)發(fā)者提供高效便捷的開(kāi)發(fā)體驗(yàn)的重要原因之一,這篇文章主要介紹了響應(yīng)式的原理及其實(shí)現(xiàn)方式,需要詳細(xì)了解可以參考下文2023-05-05uni-app獲取當(dāng)前環(huán)境信息的方法
uni-aap提供了異步(uni.getSystemInfo)和同步(uni.getSystemInfoSync)的2個(gè)API獲取系統(tǒng)信息,這篇文章主要介紹了uni-app獲取當(dāng)前環(huán)境信息的相關(guān)知識(shí),需要的朋友可以參考下2022-11-11vue中對(duì)虛擬dom的理解知識(shí)點(diǎn)總結(jié)
在本篇文章里小編給大家整理了一篇關(guān)于vue中對(duì)虛擬dom的理解知識(shí)點(diǎn)總結(jié)內(nèi)容,有興趣的朋友們可以學(xué)習(xí)參考下。2021-06-06Vue路由傳參頁(yè)面刷新后參數(shù)丟失原因和解決辦法
這幾天在開(kāi)發(fā)中遇見(jiàn)的一個(gè)關(guān)于路由傳參后,頁(yè)面刷新數(shù)據(jù)丟失的問(wèn)題,下面這篇文章主要給大家介紹了關(guān)于Vue路由傳參頁(yè)面刷新后參數(shù)丟失原因和解決辦法,需要的朋友可以參考下2022-12-12vue項(xiàng)目實(shí)現(xiàn)img的src動(dòng)態(tài)賦值
這篇文章主要介紹了vue項(xiàng)目實(shí)現(xiàn)img的src動(dòng)態(tài)賦值方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-03-03