詳解vue2和vue3如何定義響應(yīng)式數(shù)據(jù)
響應(yīng)式原理
Vue2和Vue3的響應(yīng)式實(shí)現(xiàn)原理是不同的
Vue2
底層是通過(guò)es5
的Object.defineProperty
,使用Object.defineProperty()進(jìn)行數(shù)據(jù)劫持,結(jié)合訂閱發(fā)布的方式實(shí)現(xiàn),有一定的局限性。Vue3
底層是通過(guò)es6
的Porxy
, 通過(guò)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)編寫(xiě)代碼,比如data()、computed()、watch等方法實(shí)現(xiàn)響應(yīng)式
Vue3的響應(yīng)式數(shù)據(jù)
reactive和ref
reactive
reactive定義引用數(shù)據(jù)類(lèi)型(以對(duì)象和數(shù)組舉例),它能夠?qū)?fù)雜數(shù)據(jù)類(lèi)型的內(nèi)部屬性或者數(shù)據(jù)項(xiàng)聲明為響應(yīng)式數(shù)據(jù),所以reactive的響應(yīng)式是深層次的,其底層是通過(guò)ES6的Proxy來(lái)實(shí)現(xiàn)數(shù)據(jù)響應(yīng)式,相對(duì)于Vue2的Object.defineProperty,具有能監(jiān)聽(tīng)增刪操作,能監(jiān)聽(tīng)對(duì)象屬性的變化等優(yōu)點(diǎn)
- reactive是一個(gè)函數(shù),它可以定義一個(gè)復(fù)雜數(shù)據(jù)類(lèi)型,成為響應(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ù)類(lèi)型定義為響應(yīng)式數(shù)據(jù),其實(shí)也可以定義復(fù)雜數(shù)據(jù)類(lèi)型的響應(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用于定義基本類(lèi)型和引用類(lèi)型,reactive僅用于定義引用類(lèi)型
- reactive只能用于定義引用數(shù)據(jù)類(lèi)型的原因在于內(nèi)部是通過(guò)ES6的Proxy實(shí)現(xiàn)響應(yīng)式的,而Proxy不適用于基本數(shù)據(jù)類(lèi)型
- ref定義對(duì)象時(shí),底層會(huì)通過(guò)reactive轉(zhuǎn)換成具有深層次的響應(yīng)式對(duì)象,所以ref本質(zhì)上是reactive的再封裝(會(huì)判斷數(shù)據(jù)的類(lèi)型進(jìn)行不同處理)
- 在腳本里使用ref定義的數(shù)據(jù)時(shí),記得加.value后綴
- 在定義數(shù)組時(shí),建議使用ref,從而可避免reactive定義時(shí)值修改導(dǎo)致的響應(yīng)式丟失問(wèn)題
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 // 通過(guò)訪問(wèn)list屬性重新賦值 } // 方法四:賦值前再包一層 reactive const tableData = reactive([]) const getTableData = async () => { const { data } = await getTableDataApi() tableData = reactive(data) // 賦值前再包一層reactive }
為什么需要兩個(gè)
雖然ref函數(shù)既可以處理基本數(shù)據(jù)類(lèi)型也可以處理引用數(shù)據(jù)類(lèi)型,但是在普通js代碼里修改該響應(yīng)式數(shù)據(jù)的值時(shí)需要使用.value
的寫(xiě)法,會(huì)存在.value
的嵌套問(wèn)題,因此使用reactive
來(lái)處理引用數(shù)據(jù)類(lèi)型,避免該問(wèn)題。
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>
這樣寫(xiě)有幾個(gè)問(wèn)題:
- 模板中都要使用 obj. 進(jìn)行獲取數(shù)據(jù),較為麻煩
- 明明模板中只用到了 name 和 age,卻把整個(gè) obj 進(jìn)行了導(dǎo)出,沒(méi)必要,性能浪費(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)換過(guò)后的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?element樹(shù)形控件添加虛線(xiàn)詳解
這篇文章主要為大家介紹了Vue?element樹(shù)形控件添加虛線(xiàn),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來(lái)幫助<BR>2021-11-11解決vue2.0 element-ui中el-upload的before-upload方法返回false時(shí)submit(
這篇文章主要介紹了vue2.0 element-ui中el-upload的before-upload方法返回false時(shí)submit()不生效的解決方法,這里需要主要項(xiàng)目中用的element-ui是V1.4.3,感興趣的朋友參考下吧2018-08-08Vue?element-ui?el-cascader?只能末級(jí)多選問(wèn)題
這篇文章主要介紹了Vue?element-ui?el-cascader?只能末級(jí)多選問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-09-09