vue使用:生命周期

时间:Nov. 6, 2019 分类:

目录:

vue生命周期图示

vue生命周期图示,下边会介绍各个阶段,可以用来做什么

beforeCreate

beforeCreate阶段,是实例初始化之后,但是还没有进行数据观测(data observer)和event/watcher事件配置之前被调用

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="https://cdn.staticfile.org/vue/2.2.2/vue.min.js"></script>
</head>
<body>
    <div id="app">
        {{ name }}
        <button @click="myClick">点击修改数据</button>
    </div>
    <script>
        new Vue({
            el: "#app",
            data: {
                name: "wanghongyu"
            },
            methods: {
                init: function () {
                    console.log(this.name)
                },
                myClick: function () {
                    this.name = "WHY";
                }
            },
            beforeCreate() {
                console.group("beforeCreate");
                console.log("el: ", this.$el);
                console.log("data: ", this.$data);
                console.log("name: ", this.name);
                console.log("init: ", this.init);
                console.log("myClick: ", this.myClick);
                console.log("innerHTML: ", document.getElementById("app").innerHTML);
            },
            });
    </script>
</body>
</html>

浏览器console显示

beforeCreate
el:  undefined
data:  undefined
name:  undefined
init:  undefined
myClick:  undefined
innerHTML:  
        {{ name }}
        <button @click="myClick">点击修改数据</button>

可以看到只有基础的innerHTML,可以用于创建实例的时候向后端发送请求或者记录一下请求日志等

created

在实例创建完成后被立即调用。在这一步,实例已完成以下的配置:数据观测,属性和方法的运算,watch/event事件回调。挂载阶段还没开始,$el属性目前不可见。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="https://cdn.staticfile.org/vue/2.2.2/vue.min.js"></script>
</head>
<body>
    <div id="app">
        {{ name }}
        <button @click="myClick">点击修改数据</button>
    </div>
    <script>
        new Vue({
            el: "#app",
            data: {
                name: "wanghongyu"
            },
            methods: {
                init: function () {
                    console.log(this.name)
                },
                myClick: function () {
                    this.name = "WHY";
                }
            },
            beforeCreate() {
                console.group("beforeCreate");
                console.log("el: ", this.$el);
                console.log("data: ", this.$data);
                console.log("name: ", this.name);
                console.log("init: ", this.init);
                console.log("myClick: ", this.myClick);
                console.log("innerHTML: ", document.getElementById("app").innerHTML);
            },
            created() {
                console.group("created");
                console.log("el: ", this.$el);
                console.log("data: ", this.$data);
                console.log("name: ", this.name);
                console.log("init: ", this.init);
                console.log("myClick: ", this.myClick);
                console.log("innerHTML: ", document.getElementById("app").innerHTML);
            },
            });
    </script>
</body>
</html>

浏览器console显示

created
el:  undefined
data:  Object
name:  wanghongyu
init:  function n(n){var r=arguments.length;return r?r>1?e.apply(t,arguments):e.call(t,n):e.call(t)}
myClick:  function n(n){var r=arguments.length;return r?r>1?e.apply(t,arguments):e.call(t,n):e.call(t)}
innerHTML:  
        {{ name }}
        <button @click="myClick">点击修改数据</button>

可以看到创建完之后数据和方法都有了

beforeMount

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="https://cdn.staticfile.org/vue/2.2.2/vue.min.js"></script>
</head>
<body>
    <div id="app">
        {{ name }}
        <button @click="myClick">点击修改数据</button>
    </div>
    <script>
        new Vue({
            el: "#app",
            data: {
                name: "wanghongyu"
            },
            methods: {
                init: function () {
                    console.log(this.name);
                },
                myClick: function () {
                    this.name = "WHY";
                }
            },
            beforeCreate() {
                console.group("beforeCreate");
                console.log("el: ", this.$el);
                console.log("data: ", this.$data);
                console.log("name: ", this.name);
                console.log("init: ", this.init);
                console.log("myClick: ", this.myClick);
                console.log("innerHTML: ", document.getElementById("app").innerHTML);
            },
            created() {
                console.group("created");
                console.log("el: ", this.$el);
                console.log("data: ", this.$data);
                console.log("name: ", this.name);
                console.log("init: ", this.init);
                console.log("myClick: ", this.myClick);
                console.log("innerHTML: ", document.getElementById("app").innerHTML);
            },
            beforeMount() {
                console.group("beforeMount");
                console.log("el: ", this.$el);
                console.log("data: ", this.$data);
                console.log("name: ", this.name);
                console.log("init: ", this.init);
                console.log("myClick: ", this.myClick);
                console.log("innerHTML: ", document.getElementById("app").innerHTML);
            },
            });
    </script>
