背景
關於vue3.0已經出來很久了,但是一直沒有嚐鮮,最近時間充裕一點,就開始梳理下相關新特性,也當作是一個學習歷程。
1. globalProperties
公共變量或者方法得定義
// main.js
const app = createApp(App)
app.config.globalProperties.heimayu = 'hi heimayu you are prefect!'
app.mount('#app')
// vue
<template>
<h1>{{helloword}}</h1>
</template>
<script>
import { getCurrentInstance } from 'vue'
export default {
setup () {
const { proxy } = getCurrentInstance();
const helloword = proxy.heimayu;
return {
helloword
}
}
}
</script>
2 ref 和 reactive
ref
作用:定義一個響應式數據
使用:JS中操作數據:xxx.value=xxx; 模板中使用直接{{xxx}}
reactive
作用:定義一個響應式對象
使用:JS中操作數據和模板中都直接使用
<template>
<h1>{{nameRef}}</h1>
<h1>{{student.nameForm.nameReactive}}</h1>
<button @click="changeName">修改</button>
</template>
<script setup>
import { reactive, ref } from 'vue'
let nameRef = ref('hi, heimayu!')
let student = reactive({
nameForm: {
nameReactive: 'hi yaoyao!'
}
})
const changeName = () => {
nameRef.value = 'hi, heimayu!' + new Date().getTime();
student.nameForm.nameReactive = 'hi yaoyao!' + new Date().getTime();
}
</script>
3 watch與watchEffect
watch
還是上面的例子,會發現監視reactive的數據時候,是無法獲取oldValue的,即2個value下的屬性是一樣!
watch(student, (newValue, oldValue) => {
console.log("student", newValue.nameForm.nameReactive, oldValue.nameForm.nameReactive);
}, {
deep: true
});
如果按下面的方式寫,可以獲取
watch([() => student.nameForm.nameReactive], (newValue, oldValue) => {
console.log(newValue, oldValue);
});
watchEffect
watchEffect有點像computed,而watchEffect更注重的是過程(回調函數的函數體),所以不用寫返回值。只要引用的變量做了變化,則執行函數。
watchEffect(() => { console.log('你點擊更改了!', student.nameForm.nameReactive ) })
4 生命週期
onBeforeMount(() => {
console.log('實例創建完成,即將掛載')
})
onMounted(() => {
console.log('實例掛載完成')
})
onBeforeUpdate(() => {
console.log('組件dom即將更新')
})
onUpdated(() => {
console.log('組件dom已經更新完畢')
})
// 對應vue2 beforeDestroy
onBeforeUnmount(() => {
console.log('實例即將解除掛載')
})
// 對應vue2 destroyed
onUnmounted(() => {
console.log('實例已經解除掛載')
})
onErrorCaptured(() => {
console.log('捕獲到一個子孫組件的錯誤')
})
onActivated(() => {
console.log('被keep-alive緩存的組件激活')
})
onDeactivated(() => {
console.log('被keep-alive緩存的組件停用')
})
// 兩個新鉤子,可以精確地追蹤到一個組件發生重渲染的觸發時機和完成時機及其原因
onRenderTracked(() => {
console.log('跟蹤虛擬dom重新渲染時')
})
onRenderTriggered(() => {
console.log('當虛擬dom被觸發重新渲染時')
})
5、Proxy + Reflect
vue3使用Proxy + Reflect代替了Object.defineProperty,是因爲在使用Object.defineProperty的時候,我們遇到的問題有:
1 一次只能對一個屬性進行監聽,需要遍歷來對所有屬性監聽
2 如果監聽的對象是嵌套的深層對象,需要遞歸監聽。
3 對於對象的新增屬性,需要手動監聽
4 對於數組的增刪改,只能使用固定的幾個方法才能實現監聽
proxy是用來操作對象並且擴展對象能力的,而Object.defineProperty只是單純地操作對象的屬性,用proxy來攔截對象,不管是對對象執行任何操作,都會先通過proxy的處理邏輯
使用Reflect.set 和 Reflect.get 是爲了讓數據的指向始終指向當前的proxy
let arr = [1, 2, 3];
let proxy = new Proxy(arr, {
get (target, key, receiver) {
console.log('get', key);
return Reflect.get(target, key, receiver)
},
set (target, key, value, receiver) {
console.log('set', key, value)
return Reflect.set(target, key, value, receiver)
}
})
proxy.push(4)
let obj = {
info: {
name: 'heimayu',
age: ['webpack', 'element', 'vue3']
}
}
let handler = {
get (target, key, receiver) {
console.log('get', key)
// 遞歸創建並返回
if (typeof target[key] === 'object' && target[key] !== null) {
return new Proxy(target[key], handler)
}
return Reflect.get(target, key, receiver)
},
set (target, key, value, receiver) {
console.log('set', key, value)
return Reflect.set(target, key, value, receiver)
}
}
let proxy2 = new Proxy(obj, handler)
proxy2.info.name = 'new heimayu';
proxy2.info.age.push("proxy")