前一篇文章,介紹到我們如何用已經學習到的進度製作一個連動的選單,其實大家應該不難發現在Javascript的程式中,實際上邏輯運算相關的程式碼並不多,反而是描述資料的部分又臭又長,當然這部分資料也是不可或缺的,但也提到資料有可能是從外部載入的,今天就準備朝從外部載入這個方向來進行一些準備,在這之前我們必須先認識Vue的生命週期,他對我們未來開發前、後端分離的案例將會大有幫助!
首先借用Vue官網上面的生命週期圖:
看起來有點複雜,我們先注意看到圖片上面紅色簍空框線的八個項目,分別是:beforeCreate、created、beforeMount、mounted、beforeUpdate、updated、beforeUnmount、unmounted,其實大家應該也不難發現,這八個項目裡面就是四個動作,分別是:create、mount、update、unmount再加上他們被觸發之前或之後的幾個動作。
簡單來說就是你可以讓Vue在不同的時間點去執行你希望他做的動作,好比一個人上班的生命週期可以是:起床前、起床後、到公司前、到公司後、工作完成前、工作完成後、離開公司前、離開公司後,所以有時候我們常會說:「起床後記得要刷牙洗臉」,到公司後記得先打卡...等等,可以用這樣的方式去模擬想像Vue生命週期的意思。
不過有一點需要先說明,vue3為了相容於vue2的使用,所以在上面的生命週期中還保留了beforeMount和created,但之前有說過我們的文章先不已大家接觸過vue為出發點來撰寫,所以不以與vue2做比較為出發點來介紹,但這邊因為官方的圖片,還是利用下面的表格說明一下:
因為我們的開發都以vue3新的Composition API來進行,也就是上方表格的右邊,但還是會解釋如果在vue3中若真的還是會需要用到beforeCreate和created時該怎麼建構,接下來就看看這些生命週期在網頁上的做法吧!
我們透過程式的角度來看看他們執行的效果,下面是個很簡單的網頁案例,頁面中有一個段落和兩個按鈕,特性如下:
<h2>Vue Lifecycle</h2>
<div id="app">
<p ref="content">I am learning {{ state.name }}</p>
<button @click="changeText">Change Text</button>
<button @click="unmount">Unmount</button>
</div>
<script>
const state = reactive({ name: "Vue" });
console.log("-------------");
console.log("beforeCreate");
console.log("state.name: ", state.name);
console.log("-------------");
const { reactive, ref } = Vue;
const app = {
setup(){
const content = ref(null);
const state = reactive({
name: "Vue",
})
function changeText(){
state.name = "Vue 3.x";
}
function unmount() {
myVue.unmount();
}
console.log("created");
console.log("state.name: ", state.name);
console.log("changeText: ", changeText);
console.log("ref: ", content.value);
console.log("-------------");
return { state, changeText, content, unmount };
}
}
const myVue = Vue.createApp(app);
myVue.mount("#app");
</script>
Result:
-------------
beforeCreate
state.name: Stanley
-------------
created
state.name: Vue
changeText: ƒ changeText(){
state.name = "Vue 3.x";
}
ref: null
-------------
就像前面說的,vue3的composition已經不需要使用beforeCreate和created,但如果真的需要,可以在setup的區段內外來處理,在上面範例中的Result可以看到,在beforeCreate沒有辦法取得vue data, methods,但在created之後就可以順利取得這兩項的資料,雖然感覺像廢話,但是還是讓大家參考,實際上我們其實應該不需要提到這兩個生命週期才對,因為在vue3的Composition API中已經拿掉了,但為了能讓大家了解官網的圖片,還是稍微寫一下用法,但基本之後應該是不需要用到才對。
同樣利用程式來看看它運作的情形:
<h2>Vue Lifecycle</h2>
<div id="app">
<p ref="content">I am learning {{ state.name }}</p>
<button @click="changeText">Change Text</button>
<button @click="unmount">Unmount</button>
</div>
<script>
const { reactive, ref, onBeforeMount, onMounted } = Vue;
const app = {
setup(){
const content = ref(null);
const state = reactive({ name: "Vue" });
onBeforeMount(() => {
console.log("[onBeforeMount]");
console.log("state.name: ", state.name);
console.log("function: ", changeText);
console.log("ref: ", content.value);
console.log("-------------");
})
onMounted(() => {
console.log("[onMounted]");
console.log("ref: ", content.value.outerHTML);
console.log("-------------");
})
function changeText(){
state.name = "Vue 3.x";
}
function unmount() {
myVue.unmount();
}
return { state, changeText, content, unmount };
}
}
const myVue = Vue.createApp(app);
myVue.mount("#app");
</script>
Result
-------------
[onBeforeMount]
state.name: Vue
function: ƒ changeText(){
state.name = "Vue 3.x";
}
ref: null
-------------
[onMounted]
ref: <p>I am learning Vue</p>
-------------
從上面的result當中我們可以觀察到onBeforeMount跟前述beforeCreate的結果相同,但我們也有說過現在的beforeCreate基本是不存在的,所以這樣也是合理的結果。
至於onMounted可以看到,我們在HTML的P Tag中加入了ref(HTML的第3行、JS的第4行),用來在Vue中取得該元素的內容,可以看到上面範例的Result,在beforeMount內無法抓到HTML Element元素的內容,但mounted時就可以抓到了。
<h2>Vue Lifecycle</h2>
<div id="app">
<p ref="content">I am learning {{ state.name }}</p>
<button @click="changeText">Change Text</button>
<button @click="unmount">Unmount</button>
</div>
<script>
const { reactive, ref, onBeforeUpdate, onUpdated } = Vue;
const app = {
setup(){
const content = ref(null);
const state = reactive({ name: "Vue" });
onBeforeUpdate(() => {
console.log("[onBeforeUpdate]");
console.log("ref: ", content.value.outerHTML);
console.log("-------------");
})
onUpdated(() => {
console.log("[onUpdated]");
console.log("ref: ", content.value.outerHTML);
console.log("-------------");
})
function changeText(){
state.name = "Vue 3.x";
}
function unmount() {
myVue.unmount();
}
return { state, changeText, content, unmount };
}
}
const myVue = Vue.createApp(app);
myVue.mount("#app");
</script>
Result
-------------
[onBeforeUpdate]
ref: <p>I am learning Vue</p>
-------------
[onUpdated]
ref: <p>I am learning Vue 3.x</p>
-------------
當我們按下Change Text按鈕後會觸發Update,而透過上面案例的Result可以看出來,在beforeUpdate時HTML元素內容還是舊的,updated之後HTML才更新完成。
<h2>Vue Lifecycle</h2>
<div id="app">
<p ref="content">I am learning {{ state.name }}</p>
<button @click="changeText">Change Text</button>
<button @click="unmount">Unmount</button>
</div>
<script>
const { reactive, ref, onBeforeUnmount, onUnmounted } = Vue;
const app = {
setup(){
const content = ref(null);
const state = reactive({ name: "Vue" });
onBeforeUnmount(() => {
console.log("[onBeforeUnmount]");
console.log("ref: ", content.value);
console.log("-------------");
})
onUnmounted(() => {
console.log("[onUnmounted]");
console.log("ref: ", content.value);
console.log("-------------");
})
function changeText(){
state.name = "Vue 3.x";
}
function unmount() {
myVue.unmount();
}
return { state, changeText, content, unmount };
}
}
const myVue = Vue.createApp(app);
myVue.mount("#app");
</script>
Result
-------------
[onBeforeUnmount]
ref: <p>I am learning Vue</p>
-------------
[onUnmounted]
ref: null
-------------
當我們按下Unmount之後會觸發unmount,可以看到Result中在onBeforeUnmount時還可以抓到HTML元素內容,但onUnmounted之後就抓不到了,另外Vue卸載後頁面中只會剩下<h2>
Vue Lifecycle</h2>
這個部分,另外要注意mount時的寫法:
const myVue = Vue.createApp(app).mount("#app"); <==無法卸載
----------
const myVue = Vue.createApp(app);
myVue.mount("#app"); <==可以卸載
以上大致上就是Vue的生命週期,現在我們知道Vue能讓我們在正確的時間去做正確的事,接下來我們在範例中就會加入生命週期來輔助進行。