</body>
</html>

浏览器console显示

beforeMount
el:  <div id=​"app">​"
        {{ name }}
        "<button @click=​"myClick">​点击修改数据​</button>​</div>​
data:  {__ob__: po}
name:  wanghongyu
init:  ƒ n(n){var r=arguments.length;return r?r>1?e.apply(t,arguments):e.call(t,n):e.call(t)}
myClick:  ƒ n(n){var r=arguments.length;return r?r>1?e.apply(t,arguments):e.call(t,n):e.call(t)}
innerHTML:  
        {{ name }}
        <button @click="myClick">点击修改数据</button>

可以看到el已经有了,但是没有被渲染数据

mount

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="https://cdn.staticfile.org/vue/2.2.2/vue.min.js"></script>
</head>
<body>
    <div id="app">
        {{ name }}
        <button @click="myClick">点击修改数据</button>
    </div>
    <script>
        new Vue({
            el: "#app",
            data: {
                name: "wanghongyu"
            },
            methods: {
                init: function () {
                    console.log(this.name);
                },
                myClick: function () {
                    this.name = "WHY";
                }
            },
            beforeCreate() {
                console.group("beforeCreate");
                console.log("el: ", this.$el);
                console.log("data: ", this.$data);
                console.log("name: ", this.name);
                console.log("init: ", this.init);
                console.log("myClick: ", this.myClick);
                console.log("innerHTML: ", document.getElementById("app").innerHTML);
            },
            created() {
                console.group("create");
                console.log("el: ", this.$el);
                console.log("data: ", this.$data);
                console.log("name: ", this.name);
                console.log("init: ", this.init);
                console.log("myClick: ", this.myClick);
                console.log("innerHTML: ", document.getElementById("app").innerHTML);
            },
            beforeMount() {
                console.group("beforeMount");
                console.log("el: ", this.$el);
                console.log("data: ", this.$data);
                console.log("name: ", this.name);
                console.log("init: ", this.init);
                console.log("myClick: ", this.myClick);
                console.log("innerHTML: ", document.getElementById("app").innerHTML);
            },
            mounted() {
                console.group("mounted");
                console.log("el: ", this.$el);
                console.log("data: ", this.$data);
                console.log("name: ", this.name);
                console.log("init: ", this.init);
                console.log("myClick: ", this.myClick);
                console.log("innerHTML: ", document.getElementById("app").innerHTML);
            },
            });
    </script>
</body>
</html>

浏览器console显示

mounted
el:  <div id=​"app">​"
        wanghongyu
        "<button>​点击修改数据​</button>​</div>​
data:  {__ob__: po}
name:  wanghongyu
init:  ƒ n(n){var r=arguments.length;return r?r>1?e.apply(t,arguments):e.call(t,n):e.call(t)}
myClick:  ƒ n(n){var r=arguments.length;return r?r>1?e.apply(t,arguments):e.call(t,n):e.call(t)}
innerHTML:  
        wanghongyu
        <button>点击修改数据</button>

beforeUpdate

