淺談vue —— 生命週期

追_光_者發表於2018-05-08

記於vue生命週期的學習

每個 Vue 例項在被建立時都要經過一系列的初始化過程——例如,需要設定資料監聽、編譯模板、將例項掛載到 DOM 並在資料變化時更新 DOM 等。同時在這個過程中也會執行一些叫做生命週期鉤子的函式,這給了使用者在不同階段新增自己的程式碼的機會。


比如我們經常用到的created鉤子:

export default { 
    created() { 
        ...在這裡我們通常發起非同步請求,得到資料 
        
    } 
    
} 


<!--注意-->
<!--
    這裡的created函式不能使用箭頭函式,因為箭頭函式中的this指向的是上一級的this。
-->
複製程式碼

接下來我們看一下有哪些鉤子函式:

生命週期圖

方法 作用
beforeCreate 元件例項剛被建立,在data屬性之前。
created 元件例項建立完成,data屬性、computed、props、methods、watch已繫結,但DOM還未生成。
beforeMount
mounted DOM已生成,但不保證已全部掛載在document中(用this.$nextTick 可以保證已經在document中)
beforeUpdate
updated 更新時觸發
beforeDestroy 元件銷燬之前觸發 (可以用於清除定時器,取消全域性的註冊事件),此時的this還是指向vue例項
destroyed 此時的this不指向vue例項

單個元件的生命週期

<template lang="html">
    <div class="life-cycle">
        <h1 ref="title">lifr-cycle</h1>

        <h2>{{ a }} {{watchVal}}</h2>

        <ul>
            <li v-for="(item, index) in data" ref="item" @click="setNumber(index)">{{ item }}</li>
        </ul>

        <button type="button" name="button" @click="setData">設定item的個數</button>
        
        <!--<child-file-cycle :data="data"></child-file-cycle>-->
    </div>
</template>

<script>

let oDDEven = true;

import {mapGetters} from "vuex"
import childFileCycle from "./childFileCycle"
export default {
    data() {
        return {
            number: 1,
            watchVal: 1,
            data: ["Hellow"]
        }
    },
    computed: {
        ...mapGetters([
            "value"
        ]),
    },
    // 元件例項剛被建立,在data屬性之前。
    beforeCreate() {
        this.a = "a"
        console.log(this.$el, "---", this.data, "---", "beforeCreate", "---", this.$refs.title, "---", this.value);
    },
    // 元件例項建立完成,data屬性、computed、props、methods、watch已繫結,但DOM還未生成。
    created() {
        setTimeout(() => {
            this.data = ["Javascript", "Java", "PHP"];
        }, 3000);

        console.log(this.watchVal);
        console.log(this.$el, "---", this.data, "---", "created", "---", this.$refs.title, "---", this.value);
    },
    beforeMount() {
        console.log(this.$el, "---", this.data, "---", "beforeMount", "---", this.$refs.title, "---", this.value);
    },
    // DOM已生成,但不保證已全部掛載在document中(用this.$nextTick 可以保證已經在document中)
    mounted() {
        this.$nextTick(() => {
            console.log(this.$el, "---", this.data, "---", "mounted", "---", this.$refs.title, "---", this.$refs.item, "---", this.value);
        })
        console.log(this.$el, "---", this.data, "---", "mounted", "---", this.$refs.title, "---", this.$refs.item, "---", this.value);
    },
    beforeUpdate() {
        console.log(this.$el, "---", this.data, "---", "beforeUpdate", "---", this.$refs.title, "---", this.$refs.item, "---", this.value);
    },
    // 更新時觸發
    updated() {
        console.log(this.$el, "---", this.data, "---", "update", "---", this.$refs.title, "---", this.$refs.item, "---", this.value);
    },
    beforeDestroy() {
        console.log(this.$el, "---", this.data, "---", "beforeDestory", "---", this.$refs.title);
    },
    destroyed() {
        console.log(this.$el, "---", this.data, "---", "destroyed", "---", this.$refs.title);
    },
    methods: {
        setNumber(index) {
            this.number = index;
            console.log(index);
        },
        setData() {
            if (oDDEven) {
                this.data = ["hellow"];
                oDDEven = false;

                return;
            }

            this.data = ["Javascript", "Java", "PHP"];
            oDDEven = true;
        }
    },
    watch: {
        watchVal: function(newVal, oldVal) {
            return newVal;
        }
    },
    components: {
        childFileCycle
    }
}
</script>

<style lang="css">
</style>

複製程式碼

結果

由上述執行結果:

我們可以得出,每一個vue例項都會執行beforeCreat、created、beforeMount、mounted這四個鉤子並且只執行一次,
再有資料(必須是與檢視繫結的資料)更新的時候才會執行beforeUpdate、updated這兩個鉤子,
beforeDestroy、destroyed在檢視銷燬的時候觸發。
複製程式碼

子元件

<template lang="html">
    <div class="child-file-cycle">
        <h2>child-file-cycle</h2>
        <div class="">
            child - {{ number }}
        </div>
        <button type="button" name="button" @click="setNumber">setNumber</button>
        <ul>
            <li v-for="(item, index) in data" ref="item" @click="setNumber(index)">child - {{ item }}</li>
        </ul>
    </div>
</template>

<script>
export default {
    props: {
        data: {
            type: Array,
            default: []
        }
    },
    data() {
        return {
            number: Math.random()
        }
    },
    computed: {
    },
    // 元件例項剛被建立,在data屬性之前。
    beforeCreate() {
        console.log("beforeCreate");
    },
    // 元件例項建立完成,data屬性、computed、props、methods、watch已繫結,但DOM還未生成。
    created() {
        console.log("created", this.data);
    },
    beforeMount() {
        console.log("beforeMount");
    },
    // DOM已生成,但不保證已在document中(用this.$nextTick 可以保證已經在document中)
    mounted() {
        console.log("mounted");
    },
    beforeUpdate() {
        console.log("beforeUpdate");
    },
    // 更新時觸發
    updated() {
        console.log("update");
    },
    beforeDestroy() {
        console.log("beforeDestory");
    },
    destroyed() {
        console.log("destroyed");
    },
    methods: {
        setNumber() {
            this.number = Math.random();
        }
    }
}
</script>

<style lang="css">
</style>

複製程式碼

結果圖

在父元件的beforeMount鉤子之後會執行子元件一系列的鉤子函式,將子元件掛載在父元件之後,再將父元件掛載。


更新props影響的鉤子函式

結果圖

更新props的值的時候,會觸發父元件的beforeUpdate,同時也會觸發子元件的beforeUpadte、updated鉤子,最後觸發父元件的updated鉤子。


再一次感謝您花費時間閱讀這份稿!

作者 [@xinwuliu][2]
2018 年 05月 08日

相關文章