vue3 + Typescript學習筆記 二
一、用 reactive()函式優化程式
-
上節課的程式碼可以說沒什麼章法可言,所有的變數和方法都混淆在一起,我最不能忍受的是在setup中要改變和讀取一個值的時候,還要加上value。這種程式碼一定是可以優化的,需要引入一個新的 APIreactive。它也是一個函式(方法),只不過裡邊接受的引數是一個 Object(物件)。
然後無論是變數和方法,都可以作為 Object 中的一個屬性,而且在改變selectGirl值的時候也不用再加討厭的value屬性了。再return返回的時候也不用一個個返回了,只需要返回一個data,就可以了。<script
-
修改完成
<script>
部分的程式碼後,還需要修改template部分的程式碼,因為我們這時候返回的只有data,所以模板部分的字面量前要加入data。<template> <img alt="Vue logo" src="./assets/logo.png" /> <div> <
-
這個修改完成後,可以在Terminal終端裡開啟yarn serve,檢視一下效果了,如果沒有錯誤,應該和原來的效果一樣。效果雖然一樣,但是這時候程式碼,要比上節課優雅了很多。著一些的功勞要歸屬於reactive函式。
給 data 增加型別註解
-
這時的程式碼雖然可以完美的執行,但是細心的小夥伴可以發現data這個變數,我們並沒有作型別註解,而是採用了TypeScript的型別推斷。
這樣的程式碼,在我們公司是不允許出現的,必須要增加型別註解。所以我們先定義一個介面,用介面(interface)來作型別註解。interface DataProps { girls: string[]; selectGirl: string; selectGirlFun: (index: number) => void; }
編寫完成後,你在顯示的為 data 變數作一個型別註解.
cosnt data: DataProps = ...
用 toRefs()繼續優化
-
現在template中,每次輸出變數前面都要加一個data,這是可以優化的。有的小夥伴說了,我用…擴充套件運算子就可以解決這個問題了。
在這裡我就可以告訴你不行,因為結構後就變成了普通變數,不再具有響應式的能力。所以要解決這個問題,需要使用 Vue3 的一個新函式toRefs()。使用前需要先進行引入。import { reactive, toRefs } from "vue";
引入後就可以對data進行包裝,把 data 變成refData,這樣就可以使用擴充套件運算子的方式了。具體程式碼如下:
export default { name: "App", setup() { // const girls = ref(["大腳", "劉英", "曉紅"]); // const selectGirl = ref(""); // const selectGirlFun = (index: number) => { // selectGirl.value = girls.value[index]; // }; const data: DataProps = reactive({ girls: ["大腳", "劉英", "曉紅"], selectGirl: "", selectGirlFun: (index: number) => { data.selectGirl = data.girls[index]; }, }); const refData = toRefs(data); return { ...refData, }; }, };
這樣寫之後,你的template就應該去掉 data,而是直接使用變數名和方法,就可以了。
<template> <img alt="Vue logo" src="./assets/logo.png" /> <div> <h2>歡迎光臨紅浪漫洗浴中心</h2> <div>請選擇一位美女為你服務</div> </div> <div> <button v-for="(item, index) in girls" v-bind:key="index" @click="selectGirlFun(index)" > {{ index }} : {{ item }} </button> </div> <div>你選擇了【{{ selectGirl }}】為你服務</div> </template>
如何選擇 Ref()和 reactive()
- 網路上對這兩個方法的爭論還是不少的,但到目前為止,還沒有什麼實質性的理論到底是用Ref()好,還是reactive()好,也就是兩種方法都可以。他們的作用都是生成響應式物件,目前來看只是編寫上有所不同。
我個人更傾向於使用reactive(),因為它讓程式看起來更規範。如果你學到這裡還猶豫不定,也沒關係,隨著你進一步的深入學習,一定會有你自己的最佳選擇。
二、Vue3.x 的生命週期和鉤子函式
-
Vue3 版本的生命週期和 Vue2 比有了些變化,所以我先站在一個初學者的角度(沒有學過 Vue2 版本的新手),從新講一下 Vue3.x 的生命週期,等你完全理解之後,我們再來和 Vue2.x 的生命週期作一個對比。
-
什麼是生命週期
-
Vue 是元件化程式設計,從一個元件誕生到消亡,會經歷很多過程,這些過程就叫做生命週期。
-
來個比喻,生命週期和人從出生到入土是一樣的。有少年時期、有青年時期、有中年時期、有老年時期。每個時期都應該有不同的任務,可以作不同的事。
當你理解了什麼是生命週期,你還了解一個概念“鉤子函式”。 -
鉤子函式: 伴隨著生命週期,給使用者使用的函式,操控生命週期,主要是操控鉤子函式。
Vue3 的生命週期比較多,我們需要一個個給大家講。setup() :開始建立元件之前,在beforeCreate和created之前執行。建立的是data和method onBeforeMount() : 元件掛載到節點上之前執行的函式。 onMounted() : 元件掛載完成後執行的函式。 onBeforeUpdate(): 元件更新之前執行的函式。 onUpdated(): 元件更新完成之後執行的函式。 onBeforeUnmount(): 元件解除安裝之前執行的函式。 onUnmounted(): 元件解除安裝完成後執行的函式 onActivated(): 被包含在<keep-alive>中的元件,會多出兩個生命週期鉤子函式。被啟用時執行。 onDeactivated(): 比如從 A 元件,切換到 B 元件,A 元件消失時執行。 onErrorCaptured(): 當捕獲一個來自子孫元件的異常時啟用鉤子函式(以後用到再講,不好展現)。
-
注:使用元件會將資料保留在記憶體中,比如我們不想每次看到一個頁面都重新載入資料,就可以使用元件解決。
三、鉤子函式的使用
-
Vue3.x 生命週期在呼叫前需要先進行引入,我們先暫時演示前五個生命週期。
import { reactive, toRefs, onMounted, onBeforeMount, onBeforeUpdate, onUpdated, } from "vue";
-
先來說setup(),setup 這個函式是在beforeCreate和created之前執行的,所以你可以用它來代替這兩個鉤子函式。
為了看出鉤子函式執行的時機,我在setup()函式裡,編寫了下面的程式碼:<script lang="ts"> //.... const app = { name: "App", setup() { console.log("1-開始建立元件-----setup()"); const data: DataProps = reactive({ girls: ["大腳", "劉英", "曉紅"], selectGirl: "", selectGirlFun: (index: number) => { data.selectGirl = data.girls[index]; }, }); onBeforeMount(() => { console.log("2-元件掛載到頁面之前執行-----onBeforeMount()"); }); onMounted(() => { console.log("3-元件掛載到頁面之後執行-----onMounted()"); }); onBeforeUpdate(() => { console.log("4-元件更新之前-----onBeforeUpdate()"); }); onUpdated(() => { console.log("5-元件更新之後-----onUpdated()"); }); const refData = toRefs(data); return { ...refData, }; }, }; export default app; </script>
-
寫完後可以到瀏覽器看一下效果,效果和你想象的應該是一樣的。
1 - 開始建立元件---- - setup(); 2 - 元件掛載到頁面之前執行---- - onBeforeMount(); 3 - 元件掛載到頁面之後執行---- - onMounted(); 4 - 元件更新之前---- - onBeforeUpdate(); 5 - 元件更新之後---- - onUpdated();
-
你這時候一定會有個疑問,那Vue2.X版本的生命週期函式還可以使用嗎?答案是肯定的。
你可以在setup()函式之後編寫Vue2的生命週期函式,程式碼如下:beforeCreate() { console.log("1-元件建立之前-----beforeCreate()"); }, beforeMount() { console.log("2-元件掛載到頁面之前執行-----BeforeMount()"); }, mounted() { console.log("3-元件掛載到頁面之後執行-----Mounted()"); }, beforeUpdate() { console.log("4-元件更新之前-----BeforeUpdate()"); }, updated() { console.log("5-元件更新之後-----Updated()"); },
這時候可以看到,原來的生命週期也是完全可以使用。