在Vue3.0中創建響應式數據需要引用ref,reactive這兩個方法,ref一般用來創建基本數據類型的響應式數據,reactive一般用來創建引用數據類型的響應式數據。
在模板中使用,跟之前沒有區別,需要注意的是,ref屬於將基本類型數據包裝成應用類型,在模板中正常使用。在方法中訪問的時候需要帶上.value才能訪問到。
為什么要這么寫呢?是因為Proxy的原因,Proxy要進行數據劫持的時候需要接收一個對象,所以ref就對基本數據類型的數據進行了包裝,使其可以進行響應式。
ref例子:
<template> <div> {{ count }} <button @click="add">+</button> </div> </template> <script> import { ref } from "vue"; export default { /* 在Vue3.0中創建響應式數據需要引用ref,reactive這兩個方法,ref一般用來創建基本數據類型的響應式數據,reactive一般用來創建引用數據類型的響應式數據。 在模板中使用,跟之前沒有區別,需要注意的是,ref屬於將基本類型數據包裝成應用類型,在模板中正常使用。在方法中訪問的時候需要帶上.value才能訪問到。為什么要這么寫呢?是因為Proxy的原因,Proxy要進行數據劫持的時候需要接收一個對象,所以ref就對基本數據類型的數據進行了包裝,使其可以進行響應式。 */ name: "Test", setup(props, context) { const count = ref(0); // 定義響應式數據count const objData = { name: "erha", age: "1", skill: "拆家", }; const add = ()=>{ count.value++; } return { count, add, }; }, }; </script>
由於Proxy的機制原因,如果將reactive中的響應式數據進行解構,那么原先的響應式數據就變成不可響應的了。
為什么將可觀察對象中的屬性解構出來后,變成不再可觀察了呢?因為通過reactive方法創建的可觀察對象,內部的屬性本身並不是可觀察的,而是通過Proxy代理實現的讀寫觀察,如果將這些屬性解構,這些屬性就不再通過原對象的代理來訪問了,就無法再進行觀察。
Composition API提供了一種方法來解決此機制帶來的問題,那就是toRefs,它可以將reactive創建的可觀察對象,轉換成可觀察的ref對象
當使用了toRefs的時候在模板中只需要使用name即可
<template> <div> <!-- {{ data.age }} --> {{age}} </div> </template> <script> import { reactive, toRefs } from "vue"; export default { /* 由於Proxy的機制原因,如果將reactive中的響應式數據進行解構,那么原先的響應式數據就變成不可響應的了。 為什么將可觀察對象中的屬性解構出來后,變成不再可觀察了呢?因為通過reactive方法創建的可觀察對象,內部的屬性本身並不是可觀察的,而是通過Proxy代理實現的讀寫觀察,如果將這些屬性解構,這些屬性就不再通過原對象的代理來訪問了,就無法再進行觀察。Composition API提供了一種方法來解決此機制帶來的問題,那就是toRefs,它可以將reactive創建的可觀察對象,轉換成可觀察的ref對象 */ // 當使用了toRefs的時候在模板中只需要使用name即可 name: "Test", setup(props, context) { const data = reactive({ name: "lisa", age: 18, }); let { name , age} = toRefs(data) // data.age = 20; //響應式 // age = 30; //非響應式 data.age = 30; //也是響應式 return { // data, ...toRefs(data) }; }, }; </script>
Composition API提供的computed方法就相當於2.x版本中的計算屬性。使用如下:
<template> <div> {{ count }} {{ doubeCount }} </div> </template> <script> import { ref, computed } from "vue"; export default { /* Composition API提供的computed方法就相當於2.x版本中的計算屬性。 */ name: "Test", setup(props, context) { const count = ref(2); const doubeCount = computed(() => { return count.value * 2; }); return { count, doubeCount }; }, }; </script>
Composition API提供的watch方法相當於就是2.x的觀察屬性。
watch方法接收兩個參數,第一個參數是一個函數,第二個參數也是個函數,第一個參數函數返回值表示要監聽哪個數據,第二個參數函數,表示監聽成功后的邏輯,該函數的第一個參數就是監聽到目標數據變化后的值。同時watch可以監聽多個數據。
使用如下:
<template> <div class="test"> <div>watch: count+num:{{ countAddNum }}</div> <button @click="addCount">點擊+1</button> </div> </template> <script> import { ref, computed, watch } from "vue"; export default { /* watch方法接收兩個參數,第一個參數是一個函數,第二個參數也是個函數,第一個參數函數返回值表示要監聽哪個數據,第二個參數函數,表示監聽成功后的邏輯,該函數的第一個參數就是監聽到目標數據變化后的值。同時watch可以監聽多個數據。 */ name: "Test", setup() { const count = ref(0); // 定義響應式數據count const num = ref(1); // 定義響應式數據num const countAddNum = computed(() => { // 計算屬性 return count.value + num.value; }); // 相當於watch watch( [() => count.value, () => num.value], ([count, num], [oldCount, oldNum]) => { // watch 同時觀察count和num兩個值 console.log( `count:${count},num:${num} oldCount:${oldCount},oldNum:${oldNum}` ); } ); watch( () => { return count.value; }, (newcount) => { console.log("count變啦", newcount); } ); // 相當於methods const addCount = () => { // 定義增加count方法 count.value++; }; // 統一return出去 return { count, num, addCount, countAddNum, }; }, }; </script>
在Vue2.x版本中頻繁出現的this,在Vue3.0中也消失了,取而代之的是Composition API提供的
getCurrentInstance方法,用來獲取當前組件實例,然后通過ctx獲取當前上下文。
下面是路由跳轉的例子:
<template> <button @click="pushRoute">push</button> </template> <script> import { getCurrentInstance } from "vue"; export default { name: "Test", setup(props, context) { const { ctx } = getCurrentInstance(); console.log(ctx); const pushRoute = () => { // 編程導航 ctx.$router.push({ path: "/", }); }; return { pushRoute, }; }, }; </script>
最后看一下Vue3.0中的生命周期,生命周期也是有所改動,鈎子函數名稱均發生變化。
beforeCreate,created生命周期在
setup方法中自動執行,其余生命周期鈎子函數都是從Vue中引入使用(注意在setup方法中使用)
<template> <div> <h1>{{ msg }}</h1> <div>{{ a }}</div> <button @click="setA">加A</button> </div> </template> <script> import { ref, onBeforeMount, onMounted, onBeforeUpdate, onUpdated, onBeforeUnmount, onUnmounted, onErrorCaptured, onRenderTracked, onRenderTriggered, } from "vue"; export default { setup(props, context) { // console.log(props.msg, context) const a = ref(0); const setA = () => { return a.value++; }; // 相當於 beforeMount onBeforeMount(() => { console.log("onBeforeMount"); }); // 相當於 mounted onMounted(() => { console.log("onMounted"); }); // 相當於 beforeUpdate onBeforeUpdate(() => { console.log("onBeforeUpdate"); }); // 相當於 updated onUpdated(() => { console.log("onUpdated"); }); // 相當於 beforeDestroy onBeforeUnmount(() => { console.log("onBeforeUnmount"); }); // 相當於 destroyed onUnmounted(() => { console.log("onUnmounted"); }); onErrorCaptured(() => { // 錯誤監控 參考文章 https://zhuanlan.zhihu.com/p/37404624 console.log("onErrorCaptured"); }); onRenderTracked(() => { // 已渲染 console.log("onRenderTracked"); }); onRenderTriggered(() => { // 當組件更新時會首先觸發此生命周期鈎子 onRenderTriggered->onRenderTracked->onBeforeUpdate->onUpdated console.log("onRenderTriggered"); }); return { a, setA, }; }, name: "HelloWorld", props: { msg: String, }, }; </script>