在数据更新前调用,更适合在更新前访问DOM,比如移除添加的事件监听器

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="https://cdn.staticfile.org/vue/2.2.2/vue.min.js"></script>
</head>
<body>
    <div id="app">
        {{ name }}
        <button @click="myClick">点击修改数据</button>
    </div>
    <script>
        new Vue({
            el: "#app",
            data: {
                name: "wanghongyu"
            },
            methods: {
                init: function () {
                    console.log(this.name);
                },
                myClick: function () {
                    this.name = "WHY";
                }
            },
            beforeCreate() {
                console.group("beforeCreate");
                console.log("el: ", this.$el);
                console.log("data: ", this.$data);
                console.log("name: ", this.name);
                console.log("init: ", this.init);
                console.log("myClick: ", this.myClick);
                console.log("innerHTML: ", document.getElementById("app").innerHTML);
            },
            created() {
                console.group("create");
                console.log("el: ", this.$el);
                console.log("data: ", this.$data);
                console.log("name: ", this.name);
                console.log("init: ", this.init);
                console.log("myClick: ", this.myClick);
                console.log("innerHTML: ", document.getElementById("app").innerHTML);
            },
            beforeMount() {
                console.group("beforeMount");
                console.log("el: ", this.$el);
                console.log("data: ", this.$data);
                console.log("name: ", this.name);
                console.log("init: ", this.init);
                console.log("myClick: ", this.myClick);
                console.log("innerHTML: ", document.getElementById("app").innerHTML);
            },
            mounted() {
                console.group("mounted");
                console.log("el: ", this.$el);
                console.log("data: ", this.$data);
                console.log("name: ", this.name);
                console.log("init: ", this.init);
                console.log("myClick: ", this.myClick);
                console.log("innerHTML: ", document.getElementById("app").innerHTML);
            },
            beforeUpdate() {
                console.group("beforeUpdate");
                console.log("el: ", this.$el);
                console.log("data: ", this.$data);
                console.log("name: ", this.name);
                console.log("init: ", this.init);
                console.log("myClick: ", this.myClick);
                console.log("innerHTML: ", document.getElementById("app").innerHTML);
            }
            });
    </script>
</body>
</html>

需要进行点击,浏览器console显示

beforeUpdate
el:  <div id=​"app">​"
        WHY
        "<button>​点击修改数据​</button>​</div>​
data:  {__ob__: po}
name:  WHY
init:  ƒ n(n){var r=arguments.length;return r?r>1?e.apply(t,arguments):e.call(t,n):e.call(t)}
myClick:  ƒ n(n){var r=arguments.length;return r?r>1?e.apply(t,arguments):e.call(t,n):e.call(t)}
innerHTML:  
        wanghongyu
        <button>点击修改数据</button>

可以看到el和data其实已经变化,但是innerHTML还没有被改变

updated

由于数据更改导致的虚拟DOM重新渲染和打补丁,在这之后会调用该钩子

当这个钩子被调用时,组件DOM已经更新,所以你现在可以执行依赖于DOM的操作。然而在大多数情况下,应该避免在此期间更改状态。如果要相应状态改变,通常最好使用计算属性或watcher取代。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="https://cdn.staticfile.org/vue/2.2.2/vue.min.js"></script>
</head>
<body>
    <div id="app">
        {{ name }}
        <button @click="myClick">点击修改数据</button>
    </div>
    <script>
        new Vue({
            el: "#app",
            data: {
                name: "wanghongyu"
            },
            methods: {
                init: function () {
                    console.log(this.name);
                },
                myClick: function () {
                    this.name = "WHY";
                }
            },
            beforeCreate() {
                console.group("beforeCreate");
                console.log("el: ", this.$el);
                console.log("data: ", this.$data);
                console.log("name: ", this.name);
                console.log("init: ", this.init);
                console.log("myClick: ", this.myClick);
                console.log("innerHTML: ", document.getElementById("app").innerHTML);
            },
            created() {
                console.group("create");
                console.log("el: ", this.$el);
                console.log("data: ", this.$data);
                console.log("name: ", this.name);
                console.log("init: ", this.init);
                console.log("myClick: ", this.myClick);
                console.log("innerHTML: ", document.getElementById("app").innerHTML);
            },
            beforeMount() {
                console.group("beforeMount");
                console.log("el: ", this.$el);
                console.log("data: ", this.$data);
                console.log("name: ", this.name);
                console.log("init: ", this.init);
                console.log("myClick: ", this.myClick);
                console.log("innerHTML: ", document.getElementById("app").innerHTML);
            },
            mounted() {
                console.group("mounted");
                console.log("el: ", this.$el);
                console.log("data: ", this.$data);
                console.log("name: ", this.name);
                console.log("init: ", this.init);
                console.log("myClick: ", this.myClick);
                console.log("innerHTML: ", document.getElementById("app").innerHTML);
            },
            beforeUpdate() {
                console.group("beforeUpdate");
                console.log("el: ", this.$el);
                console.log("data: ", this.$data);
                console.log("name: ", this.name);
                console.log("init: ", this.init);
                console.log("myClick: ", this.myClick);
                console.log("innerHTML: ", document.getElementById("app").innerHTML);
            },
            updated() {
                console.group("updated");
                console.log("el: ", this.$el);
                console.log("data: ", this.$data);
                console.log("name: ", this.name);
                console.log("init: ", this.init);
                console.log("myClick: ", this.myClick);
                console.log("innerHTML: ", document.getElementById("app").innerHTML);
            }
            });
    </script>
