vue中Vue.set()的使用以及對其進行深入解析
Vue.set()使用
vue 在實例上添加新的屬性的時候,該屬性,并不是響應式的。同樣刪除某一屬性的時候,也不會實時渲染到頁面上。
比如:
<p> 年齡:{{obj.age? obj.age: "無"}}</p>
···········
data() {
return {
obj:{ name:"Lena", id:1 },
}
}
頁面上 顯示的是 年齡:無 現(xiàn)在需要添加一個響應式的屬性 age 。
<template> <div class="app"> <ul> <li> 年齡:{{obj.age? obj.age: "無"}}</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>
效果:
通過 this.obj.age= 20 ,控制臺打印已經(jīng)有了該屬性,并沒有渲染到頁面上。 可見,這種方式添加的屬性 age 并不是響應式的。
使用Vue.set() ,更改add()方法:
add(){ Vue.set(this.obj,'age', '20') },
效果:
因為vue不能檢測到對象屬性的添加或者刪除,只有在data對象上存在的屬性是響應式的,所以要使用Vue.set()方法將響應式屬性添加到對象上。同樣的道理,刪除對象 Vue.delete也是如此。
Vue.delete()的使用
<template> <div class="app"> <ul> <li> 年齡:{{obj.age? obj.age: "無"}}</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() 方法如果是下面兩種,同樣不是響應式的。
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 }
對象調(diào)用:Vue.set( target ,'age', 20 )
數(shù)組調(diào)用:Vue.set( array , 0, 20 ) //數(shù)組對象,索引,值
首先是判斷是否是開發(fā)環(huán)境并且 對象是否被定義isUndef(target)或者是否是基礎(chǔ)類型isPrimitive(target),否則會報錯:
`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)用重寫的splice()方法,可以更新視圖。
isValidArrayIndex(key)方法用來驗證是否是一個有效的數(shù)組索引, 其實就是驗證是否是一個非無窮大的正整數(shù)。
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 ? }
如果是Vue實例,或者是根數(shù)據(jù)data的時候,就會報錯。
如果本身就不是響應式的,只需要直接賦值即可。
const ob = (target: any).__ob__ //如果是Vue實例,或者是根數(shù)據(jù)data的時候,就會報錯。 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
排除各種不合適的,最后給當前對象定義一個屬性:defineReactive(ob.value, key, val) 相當于用了 Object.defineProperty 重新定義了一下。
最后,手動通知視圖更新:ob.dep.notify()
總結(jié)
這個 set方法,對于數(shù)組來說,調(diào)用的就是splice,對于對象來說,使用的就是defineReactive,再添加了一個手動的視圖更新。這就是set的原理。
到此這篇關(guān)于vue中Vue.set()的使用以及對其進行深入解析的文章就介紹到這了,更多相關(guān)vue Vue.set()的使用內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
vue-cli 打包后提交到線上出現(xiàn) "Uncaught SyntaxError:Unexpected token" 報
這篇文章主要介紹了vue-cli 打包后提交到線上出現(xiàn) "Uncaught SyntaxError:Unexpected token" 報錯,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2018-11-11elementUI同一頁面展示多個Dialog的實現(xiàn)
這篇文章主要介紹了elementUI同一頁面展示多個Dialog的實現(xiàn),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2020-11-11vue中的this.$refs,this.$emit,this.$store,this.$nextTick的使用方式
這篇文章主要介紹了vue中的this.$refs,this.$emit,this.$store,this.$nextTick的使用方式,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2024-04-04