1. 程式人生 > >Vue巢狀元件建立和銷燬的順序

Vue巢狀元件建立和銷燬的順序

       理解生命週期和鉤子函式的呼叫在工程中十分重要,關於Vue生命週期的理解我推薦這一遍詳解Vue生命週期 。寫得真不錯,淺顯易懂,任何初學者一看都能明白是怎麼一回事。今天我當然不是來講生命週期的,我要將的是巢狀元件的建立順序,巢狀元件件鉤子函式的執行順序,最後是銷燬順序。閒話少說,直接上程式碼。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>測試Vue</title>
    <script src="js/vue.js"></script>

</head>
<body>
    <div id="app" style="border: 1px solid red;padding: 10px">
        <div >
            根元件
            <button @click="handleClick">根元件銷燬</button>
        </div>
        <a-component></a-component>
        <b-component></b-component>
    </div>
    
    <script>
        Vue.component('a-component' , {
            template : `
                <div style="border:1px solid black;padding: 10px;margin: 10px">
                    元件A
                    <c-component/>
                </div>
            ` ,
            data(){
                return {
                    name : 'a-component'
                }
            } ,
            beforeCreate(){
                console.log('A元件beforeCreate')
            } ,
            created(){
                console.log('A元件created')
            } ,
            beforeMount(){
                console.log('A元件beforeMount')
            } ,
            mounted(){
                console.log('A元件被mounted')
            } ,
            beforeDestroy(){
                console.log('A元件被beforeDestroy')
            } ,
            destroyed(){
                console.log('A元件被destroyed')
            }
        });
        Vue.component('b-component' , {
            template : `
                <div style="border: 1px solid black;padding: 10px">元件B</div>
            ` ,
            data(){
                return {
                    name : 'b-component'
                }
            } ,
            beforeCreate(){
                console.log('B元件beforeCreate')
            } ,
            created(){
                console.log('B元件created')
            } ,
            beforeMount(){
                console.log('B元件beforeMount')
            } ,
            mounted(){
                console.log('B元件被mounted')
            } ,
            beforeDestroy(){
                console.log('B元件被beforeDestroy')
            } ,
            destroyed(){
                console.log('B元件被destroyed')
            }
        });
        Vue.component('c-component' , {
            template : `
                <div style="border:1px solid black">元件C</div>
            ` ,
            data(){
                return {
                    name : 'c-component'
                }
            } ,
            beforeCreate(){
                console.log('C元件beforeCreate')
            } ,
            created(){
                console.log('C元件created')
            } ,
            beforeMount(){
                console.log('C元件beforeMount')
            } ,
            mounted(){
                console.log('C元件被mounted')
            } ,
            beforeDestroy(){
                console.log('C元件被beforeDestroy')
            } ,
            destroyed(){
                console.log('C元件被destroyed')
            }
        });


        let vm = new Vue({
            el : '#app' ,
            computed : {} ,
            methods : {
                handleClick(){
                    this.$destroy();
                }
            } ,
            beforeCreate(){
                console.log('根元件beforeCreate')
            } ,
            created(){
                console.log('根元件created')
            } ,
            beforeMount(){
                console.log('根元件beforeMount')
            } ,
            mounted(){
                console.log('根元件被mounted')
            } ,
            beforeDestroy(){
                console.log('根元件被beforeDestroy')
            } ,
            destroyed(){
                console.log('根元件被destroyed')
            }
        })
    
    
    </script>


</body>
</html>

在程式碼裡我註冊了三個全域性元件,分別是a-component,b-component和c-component,另外還有一個根元件vm作為入口。

其中根元件下有一個按鈕、a和b兩個元件,a元件下又有c元件。下面來看執行結果:

                                      

        由上面列印的結果,我們可以知道,同一個元件中的beforeCreate,created和beforeMount是按順序執行,並不會因為巢狀元件而打斷。這三個鉤子的執行順序是先外後內,先是根元件的created先執行,接著A元件先執行,意料之中,但接下來C元件先執行created就有點意外了,我們可以認為C元件是A元件的一部分,所以A元件建立的時候也會建立C元件。最後B元件的created執行。另外需要注意,在巢狀元件中,同一個元件beforeMount和mounted不是在一起執行的。接下來看一下掛載順序,沒接觸過的人肯定會感到很驚奇,順序和建立順序完全反過來了。這是怎麼回事呢?這個需要知道beforeMount鉤子到mounted鉤子之間發生了什麼。不清楚可以看一下我上面發的連結,裡面清楚地講到,mounted之後,el中的{{name}}類似的語句和指令都會被替換成真正的文字,也說明mounted之後所有的模板被渲染成DOM了。大家都知道Vue和React中都有virtual dom(虛擬dom),虛擬dom是什麼,按我的理解是按模板的結構使用vnode組織的物件,說白了就是一個物件。模板是被編譯成vdom之後才會被渲染成真正dom,也就是說mounted之後vdom肯定已經存在了,那麼也就是說mounted的執行順序跟dom的組織有關,像c元件在A元件中,所以必須先有c元件的vdom才能有A元件的Vdom。同理,根元件也是如此,先編譯完成a和b元件的vdom才能生成根元件的vdom。這類似遞迴,要想執行完成遞迴函式,必須等最底部的先完成,然後上面的才能一一執行完成。

    接下來,看一下銷燬順序:點選一下銷燬按鈕

                            

      是不是部分猜到,然後關於beforeDestroy部分沒有猜到。這又得看beforeDestroy和destroyed的區別,還是在生命週期那篇文章中。在執行beforeDestroy時,例項還是存在的,即元件裡面的所有資料都是可以使用的,到destryed執行的時候,一切都已被銷燬了,不可以使用元件裡面的所有東西。合理的毀壞方法,我們可以想到,先把最裡面的毀了,再逐步往外銷燬。

       總的來說,鉤子的執行順序肯定是由vue的作者決定,但這一切又在情理之中,可以說這是一種必然的選擇。