</body>
</html>

需要进行点击,浏览器console显示

updated
es601.html:74 el:  <div id=​"app">​"
        WHY
        "<button>​点击修改数据​</button>​</div>​
es601.html:75 data:  {__ob__: po}
es601.html:76 name:  WHY
es601.html:77 init:  ƒ n(n){var r=arguments.length;return r?r>1?e.apply(t,arguments):e.call(t,n):e.call(t)}
es601.html:78 myClick:  ƒ n(n){var r=arguments.length;return r?r>1?e.apply(t,arguments):e.call(t,n):e.call(t)}
es601.html:79 innerHTML:  
        WHY
        <button>点击修改数据</button>

beforeDestroy

实例销毁之前调用。在这一步,实例仍然完全可用。频繁的创建和销毁组件对性能的影响很大,因此可以使用activated和deactivated。

在父组件操作isShow,然后控制子组件Laside是否存在

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="https://cdn.staticfile.org/vue/2.2.2/vue.min.js"></script>
</head>
<body>
    <div id="app">
        <App></App>
    </div>

    <script>
        let Laside = {
            template: `
                <div>
                    <h1>{{ mes }}</h1>
                    <button @click="changeData">点击修改数据</button>
                </div>
            `,

            data () {
                return {
                    mes: "Hello Vue!"
                }
            },

            methods: {
                changeData: function () {
                    this.mes = "why is here!";
                }
            },

            // 组件的创建和销毁对性能有影响
            beforeDestroy() {
                console.group("beforeDestroy");
                console.log("el: ", this.$el);
                console.log("data: ", this.$data);
                console.log("mes: ", this.mes);
            },
        };

        let App = {
            template: `
                <div >
                    <Laside v-if="isShow"></Laside>
                    <button @click="showHide">创建消除组件</button>
                </div>
            `,
            components: {
                "Laside": Laside,
            },
            methods: {
                showHide: function () {
                    this.isShow = !this.isShow;
                }
            },
            data () {
                return {
                    isShow: true,
                }
            }
        };

        new Vue({
            el: "#app",
            // 在template中使用组件与在body中使用组件是一样的
            // template: `<cont></cont>`,
            components: {
                App,
            }
        })
    </script>
</body>
</html>

多次点击发现,之后在销毁的之后console里可以看到

beforeDestroy
el:  <div>​<h1>​Hello Vue!​</h1>​<button>​点击修改数据​</button>​</div>​
data:  {__ob__: po}
mes:  Hello Vue!

destroyed

Vue实例销毁后调用。调用后,Vue实例指示的所有东西都会解绑定,所有的事件监听器会被移除,所有的子实例也会被销毁。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="https://cdn.staticfile.org/vue/2.2.2/vue.min.js"></script>
</head>
<body>
    <div id="app">
        <App></App>
    </div>

    <script>
        let Laside = {
            template: `
                <div>
                    <h1>{{ mes }}</h1>
                    <button @click="changeData">点击修改数据</button>
                </div>
            `,

            data () {
                return {
                    mes: "Hello Vue!"
                }
            },

            methods: {
                changeData: function () {
                    this.mes = "why is here!";
                }
            },

            // 组件的创建和销毁对性能有影响
            beforeDestroy() {
                console.group("beforeDestroy");
                console.log("el: ", this.$el);
                console.log("data: ", this.$data);
                console.log("mes: ", this.mes);
            },
            destroyed() {
                console.group("destroyed");
                console.log("el: ", this.$el);
                console.log("data: ", this.$data);
                console.log("mes: ", this.mes);
            }
        };

        let App = {
            template: `
                <div >
                    <Laside v-if="isShow"></Laside>
                    <button @click="showHide">创建消除组件</button>
                </div>
            `,
            components: {
                "Laside": Laside,
            },
            methods: {
                showHide: function () {
                    this.isShow = !this.isShow;
                }
            },
            data () {
                return {
                    isShow: true,
                }
            }
        };

        new Vue({
            el: "#app",
            // 在template中使用组件与在body中使用组件是一样的
            // template: `<cont></cont>`,
            components: {
                App,
            }
        })
    </script>
</body>
</html>

activated

