前言: 前天我們學了 ref 和 reactive ,提到了響應式數據和 Proxy ,那我們今天就來瞭解一下,vue3 的響應式 在瞭解之前,先複習一下之前 vue2 的響應式原理 vue2 的響應式: 原理: 對象類型:通過 Object.defineProperty() 對象的讀取,修改進行攔 ...
前言:
前天我們學了 ref 和 reactive ,提到了響應式數據和 Proxy ,那我們今天就來瞭解一下,vue3 的響應式
在瞭解之前,先複習一下之前 vue2 的響應式原理
vue2 的響應式:
原理:
對象類型:通過 Object.defineProperty() 對象的讀取,修改進行攔截,也就是數據劫持,響應式的根基
缺點:因為只有 讀取和修改(get,set)所以新增屬性,和刪除屬性,頁面是不會刷新的
數組類型:通過重寫,更新數組的一系列方法來實現攔截,假如你調了一個數組的 push 方法,其實 push 是被二次重寫封裝的(對數組的變更方法進行了重寫)
缺點:直接通過下標修改數組,頁面不會更新
解決方法:用 this.$set(數據,添加名字,添加內容),this.$delete(數據,刪除的數據名)
vue3 的響應式:
通過 Proxy 代理 :攔截對象中任意屬性的變化,包括增,刪,改,查
通過 Reflect 反射 : 對被代理對象(源對象)的屬性進行操作
new Proxy(data,{
//攔截讀取的屬性值
get(target,prop){
return Reflect.get(targert,prop)
}
//攔截設置和添加
set(target,prop,value){
return Reflect.set(targert,prop,value)
}
// 攔截刪除
deleteProperty(target,prop){
return Reflect.deleteProperty(targert,prop)
}
})
這差不多就是 vue3 響應式的簡單原理,Proxy 比較之前的 Object.defineProperty 功能更詳細,和強壯
reactive 與 ref 的區別:
定義:
ref:用來定義基本數據類型
reactive:用來定義對象(數組)類型數據
ps:ref 也可以用來定義對象(或數組)類型數據,內部求助了 reactive
原理:
ref: 通過 Object.defineProperty()的 get 與 set 來實現響應式也就是數據劫持
reactive:通過使用 Proxy 來實現響應式,並用 Reflect 操作源對象內部數據
使用:
ref:用 ref 定義的數據,操作需要 .value
reactive : 定義的數據,操作不需要
setup 的註意:
setup 的執行時機是在 beforeCreate 之前執行,this 是 undefined
setup 的參數:
props :值為對象,包含:組件外部傳遞過來,並且組件內部聲明接收了的屬性
context :上下文對象,有三個值分別是 attrs,slots,emit
attrs :對象,沒有在 props 聲明配置的屬性,相當於 vue2 的 this.$attrs
slots :插槽,相當於 this. $slots
emit :分發自定義事件的函數,相當於 this.$emit
計算屬性,computed函數
與 vue2 中的 computed 配置功能一致
watch 函數監聽:
與 vue2 中的 watch 配置功能一致
watch 監視 ref 基本數據:
情況一 :監視 ref 定義的一個響應式數據
let sum = ref(0)
watch(sum,(newValue,oldValue)=>{
console.log('監聽sum變了',newValue,oldValue)
})
情況二:監視 ref 定義的多個響應式數據
let msg = ref('你好啊')
let sum = ref(0)
watch([sum,msg],(newValue,oldValue)=>{
console.log('監聽sum變了',newValue,oldValue)
},{immediate:true})
ps:watch 一共可以傳遞三個值,第一個 監視的數據,監視的行為,watch 的配置
watch 監視 reactive 對象:
情況三:監視 reactive 所定義數據中的全部屬性
let preson = reactive({
name:'六扇老師',
age:18
})
watch(preson,(newValue,oldValue)=>{
console.log('監聽preson變了',newValue,oldValue)
},{deep:false}) // 此處的 deep 配置無效
ps:此處無法正確的獲得 oldValue,是 reactive 的問題無法解決
強制開啟深度監視( deep 配置無效)
情況四:監視 reactive 所定義數據中的某一個屬性
watch(()=>preson.name,(newValue,oldValue)=>{
console.log('監聽preson.name變了',newValue,oldValue)
})
情況五:監視 reactive 所定義數據中的某些屬性
watch([()=>preson.name,()=>preson.age],(newValue,oldValue)=>{
console.log('監聽preson.name/preson.age變了',newValue,oldValue)
})
特殊情況:
let preson = reactive({
name:'六扇老師',
age:18,
job:{
j1:{ salary:30 }
}
})
watch(()=>preson.job,(newValue,oldValue)=>{
console.log('監聽preson.job變了',newValue,oldValue)
},{deep:true})
ps:如果單獨監視 reactive 對象裡面的對象的數據,則必須開啟 deep:true 深度監視,否則監視無效
watchEffect 函數:
watchEffect 函數是 vue3 新增的一個函數
和 watch 區別:
watch:既要指明監視屬性,也要指明監視的回調
watchEffect :不用指明監視屬性,監視的回調中使用了那個屬性,就預設監視那幾個屬性
watchEffect 和 computed 有點像似
不一樣的是,computed 註重計算出來的值,回調函數的返回值,所以必須要寫返回值
watchEffect 更註重過程,回調函數的函數體,所以不用寫返回值
let sum = ref(0)
let preson = reactive({
name:'六扇老師',
age:18,
job:{
j1:{ salary:30 }
}
})
// watchEffect vue3 新增
// 預設開啟 immediate,也有 deep
watchEffect(()=>{
const x1 = sum.value const
x2 = preson.job.j1.salary
console.log('所指定的 watchEffect 的回調執行了')
})
vue2 和 vue3 生命周期對比:
vue2 開始不管你有沒有使用都會先執行倆個鉤子,然後才會去判斷,vue3 則不會得明確得告訴 app 你服務於那個容器,才開始走,更智能了
剩下得生命周期都相差不多,但在 vue3 里用 beforeUnmount (卸載之前)和 unmounted (卸載完畢)替換了 beforeDestroy (銷毀之前) 和 destroyed (銷毀完畢),和 react 像似了
組合式 api 裡面的生命周期:
用組合式 api 往 setup 裡面寫的生命周期,這種寫法不見得非要用,只是瞭解就行,問題不大
beforeCreate | setup |
created | setup |
beforeCreate 和 created 這倆鉤子 vue3 並沒有給我們提供組合式 api ,放不進去 setup,setup 就相當於他們倆個
beforeMount | onbeforeMount |
mounted | onmounted |
beforeUpdate | onbeforeUpdate |
updated | onupdated |
beforeUnmount | onbeforeUnmount |
unmounted | onunmounted |
就是在之前的生命周期,加上一個 on,而且 setup 的優先順序更高
自定義 hook 函數:
hook 本質是一個函數,把 setup 函數中使用的 組合式 API 進行了自定義封裝
類似於 vue2 中的 mixin
自定義 hook 復用代碼,可以讓 setup 中的邏輯更清楚,更容易懂,更簡單
toRef:
創建一個 ref 對象,其 value 值指向另一個對象中的某個屬性
回到我們之前的代碼
可以看到頁面上,想要獲取數據,就要 preson 點什麼什麼一大堆,看著也不美觀,這時候就要用到 toRef 了
toRef 語法 : const name = toRef (preson ,‘nama’) 第一個參數對象,第二個是對象里的那個值
toRefs:
toRef 的升級版,可以批量處理一個對象里的所有屬性
以上就是我們常用的組合式 API 了,知道了這些差不多就完成了一個 vue3 的入門,明天我們開始學習一些不常用的組合式 API ,雖然不常用當還是要瞭解滴,所以我們明天再見