在 Vue
中,每一個實例都有本身的一個完整的生命週期,包括開始建立 —— 初始化數據 —— 編譯模板 —— 將實例掛載到 DOM
—— 渲染 —— 更新 —— 渲染 —— 卸載等一系列過程。同時在這個過程當中也會運行一些叫作生命週期鉤子的函數,這樣咱們就能夠在實例生命週期的不一樣階段作一些須要作的事情。javascript
這裏可能會有個小疑惑,怎麼忽然又說是 Vue
實例呢?實例和組件有什麼區別嗎?css
在 SPA(Single Page Application)
應用中,咱們只會建立一個 Vue
根實例,整個應用都是經過這個根實例啓動的。在經過 vue-cli
腳手架生成的項目中, main.js
裏建立了 Vue
根實例:
<!-- more -->html
new Vue({ el: '#app', router, components: { App }, template: '<App/>', });
經過 new Vue()
建立一個 Vue
實例。在實例化 Vue
時,須要傳入一個選項對象,它能夠包含掛載元素 el
、路由router
、模板 template
、數據 data
、方法 methods
、生命週期鉤子等選項。vue
Vue
組件是被擴展的 Vue
實例。同 Vue
實例相似,它也須要傳入一個選項對象,包含數據、模板、生命週期鉤子函數等等。在前面咱們只介紹了單文件組件的方式來建立組件,也能夠這樣來建立一個組件:java
// 定義一個名爲 button-counter 的新組件 Vue.component('button-counter', { data: function () { return { count: 0 } }, template: '<button v-on:click="count++">You clicked me {{ count }} times.</button>' })
能夠發現,和建立 Vue
實例很是的相似,全部的 Vue
組件同時都是 Vue
的實例。因此咱們說:實例的生命週期也叫作組件的生命週期。vue-cli
Vue
實例從建立到銷燬的過程,就是生命週期。文章的開頭咱們提到了生命週期鉤子函數,它是框架提供的函數,可以讓開發人員的代碼參與到組件的生命週期中。也就是說,經過鉤子函數,能夠控制組件的行爲。這裏有兩個點須要記住:緩存
Vue
實例的的生命週期中,會自動調用這些生命週期函數,咱們只須要提供這些鉤子函數便可;生命週期圖示:app
圖中,紅色矩形框表明着在生命週期對應階段的鉤子函數。框架
咱們經過三種案例來學習生命週期函數:函數
案例中,經過打開控制檯查看鉤子函數打印的內容來學習。
<template> <div class='container'> <h3>單組件的生命週期(打開控制檯查看)</h3> <button @click='dataVar += 1'>更新 {{dataVar}}</button> <button @click='handleDestroy'>銷燬</button> </div> </template> <script> const compName = 'single'; export default { name: 'SingleComLifecycle', data() { return { dataVar: 1, }; }, beforeCreate() { console.log(`--${compName}--beforeCreate`); // eslint-disable-line }, created() { console.log(`--${compName}--created`); // eslint-disable-line }, beforeMount() { console.log(`--${compName}--beforeMount`); // eslint-disable-line }, mounted() { console.log(`--${compName}--mounted`); // eslint-disable-line }, beforeUpdate() { console.log(`--${compName}--beforeUpdate`); // eslint-disable-line }, updated() { console.log(`--${compName}--updated`); // eslint-disable-line }, beforeDestroy() { console.log(`--${compName}--beforeDestroy`); // eslint-disable-line }, destroyed() { console.log(`--${compName}--destroyed`); // eslint-disable-line }, methods: { handleDestroy() { this.$destroy(); }, }, }; </script> <style lang="postcss" scoped> .container { width: 70%; margin: 0 auto; background-color: aliceblue; padding: 50px; text-align: center; } button { padding: 6px; background-color: #35b880; border: none; color: white; font-size: 16px; margin: 5px; } </style>
初始化組件時打印:
--single--beforeCreate --single--created --single--beforeMount --single--mounted
data
中的數據變化時打印:
--single--beforeUpdate --single--updated
組件銷燬時打印:
--single--beforeDestroy --single--destroyed
因此咱們能夠得出如下結論:
beforeCreate/Created/beforeMount/mounted
四個鉤子函數data
中定義的變量(響應式變量)時,會執行 beforeUpdate/updated
鉤子函數beforeDestory/destroyed
鉤子函數beforeUpdate/updated
可屢次執行建立一個父組件:
<template> <div class='container'> <h3>父子組件的生命週期(打開控制檯查看)</h3> <child-com :compName='dataVar.toString()'></child-com> <button @click='dataVar += 1'>父組件更新 {{dataVar}}</button> <button @click='handleDestroy'>父組件銷燬</button> </div> </template> <script> import ChildCom from './ChildCom'; const COMPONENT_NAME = 'parent'; export default { data() { return { dataVar: 1, }; }, components: { 'child-com': ChildCom, }, beforeCreate() { console.log(`--${COMPONENT_NAME}--beforeCreate`); // eslint-disable-line }, created() { console.log(`--${COMPONENT_NAME}--created`); // eslint-disable-line }, beforeMount() { console.log(`--${COMPONENT_NAME}--beforeMount`); // eslint-disable-line }, mounted() { console.log(`--${COMPONENT_NAME}--mounted`); // eslint-disable-line }, beforeUpdate() { console.log(`--${COMPONENT_NAME}--beforeUpdate`); // eslint-disable-line }, updated() { console.log(`--${COMPONENT_NAME}--updated`); // eslint-disable-line }, beforeDestroy() { console.log(`--${COMPONENT_NAME}--beforeDestroy`); // eslint-disable-line }, destroyed() { console.log(`--${COMPONENT_NAME}--destroyed`); // eslint-disable-line }, methods: { handleDestroy() { this.$destroy(); }, }, }; </script> <style lang="postcss" scoped> .container { width: 70%; margin: 20px auto; background-color: aliceblue; padding: 50px; text-align: center; } button { padding: 6px; background-color: #2196f3; border: none; color: white; font-size: 16px; margin: 5px; } </style>
建立一個子組件:
<template> <div> <div>父組件傳遞的props:{{compName}}</div> <button @click='dataVar += 1'>子組件更新 {{dataVar}}</button> <button @click='handleDestroy'>子組件銷燬</button> </div> </template> <script> export default { data() { return { dataVar: 1, }; }, props: { compName: { type: String, default: 'single', }, }, beforeCreate() { console.log(` --此時data未初始化--child--beforeCreate`); // eslint-disable-line }, created() { console.log(`--${this.compName}--child--created`); // eslint-disable-line }, beforeMount() { console.log(`--${this.compName}--child--beforeMount`); // eslint-disable-line }, mounted() { console.log(`--${this.compName}--child--mounted`); // eslint-disable-line }, beforeUpdate() { console.log(`--${this.compName}--child--beforeUpdate`); // eslint-disable-line }, updated() { console.log(`--${this.compName}--child--updated`); // eslint-disable-line }, beforeDestroy() { console.log(`--${this.compName}--child--beforeDestroy`); // eslint-disable-line }, destroyed() { console.log(`--${this.compName}--child--destroyed`); // eslint-disable-line }, methods: { handleDestroy() { this.$destroy(); }, }, }; </script> <style lang="postcss" scoped> button { padding: 6px; background-color: #35b880; border: none; color: white; font-size: 16px; margin: 5px; } </style>
初始化組件時打印:
--parent--beforeCreate --parent--created --parent--beforeMount --此時data未初始化--child--beforeCreate --1--child--created --1--child--beforeMount --1--child--mounted --parent--mounted
當子組件 data
中的值變化時打印:
--1--child--beforeUpdate --1--child--updated
當父組件 data
中的值變化時打印(子組件接受了父組件傳遞的 props
):
--parent--beforeUpdate --2--child--beforeUpdate --2--child--updated --parent--updated
當子組件銷燬時打印:
--1--child--beforeDestroy --1--child--destroyed
當父組件銷燬時打印:
--parent--beforeDestroy --1--child--beforeDestroy --1--child--destroyed --parent--destroyed
結論:
data
變化中是分別監控的,可是在更新 props
中的數據是關聯的建立一個單組件:
<template> <div class='container'> <button @click='dataVar += 1'>更新 {{dataVar}}</button> <button @click='handleDestroy'>銷燬</button> </div> </template> <script> export default { data() { return { dataVar: 1, }; }, props: { compName: { type: String, default: 'single', }, }, beforeCreate() { console.log(`--此時data未初始化--beforeCreate`); // eslint-disable-line }, created() { console.log(`--${this.compName}--created`); // eslint-disable-line }, beforeMount() { console.log(`--${this.compName}--beforeMount`); // eslint-disable-line }, mounted() { console.log(`--${this.compName}--mounted`); // eslint-disable-line }, beforeUpdate() { console.log(`--${this.compName}--beforeUpdate`); // eslint-disable-line }, updated() { console.log(`--${this.compName}--updated`); // eslint-disable-line }, beforeDestroy() { console.log(`--${this.compName}--beforeDestroy`); // eslint-disable-line }, destroyed() { console.log(`--${this.compName}--destroyed`); // eslint-disable-line }, methods: { handleDestroy() { this.$destroy(); }, }, }; </script> <style lang="postcss" scoped> .container { width: 70%; margin: 0 auto; background-color: aliceblue; padding: 10px; text-align: center; } button { padding: 6px; background-color: #35b880; border: none; color: white; font-size: 16px; margin: 5px; } </style>
引入兩個單組件,構建兄弟組件:
<template> <div class='container'> <h3>兄弟組件的生命週期(打開控制檯查看)</h3> <div>兄弟1 <single compName='cihld1'></single> </div> <div>兄弟2 <single compName='child2'></single> </div> <div> <p>兄弟兩個的父親</p> <button @click='dataVar += 1'>更新 {{dataVar}}</button> <button @click='handleDestroy'>銷燬</button> </div> </div> </template> <script> import Single from './Single'; const COMPONENT_NAME = 'parent'; export default { data() { return { dataVar: 1, }; }, components: { single: Single, }, beforeCreate() { console.log(`--${COMPONENT_NAME}--beforeCreate`); // eslint-disable-line }, created() { console.log(`--${COMPONENT_NAME}--created`); // eslint-disable-line }, beforeMount() { console.log(`--${COMPONENT_NAME}--beforeMount`); // eslint-disable-line }, mounted() { console.log(`--${COMPONENT_NAME}--mounted`); // eslint-disable-line }, beforeUpdate() { console.log(`--${COMPONENT_NAME}--beforeUpdate`); // eslint-disable-line }, updated() { console.log(`--${COMPONENT_NAME}--updated`); // eslint-disable-line }, beforeDestroy() { console.log(`--${COMPONENT_NAME}--beforeDestroy`); // eslint-disable-line }, destroyed() { console.log(`--${COMPONENT_NAME}--destroyed`); // eslint-disable-line }, methods: { handleDestroy() { this.$destroy(); }, }, }; </script> <style lang="postcss" scoped> .container { width: 70%; margin: 5px auto; background-color: aliceblue; padding: 50px; text-align: center; } button { padding: 6px; background-color: #2196f3; border: none; color: white; font-size: 16px; margin: 5px; } </style>
初始化組件時打印:
--parent--beforeCreate --parent--created --parent--beforeMount --此時data未初始化--beforeCreate --cihld1--created --cihld1--beforeMount --此時data未初始化--beforeCreate --child2--created --child2--beforeMount --cihld1--mounted --child2--mounted --parent--mounted
當 child1
更新和銷燬時,打印:
--cihld1--beforeUpdate --cihld1--updated --cihld1--beforeDestroy --cihld1--destroyed
當 child2
更新和銷燬時,打印:
--cihld2--beforeUpdate --cihld2--updated --cihld2--beforeDestroy --cihld2--destroyed
當父組件銷燬時,打印:
--parent--beforeDestroy --cihld1--beforeDestroy --cihld1--destroyed --child2--beforeDestroy --child2--destroyed --parent--destroyed
結論:
歡迎關注個人博客: https://togoblog.cn/