keep-alive组件激活时调用。<keep-alive>包裹动态组件时,会缓存不活动的组件实例,而不是销毁它们

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="https://cdn.staticfile.org/vue/2.2.2/vue.min.js"></script>
</head>
<body>
    <div id="app">
        <App></App>
    </div>

    <script>
        let Laside = {
            template: `
                <div>
                    <h1>{{ mes }}</h1>
                    <button @click="changeData">点击修改数据</button>
                </div>
            `,

            data () {
                return {
                    mes: "Hello Vue!"
                }
            },

            methods: {
                changeData: function () {
                    this.mes = "why is here!";
                }
            },

            activated() {
                console.group("activated");
                console.log("el: ", this.$el);
                console.log("data: ", this.$data);
                console.log("mes: ", this.mes);
            },
        };

        let App = {
            template: `
                <div >
                    <keep-alive>
                        <Laside v-if="isShow"></Laside>
                    </keep-alive>
                    <button @click="showHide">创建消除组件</button>
                </div>
            `,
            components: {
                "Laside": Laside,
            },
            methods: {
                showHide: function () {
                    this.isShow = !this.isShow;
                }
            },
            data () {
                return {
                    isShow: true,
                }
            }
        };

        new Vue({
            el: "#app",
            // 在template中使用组件与在body中使用组件是一样的
            // template: `<cont></cont>`,
            components: {
                App,
            }
        })
    </script>
</body>
</html>

浏览器console显示

activated
el:  <div>​<h1>​Hello Vue!​</h1>​<button>​点击修改数据​</button>​</div>​
data:  {__ob__: po}
mes:  Hello Vue!

deactivated

keep-alive组件停用时调用

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="https://cdn.staticfile.org/vue/2.2.2/vue.min.js"></script>
</head>
<body>
    <div id="app">
        <App></App>
    </div>

    <script>
        let Laside = {
            template: `
                <div>
                    <h1>{{ mes }}</h1>
                    <button @click="changeData">点击修改数据</button>
                </div>
            `,

            data () {
                return {
                    mes: "Hello Vue!"
                }
            },

            methods: {
                changeData: function () {
                    this.mes = "why is here!";
                }
            },

            activated() {
                console.group("activated");
                console.log("el: ", this.$el);
                console.log("data: ", this.$data);
                console.log("mes: ", this.mes);
            },
            deactivated() {
                console.group("deactivated");
                console.log("el: ", this.$el);
                console.log("data: ", this.$data);
                console.log("mes: ", this.mes);
            }
        };

        let App = {
            template: `
                <div >
                    <keep-alive>
                        <Laside v-if="isShow"></Laside>
                    </keep-alive>
                    <button @click="showHide">创建消除组件</button>
                </div>
            `,
            components: {
                "Laside": Laside,
            },
            methods: {
                showHide: function () {
                    this.isShow = !this.isShow;
                }
            },
            data () {
                return {
                    isShow: true,
                }
            }
        };

        new Vue({
            el: "#app",
            // 在template中使用组件与在body中使用组件是一样的
            // template: `<cont></cont>`,
            components: {
                App,
            }
        })
    </script>
</body>
</html>

频繁点击浏览器console显示

activated
el:  <div>​<h1>​Hello Vue!​</h1>​<button>​点击修改数据​</button>​</div>​
data:  {__ob__: po}
mes:  Hello Vue!
deactivated
el:  <div>​<h1>​Hello Vue!​</h1>​<button>​点击修改数据​</button>​</div>​
data:  {__ob__: po}
mes:  Hello Vue!
activated
el:  <div>​<h1>​Hello Vue!​</h1>​<button>​点击修改数据​</button>​</div>​
data:  {__ob__: po}
mes:  Hello Vue!

总结

  1. beforeCreate 实例创建之前除标签外,所有vue需要的数据,事件都不存在
  2. created 创建实例,data被解析到,el还没有找到
  3. beforeMount 标签找到,数据还没有被渲染,事件也没有被监听
  4. Mounted 数据被渲染,开始监听事件
  5. beforeUpdate 数据被更新在虚拟DOM,但是没有渲染到页面上
  6. updated 使用diff算法将虚拟DOM上的数据应用到页面上,此时真实DOM的数据被修改
  7. beforeDestroy 所有数据都存在
  8. destory 所有数据都有(在虚拟DOM中)
  9. keep-alive提供缓存被消除的标签,用active和deactive取代了beforeDestroy和destory