建設(shè)好網(wǎng)站靠什么賺錢適合40歲女人的培訓(xùn)班
文章目錄
- 1、Vue3中為什么修改變量的值后,視圖不更新?
- 2、使用 ref 還是 reactive?
- 3、reactive 為什么會(huì)有響應(yīng)性連接丟失情況?
- 4、watch的不同使用方法
- 5、watchEffect和 watch 的區(qū)別
- 區(qū)別1:數(shù)據(jù)源的區(qū)別
- 區(qū)別2:獲取新值和舊值的區(qū)別
- 區(qū)別3:惰性執(zhí)行和非惰性(立即)執(zhí)行的區(qū)別
- 6、watchEffect和 watch 使用注意點(diǎn)
- 7、使用ref修改DOM元素
1、Vue3中為什么修改變量的值后,視圖不更新?
<template><div>app</div><div class="container">{{ msg1 }}{{ msg2 }}</div><button @click="say()">按鈕</button>
</template><script setup>
import { reactive, ref } from 'vue'let msg1 = 'hi'
let msg2 = ref('hello')
const say = () => {console.log(msg1) // himsg1 = 'hi vue3' // 這里修改 msg1的值,console.log('msg1', msg1) // 這里可以獲取到修改后的值,hi vue3,但是視圖中的 msg1 沒有更新,原因是 msg1不是響應(yīng)式的。msg2.value = 'hello vue3 ' // 這里修改 msg2的值console.log('msg2', msg2) // 這里可以獲取到修改后的值,hello vue3,視圖中的 msg2 也會(huì)更新,原因是 msg2是響應(yīng)式的。
}
</script>
2、使用 ref 還是 reactive?
reactive
可以轉(zhuǎn)換【復(fù)雜數(shù)據(jù)類型】(例如:對(duì)象、數(shù)組等) 成為響應(yīng)式數(shù)據(jù),但是不支持簡(jiǎn)單數(shù)據(jù)類型(例如:字符串、數(shù)值、布爾值);ref
可以轉(zhuǎn)換【簡(jiǎn)單數(shù)據(jù)類型】或【復(fù)雜數(shù)據(jù)類型】 為響應(yīng)式數(shù)據(jù),但是操作的時(shí)候需要.value
。
如果能確定數(shù)據(jù)是復(fù)雜數(shù)據(jù)類型,并且定義的屬性也是知道的,則可以使用 reactive
轉(zhuǎn)成響應(yīng)式數(shù)據(jù),如果不滿足以上條件,則使用 ref
。
代碼如下:
// 1. 明確login對(duì)象有兩個(gè)字段,需要使用 reactiveconst login = reactive({username: '',password: ''})// 2. 后臺(tái)返回的數(shù)據(jù)對(duì)象const data = ref(null)const res = await axios.get('/login')data.value = res.data // 把不是響應(yīng)式的 res 賦值給 響應(yīng)式data中的value,data仍然是響應(yīng)式的。// 3. 思考:為什么以下方式不可行?const data = reactive({ })const res = await axios.get('/login')data = res // 由于res 不是響應(yīng)式的,然后把不是響應(yīng)式的 res 賦值給 響應(yīng)式的data ,那么data就不是響應(yīng)式的了。
3、reactive 為什么會(huì)有響應(yīng)性連接丟失情況?
響應(yīng)性連接丟失的意思是:一個(gè)響應(yīng)式對(duì)象原本是響應(yīng)式的,但隨意通過 “賦值”操作,把一個(gè)非響應(yīng)式的數(shù)據(jù),賦值給響應(yīng)式的數(shù)據(jù)對(duì)象,這個(gè)響應(yīng)式對(duì)象就變成了非響應(yīng)式數(shù)據(jù)對(duì)象了。
reactive
API有兩個(gè)限制性情況:
-
情況1:
reactive
僅支持復(fù)雜數(shù)據(jù)類型(對(duì)象、數(shù)組等),對(duì)簡(jiǎn)單數(shù)據(jù)類型(字符串、數(shù)值、布爾值)等原始類型不支持。 -
情況2:因?yàn)閂ue 的響應(yīng)式系統(tǒng)是通過屬性訪問進(jìn)行跟蹤的,必須始終保持對(duì)該響應(yīng)式對(duì)象的相同引用。所以不可以隨意地“替換(賦值)”一個(gè)響應(yīng)式對(duì)象,因?yàn)檫@將導(dǎo)致對(duì)初始引用的響應(yīng)性連接丟失。
也就是說:如果重新賦值或解構(gòu)賦值,就會(huì)丟失原來響應(yīng)式對(duì)象的引用地址,然后變成了一個(gè)新的引用地址,因?yàn)檫@個(gè)新的引用地址指向的對(duì)象是沒有經(jīng)過
reactive
處理的,所以就是一個(gè)普通對(duì)象,而不是響應(yīng)式對(duì)象。
? 響應(yīng)性連接丟失 代碼舉例1:
const data = reactive({ })const res = await axios.get('/login')data = res // 由于res 不是響應(yīng)式的,然后把不是響應(yīng)式的 res 賦值給 響應(yīng)式的data ,那么data就不是響應(yīng)式的了
? 響應(yīng)性連接丟失 代碼舉例2:
// 將響應(yīng)式對(duì)象的屬性直接賦值或解構(gòu)賦值時(shí),或是將該屬性傳入一個(gè)函數(shù)時(shí),也會(huì)失去響應(yīng)性連接let dataCount = reactive({ count: 0 })// 響應(yīng)式對(duì)象的屬性直接賦值時(shí),響應(yīng)式對(duì)象的屬性響應(yīng)性連接丟失,也就是說:dataCount.count 失去響應(yīng)式連接,但不會(huì)影響 dataCount (dataCount仍然是響應(yīng)式數(shù)據(jù)對(duì)象)
let num = dataCount.count // 響應(yīng)式對(duì)象的屬性值 直接賦值給了 num
num++// 響應(yīng)式對(duì)象屬性解構(gòu)時(shí),響應(yīng)式對(duì)象屬性(dataCount.count)響應(yīng)性連接丟失,但不會(huì)影響 dataCount
let { count } = dataCount // 響應(yīng)式對(duì)象的屬性解構(gòu)賦值
count++// change函數(shù)接收一個(gè)普通數(shù)字,將無法跟蹤 dataCount.count 的變化, dataCount.count失去響應(yīng)性連接
const change = (item) => {console.log(item)
}
change(dataCount.count)
4、watch的不同使用方法
watch
第一個(gè)參數(shù):不同形式的數(shù)據(jù)源,
- 可以是 ref(含計(jì)算屬性)
- 一個(gè)getter函數(shù)
- 一個(gè)響應(yīng)式對(duì)象
- 或多個(gè)數(shù)據(jù)源組成的數(shù)組。
注意: watch不能偵聽到響應(yīng)式對(duì)象的屬性值,比如:watch(data.count,()=>{ })
,可以提供一個(gè)getter函數(shù)進(jìn)行返回響應(yīng)式對(duì)象的屬性值。
watch
第二個(gè)參數(shù):回調(diào)函數(shù),當(dāng)數(shù)據(jù)源發(fā)生變化時(shí),執(zhí)行回調(diào)函數(shù)
watch
第三個(gè)參數(shù)【可選】:是一個(gè)配置項(xiàng),
deep
用于強(qiáng)制深度遍歷immediate
用于立即執(zhí)行第二個(gè)參數(shù)中的回調(diào)函數(shù)flush
用于調(diào)整回調(diào)函數(shù)的刷新時(shí)機(jī)onTrack / onTrigger
調(diào)試偵聽器的依賴
watch
的五種不同使用方法如下:
<template><div>app</div><div>{{ count }}</div><button @click="count++">累加</button>
</template><script setup>
import { ref, reactive, watch } from 'vue'const count = ref(0)
const obj = reactive({name: 'xiaozhu',age: 18,info: {height: 180,weight: 70,},
})// 使用方法1:第一個(gè)參數(shù)為 ref
watch(count, (newVal, oldVal) => {console.log('newVal', newVal) // 累加后 新的值console.log('oldVal', oldVal) // 累加前 舊的值
})// 使用方法2:第一個(gè)參數(shù)為 getter函數(shù)
watch(() => obj.age,(newVal, oldVal) => {console.log('newVal', newVal) // 20console.log('oldVal', oldVal) // 18}
)
setTimeout(() => {obj.age = 20
}, 1000)// 使用方法3:第一個(gè)參數(shù)為 一個(gè)響應(yīng)式對(duì)象中的 簡(jiǎn)單數(shù)據(jù)類型
watch(() => obj.name, // name為obj對(duì)象中的一個(gè)字符串類型(newVal, oldVal) => {console.log('改變了')console.log('obj.name', obj.name) // 筱竹console.log('newVal', newVal) // 筱竹console.log('oldVal', oldVal) // xiaozhu}
)
setTimeout(() => {obj.name = '筱竹'
}, 1000)// 使用方法4:第一個(gè)參數(shù)為 一個(gè)響應(yīng)式對(duì)象中的 復(fù)雜數(shù)據(jù)類型時(shí),需要開啟深度監(jiān)聽(設(shè)置deep選項(xiàng))
watch(() => obj.info, // info 為obj對(duì)象中的一對(duì)象類型(newVal, oldVal) => {console.log('obj.info.height', obj.info.height) // 筱竹console.log('newVal', newVal) // 筱竹console.log('oldVal', oldVal) // xiaozhu},{ deep: true } // 開啟深度監(jiān)聽
)
setTimeout(() => {obj.info.height = 175
}, 1000)// 使用方法5:第一個(gè)參數(shù)為 多個(gè)數(shù)據(jù)源組成的數(shù)組
watch([count, obj], () => {console.log('count.value', count.value) // 點(diǎn)擊 累加按鈕后,count+1console.log('obj.info.weight', obj.info.weight) // 65
})
setTimeout(() => {obj.info.weight = 65
}, 1000)
</script>
5、watchEffect和 watch 的區(qū)別
區(qū)別1:數(shù)據(jù)源的區(qū)別
watch
是需要偵聽一個(gè)數(shù)據(jù)源(ref
、響應(yīng)式對(duì)象等),當(dāng)依賴數(shù)據(jù)更新時(shí)執(zhí)行回調(diào)函數(shù);watchEffect
不需要設(shè)置偵聽的數(shù)據(jù)源,而是自動(dòng)收集依賴數(shù)據(jù),當(dāng)依賴數(shù)據(jù)更新時(shí)會(huì)立即執(zhí)行回調(diào)函數(shù)
<template><div>app</div><div>{{ count }}</div><button @click="count++">累加</button>
</template><script setup>
import { ref, reactive, watch, watchEffect } from 'vue'const count = ref(0)// watchEffect 和 watch 區(qū)別1:// watchEffect 不需要設(shè)置偵聽的數(shù)據(jù)源,就可以自動(dòng)收集依賴(以下可以自動(dòng)收集 ref 數(shù)據(jù)源)
watchEffect(() => {console.log('count.value', count.value)
})// watch 需要設(shè)置偵聽的數(shù)據(jù)源,只有設(shè)置了數(shù)據(jù)源,才能偵聽數(shù)據(jù)源的變化
watch(count, (newVal, oldVal) => {console.log('newVal', newVal) console.log('oldVal', oldVal)
})
</script>
區(qū)別2:獲取新值和舊值的區(qū)別
watch
在回調(diào)函數(shù)中獲取到 新值(變化后的值)和 舊值(變化之前的值);watchEffect
在回調(diào)函數(shù)中 只可以獲取到新值(變化后的值),不能獲取到 舊值(變化之前的值);
// watchEffect 和 watch 區(qū)別2:// watchEffect 只能拿到 新值
watchEffect(() => {console.log('count.value', count.value) // 只能拿到 新值
})// watch 可以獲取到 新值和 舊值
watch(count, (newVal, oldVal) => {console.log('newVal', newVal) // 累加后 新的值console.log('oldVal', oldVal) // 累加前 舊的值
})
區(qū)別3:惰性執(zhí)行和非惰性(立即)執(zhí)行的區(qū)別
watch
的回調(diào)函數(shù)具有一定的惰性 當(dāng)?shù)谝淮雾撁嬲故镜臅r(shí)候不會(huì)執(zhí)行,只有數(shù)據(jù)變化的時(shí)候才會(huì)執(zhí)行(設(shè)置immediate
選項(xiàng)為true時(shí)可以變?yōu)榉嵌栊?#xff08;可以立即執(zhí)行),頁面首次加載就會(huì)執(zhí)行;watchEffect
的回調(diào)函數(shù)可以立即執(zhí)行,沒有惰性,頁面的首次加載就會(huì)執(zhí)行;
// watchEffect 和 watch 區(qū)別3:
const todoId = ref(1)
const data = ref(null)// watchEffect 中的回調(diào)函數(shù)會(huì)立即執(zhí)行,不需要指定 immediate: true
watchEffect(async () => {const response = await fetch(`https://jsonplaceholder.typicode.com/todos/${todoId.value}`)data.value = await response.json()
})// 在 watch 中想要立即執(zhí)行回調(diào)函數(shù),就需要 設(shè)置 immediate: true
// watch 默認(rèn)是惰性的:僅當(dāng)數(shù)據(jù)源變化時(shí),才會(huì)執(zhí)行回調(diào)。但在某些場(chǎng)景中,我們希望在創(chuàng)建偵聽器時(shí),立即執(zhí)行一遍回調(diào)。舉例來說,我們想請(qǐng)求一些初始數(shù)據(jù),然后在相關(guān)狀態(tài)更改時(shí)重新請(qǐng)求數(shù)據(jù)。
watch(todoId,async () => {const response = await fetch(`https://jsonplaceholder.typicode.com/todos/${todoId.value}`)data.value = await response.json()},{ immediate: true }
)
6、watchEffect和 watch 使用注意點(diǎn)
【注意點(diǎn)1】: 偵聽器必須用同步語句創(chuàng)建:如果用異步回調(diào)創(chuàng)建一個(gè)偵聽器,那么它不會(huì)綁定到當(dāng)前組件上,必須手動(dòng)停止偵聽,以防止內(nèi)存泄漏。例如:
// 它會(huì)自動(dòng)停止 ( watch同理 )
watchEffect(() => {})// 這個(gè)則不會(huì)! ( watch同理 )
setTimeout(() => {watchEffect(() => {})
}, 100)// 要手動(dòng)停止一個(gè)偵聽器,請(qǐng)調(diào)用 watch 或 watchEffect 返回的函數(shù):
const unwatch = watchEffect(() => {})// 當(dāng)該偵聽器不再需要時(shí)
unwatch()
【注意點(diǎn)2】: 需要異步創(chuàng)建偵聽器的情況很少,請(qǐng)盡可能選擇同步創(chuàng)建,如果需要等待一些異步數(shù)據(jù),你可以使用條件式的偵聽邏輯:
// 需要異步請(qǐng)求得到的數(shù)據(jù)
const info = ref(null)watchEffect(() => {if (info.value) {// 數(shù)據(jù)加載后執(zhí)行某些操作...}
})
7、使用ref修改DOM元素
<template><div ref="ref_item">app</div><input type="button" value="修改DOM元素" @click="change()" />
</template><script setup>
import { ref, onMounted } from 'vue'const ref_item = ref(null)// 注意: 獲取元素需要在Vue3 生命周期鉤子 onMounted中獲取,如果在 setup 中是獲取不到的,因?yàn)閟etup中類似Vue2聲明周期鉤子函數(shù)中的beforeCreate和 created ,此時(shí)DOM還沒生成,所以獲取不到DOM。
onMounted(() => {// 獲取DOM元素console.log('ref_item.value.innerText', ref_item.value.innerText) // app
})const change = () => {// 修改DOM元素的值ref_item.value.innerText = '你好 Vue3'console.log('ref_item.value.innerText', ref_item.value.innerText) // 你好 Vue3
}
</script>