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的作者決定,但這一切又在情理之中,可以說這是一種必然的選擇。

 

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章