詳解vue2和vue3如何定義響應(yīng)式數(shù)據(jù)
響應(yīng)式原理
Vue2和Vue3的響應(yīng)式實(shí)現(xiàn)原理是不同的
Vue2底層是通過es5的Object.defineProperty,使用Object.defineProperty()進(jìn)行數(shù)據(jù)劫持,結(jié)合訂閱發(fā)布的方式實(shí)現(xiàn),有一定的局限性。Vue3底層是通過es6的Porxy, 通過Proxy代理,使用ref或者reactive將數(shù)據(jù)轉(zhuǎn)化為響應(yīng)式數(shù)據(jù),能夠更好地支持動(dòng)態(tài)添加屬性和刪除屬性。它解決了Vue2底層實(shí)現(xiàn)的缺點(diǎn),對(duì)數(shù)組、層級(jí)比較深的對(duì)象處理都很優(yōu)秀,但缺點(diǎn)是瀏覽器兼容不是很好。
Vue2的響應(yīng)式數(shù)據(jù)
在Vue2中,是使用選項(xiàng)式API的方式來(lái)編寫代碼,比如data()、computed()、watch等方法實(shí)現(xiàn)響應(yīng)式
Vue3的響應(yīng)式數(shù)據(jù)
reactive和ref
reactive
reactive定義引用數(shù)據(jù)類型(以對(duì)象和數(shù)組舉例),它能夠?qū)?fù)雜數(shù)據(jù)類型的內(nèi)部屬性或者數(shù)據(jù)項(xiàng)聲明為響應(yīng)式數(shù)據(jù),所以reactive的響應(yīng)式是深層次的,其底層是通過ES6的Proxy來(lái)實(shí)現(xiàn)數(shù)據(jù)響應(yīng)式,相對(duì)于Vue2的Object.defineProperty,具有能監(jiān)聽增刪操作,能監(jiān)聽對(duì)象屬性的變化等優(yōu)點(diǎn)
- reactive是一個(gè)函數(shù),它可以定義一個(gè)復(fù)雜數(shù)據(jù)類型,成為響應(yīng)式數(shù)據(jù);
- 通常用來(lái)定義響應(yīng)式的對(duì)象數(shù)據(jù)。
<template>
<div>name:{{obj.name}}</div>
<button @click="updateName">修改name</button>
</template>
<script>
import { reactive } from 'vue'
export default {
setup() {
// 定義響應(yīng)式對(duì)象
const obj = reactive({
name: 'lisi',
age:20
})
const updateName = () => {
obj.name = '我是修改后的name'
console.log('我是按鈕..........');
};
return {
obj,
updateName
}
}
}
</script>
ref函數(shù)
ref函數(shù),常用于簡(jiǎn)單數(shù)據(jù)類型定義為響應(yīng)式數(shù)據(jù),其實(shí)也可以定義復(fù)雜數(shù)據(jù)類型的響應(yīng)式數(shù)據(jù),對(duì)于數(shù)據(jù)未知的情況下ref是最適用的。
在修改值,獲取值的時(shí)候,需要.value。在模板中使用ref申明的響應(yīng)式數(shù)據(jù),可以省略.value,在js代碼中修改ref聲明的數(shù)據(jù),需要加上.value。
<template>
<div>name:{{name}}</div>
<button @click="changeName">修改name</button>
</template>
<script>
import { ref } from 'vue'
export default {
setup() {
const name = ref('zhangsan');
const changeName = () => {
name.value = 'lisi'
}
return {
name,
changeName
}
}
}
</script>
兩者的不同
- ref用于定義基本類型和引用類型,reactive僅用于定義引用類型
- reactive只能用于定義引用數(shù)據(jù)類型的原因在于內(nèi)部是通過ES6的Proxy實(shí)現(xiàn)響應(yīng)式的,而Proxy不適用于基本數(shù)據(jù)類型
- ref定義對(duì)象時(shí),底層會(huì)通過reactive轉(zhuǎn)換成具有深層次的響應(yīng)式對(duì)象,所以ref本質(zhì)上是reactive的再封裝(會(huì)判斷數(shù)據(jù)的類型進(jìn)行不同處理)
- 在腳本里使用ref定義的數(shù)據(jù)時(shí),記得加.value后綴
- 在定義數(shù)組時(shí),建議使用ref,從而可避免reactive定義時(shí)值修改導(dǎo)致的響應(yīng)式丟失問題
const tableData = reactive([]) // 定義
const getTableData = async () => {
const { data } = await getTableDataApi() // 模擬接口獲取表格數(shù)據(jù)
tableData = data // 修改,錯(cuò)誤示例,這樣賦值會(huì)使tableData失去響應(yīng)式
}
// 方法一:改為 ref 定義
const tableData = ref([])
const getTableData = async () => {
const { data } = await getTableDataApi()
tableData.value = data // 使用.value重新賦值
}
// 方法二:使用 push 方法
const tableData = reactive([])
const getTableData = async () => {
const { data } = await getTableDataApi()
tableData.push(...data) // 先使用...將data解構(gòu),再使用push方法
}
// 方法三:定義時(shí)數(shù)組外層嵌套一個(gè)對(duì)象
const tableData = reactive({ list:[] })
const getTableData = async () => {
const { data } = await getTableDataApi()
tableData.list = data // 通過訪問list屬性重新賦值
}
// 方法四:賦值前再包一層 reactive
const tableData = reactive([])
const getTableData = async () => {
const { data } = await getTableDataApi()
tableData = reactive(data) // 賦值前再包一層reactive
}為什么需要兩個(gè)
雖然ref函數(shù)既可以處理基本數(shù)據(jù)類型也可以處理引用數(shù)據(jù)類型,但是在普通js代碼里修改該響應(yīng)式數(shù)據(jù)的值時(shí)需要使用.value的寫法,會(huì)存在.value的嵌套問題,因此使用reactive來(lái)處理引用數(shù)據(jù)類型,避免該問題。
toRef和toRefs
ref是對(duì)元數(shù)據(jù)的拷貝,修改響應(yīng)式數(shù)據(jù)時(shí)不會(huì)影響之前的數(shù)據(jù),視圖會(huì)更新。tooRef和toRefs是對(duì)元數(shù)據(jù)的引用,修改響應(yīng)式數(shù)據(jù)時(shí),原數(shù)據(jù)也會(huì)改變,但是視圖不會(huì)更新,只有原始數(shù)據(jù)改變后,該數(shù)據(jù)和視圖都會(huì)更新。toRef修改的是對(duì)象的某個(gè)屬性,toRefs修改的是整個(gè)對(duì)象
toRef
toRef 函數(shù)的作用:轉(zhuǎn)換響應(yīng)式對(duì)象中某個(gè)屬性為單獨(dú)響應(yīng)式數(shù)據(jù),并且轉(zhuǎn)換后的值和之前是關(guān)聯(lián)的(ref 函數(shù)也可以轉(zhuǎn)換,但值非關(guān)聯(lián))。
<template>
<div class="container">
<h2>name: {{ obj.name }} age: {{obj.age}}</h2>
<button @click="updateName">修改數(shù)據(jù)</button>
</div></template><script>
import { reactive } from 'vue'
export default {
name: 'App',
setup() {
const obj = reactive({
name: '初映',
age: 18,
address: '江西',
sex: '男',
})
const updateName = () => {
obj.name = '初映CY的前說(shuō)'
}
return { obj, updateName }
},
}</script>
這樣寫有幾個(gè)問題:
- 模板中都要使用 obj. 進(jìn)行獲取數(shù)據(jù),較為麻煩
- 明明模板中只用到了 name 和 age,卻把整個(gè) obj 進(jìn)行了導(dǎo)出,沒必要,性能浪費(fèi)。
使用toRef進(jìn)行修改,只需要將需要的屬性return出去即好,且模板中也不需要加obj.前綴了。
<template>
<div class="container">
<h2>name: {{ name }} </h2>
<button @click="updateName">修改數(shù)據(jù)</button>
</div></template><script>
import { reactive,toRef } from 'vue'
export default {
name: 'App',
setup() {
const obj = reactive({
name: '初映',
age: 18,
address: '江西',
sex: '男',
})
const name = toRef(obj, 'name')
const updateName = () => {
obj.name = '初映CY的前說(shuō)'
}
return { name, updateName }
},
}</script>
toRefs
toRefs 函數(shù)的作用:轉(zhuǎn)換響應(yīng)式對(duì)象中所有屬性為單獨(dú)響應(yīng)式數(shù)據(jù),并且轉(zhuǎn)換后的值和之前是關(guān)聯(lián)的。
<template>
<div>{{name}}</div>
<div>{{age}}</div>
<button @click="update">修改name</button>
</template>
<script>
import {reactive, toRefs} from 'vue'
export default {
setup() {
const obj = reactive({
name: '張三',
age:18
})
console.log(obj);
const obj2 = toRefs(obj);
console.log(obj2); //發(fā)現(xiàn)obj2里面的name和age都是響應(yīng)式屬性,指向obj的屬性
// 解構(gòu)之后重新賦值的是普通對(duì)象
const obj3 = { ...obj };
console.log(obj3);
const update =()=> {
obj.name = '我是修改的原始數(shù)據(jù)的obj'
}
return {
// 解構(gòu)obj2,用的時(shí)候直接拿屬性名,不需要obj2.name或obj2.age
...obj2,
update
}
}
}
</script>
修改原始數(shù)據(jù)obj后會(huì)發(fā)現(xiàn),轉(zhuǎn)換過后的obj2中的值會(huì)跟著改變。
以上就是詳解vue2和vue3如何定義響應(yīng)式數(shù)據(jù)的詳細(xì)內(nèi)容,更多關(guān)于vue定義響應(yīng)式數(shù)據(jù)的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
vue 使用moment獲取當(dāng)前時(shí)間及一月前的時(shí)間
開發(fā)中會(huì)有要獲取當(dāng)前日期的需求,有的是獲取到當(dāng)前月份,本文就介紹了vue獲取當(dāng)前日期時(shí)間(moment、new?Date()),文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2023-08-08
vue動(dòng)畫—通過鉤子函數(shù)實(shí)現(xiàn)半場(chǎng)動(dòng)畫操作
這篇文章主要介紹了vue動(dòng)畫—通過鉤子函數(shù)實(shí)現(xiàn)半場(chǎng)動(dòng)畫操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來(lái)看看吧2020-08-08
VUE使用ElementUI下拉框 @change事件數(shù)據(jù)不回顯問題
這篇文章主要介紹了VUE使用ElementUI下拉框 @change事件數(shù)據(jù)不回顯問題。具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-02-02
Vue出現(xiàn)did you register the component 
這篇文章主要介紹了Vue出現(xiàn)did you register the component correctly?解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-03-03
Vue中watch監(jiān)聽屬性新舊值相同的問題解決方案
這篇文章主要給大家分享了Vue中watch監(jiān)聽屬性新舊值相同問題解決方案,如果有遇到相同問題的朋友,可以參考閱讀本文2023-08-08

