iT邦幫忙

第 12 屆 iThome 鐵人賽

DAY 13
0
自我挑戰組

網頁前端框架 Vue 3 從頭開始(重新挑戰)系列 第 13

vue3 Composition API 學習手冊-13 生命週期

  • 分享至 

  • xImage
  •  

前一篇文章,介紹到我們如何用已經學習到的進度製作一個連動的選單,其實大家應該不難發現在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時該怎麼建構,接下來就看看這些生命週期在網頁上的做法吧!

beforeCreate & created


  • beforeCreate:Vue初始化時期,在這邊的動作會在vue導入期就被執行,但在這個階段還拿不到Vue Data,也沒有辦法使用vue裡面的Methods, Watch, Computed...等。
  • created:Vue已被建立,在這個階段的動作可以拿到Vue Data, Function, Watch, Computed...等,但網頁內容必須依靠HTML Element才能取得,這時HTML還沒準備好,所以拿不到元素內容。

我們透過程式的角度來看看他們執行的效果,下面是個很簡單的網頁案例,頁面中有一個段落和兩個按鈕,特性如下:

  • p:讓vue可以透過ref來追蹤HTML元素
  • button:一個按鈕點選後可以執行changeText變更vue data,另一個按鈕可以卸載vue
<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中已經拿掉了,但為了能讓大家了解官網的圖片,還是稍微寫一下用法,但基本之後應該是不需要用到才對。

beforeMount & mounted


  • beforeMount:已經載入原始HTML至Virtual DOM,但內容尚未透過Vue進行渲染。
  • mounted:已經透過Vue進行渲染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, 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時就可以抓到了。

beforeUpdate & updated


  • beforeUpdate:當Vue中的Data被改變或是強制讓Vue Update(vm.$forceUpdate),準備重新渲染頁面之前。
  • updated:承上,當頁面已經完成渲染之後。
<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才更新完成。

beforeUnmount & unmounted


  • beforeUnmount:在Vue被摧毀前。
  • unmounted:所有綁定、事件監聽、Watch與渲染至目標的HTML DOM…等等皆移除。
<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能讓我們在正確的時間去做正確的事,接下來我們在範例中就會加入生命週期來輔助進行。


上一篇
vue3 Composition API 學習手冊-12 實作 多層次動態選單
下一篇
vue3 Composition API 學習手冊-14 透過axios載入外部json
系列文
網頁前端框架 Vue 3 從頭開始(重新挑戰)30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言