vue组件的生命周期钩子

1,063 阅读3分钟

data

组件生命周期

组件生命周期指的是组件从创建到销毁的过程,在这个过程中的一些不同的阶段,vue 会调用指定的一些组件方法

基本生命周期函数有下面几个阶段:

  • 创建阶段
  • 挂载阶段
  • 更新阶段
  • 卸载阶段

每一个阶段都对应着 之前 和 之后 两个函数

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>

    <div id="app">
        <h1>{{title}}</h1>
        <button @click="show=!show">隐藏</button>
        <hr>
        <template v-if="hasError">
            <h4>有错误发生了</h4>
        </template>
        <template v-else>
            <hhl-component v-if="show" :t="title"></hhl-component>
        </template>
    </div>
    
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>

    <script>

        const hhlComponent = {
            props: ['t'],
            template: `
                <div>
                    <h1>hhlComponent - {{t.a.b}}</h1>
                </div>
            `,
            beforeCreate() {
                console.log('hhlComponent:beforeCreate');
                console.log('data', this.$data);
                console.log('el', this.$el);
                console.log('='.repeat(100));
            },
            created() {
                console.log('hhlComponent:created');
                console.log('data', this.$data);
                console.log('el', this.$el);
                console.log('='.repeat(100));
            },
            beforeMount() {
                console.log('hhlComponent:beforeMount');
                console.log('data', this.$data);
                console.log('el', this.$el);
                console.log('='.repeat(100));
            },
            mounted() {
                console.log('hhlComponent:mounted');
                console.log('data', this.$data);
                console.log('el', this.$el);
                console.log('='.repeat(100));
            },
            beforeUpdate() {
                console.log('hhlComponent:beforeUpdate');
                console.log('props', this.$props);
                console.log('='.repeat(100));
            },
            updated() {
                console.log('hhlComponent:updated');
                console.log('='.repeat(100));
            },
            beforeDestroy() {
                console.log('hhlComponent:beforeDestroy');
                console.log('this', this);
                console.log('='.repeat(100));
            },
            destroyed() {
                console.log('hhlComponent:destroyed');
                console.log('this', this);
                console.log('='.repeat(100));
            }
        }
        
        let app = new Vue({
            el: '#app',
            data: {
                title: '标题',
                show: true,
                hasError: false
            },
            components: {
                'hhl-component': hhlComponent
            },

            beforeCreate() {
                console.log('beforeCreate');
                console.log('data', this.$data);
                console.log('el', this.$el);
                console.log('='.repeat(100));
            },
            created() {
                console.log('created');
                console.log('data', this.$data);
                console.log('el', this.$el);
                console.log('='.repeat(100));
            },
            beforeMount() {
                console.log('beforeMount');
                console.log('data', this.$data);
                console.log('el', this.$el);
                console.log('='.repeat(100));
            },
            mounted() {
                console.log('mounted');
                console.log('data', this.$data);
                console.log('el', this.$el);
                console.log('='.repeat(100));
            },
            beforeUpdate() {
                console.log('beforeUpdate');
                console.log('props', this.$props);
                console.log('='.repeat(100));
            },
            updated() {
                console.log('updated');
                console.log('='.repeat(100));
            },
            beforeDestroy() {
                console.log('beforeDestroy');
                console.log('this', this);
                console.log('='.repeat(100));
            },
            destroyed() {
                console.log('destroyed');
                console.log('this', this);
                console.log('='.repeat(100));
            },
            errorCaptured(err, vm, info) {
                console.log('errorCaptured');
                console.log(err, vm, info);
                console.log('='.repeat(100));
                this.hasError = true;
                return false;
            }
        });
    </script>
</body>
</html>

创建阶段

beforeCreate()

初始化阶段,应用不多

created()

在实例创建完成后被立即调用,该阶段完成了对 data 中的数据的 observer,该阶段可以处理一些异步任务

挂载阶段

beforeMount()

在挂载开始之前被调用,应用不多

mounted()

该阶段执行完了模板解析,以及挂载。同时组件根组件元素被赋给了 $el 属性,该阶段可以通过 DOM 操作来对组件内部元素进行处理了

更新阶段

beforeUpdate()

数据更新时调用,但是还没有对视图进行重新渲染,这个时候,可以获取视图更新之前的状态

updated()

由于数据的变更导致的视图重新渲染,可以通过 DOM 操作来获取视图的最新状态

卸载阶段

beforeDestroy()

实例销毁之前调用,移除一些不必要的冗余数据,比如定时器

destroyed()

Vue 实例销毁后调用

errorCaptured()

当捕获一个来自子孙组件的错误时被调用,此钩子会收到三个参数:错误对象、发生错误的组件实例以及一个包含错误来源信息的字符串。此钩子可以返回 false 以阻止该错误继续向上传播。

ref 与 $refs

如果我们希望获取组件节点,进行 DOM 相关操作,可以通过 ref$refs 来完成

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>

    <div id="app">
        <h1>{{title}}</h1>
        <button @click="getBoxHeight">获取 box 的高度</button>
        <button @click="gethhlComponent">获取自定义组件实例及内部方法</button>
        <hr>
        <div ref="box">
            这是内容<br>这是内容<br>这是内容<br>这是内容<br>这是内容<br>
        </div>
        <hr>
        <hhl-component ref="hhl" :t="title"></hhl-component>
    </div>
    
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>

    <script>

        const hhlComponent = {
            props: ['t'],
            data() {
                return {
                    isShow: true
                }
            },
            template: `
                <div v-if="isShow">
                    <h1>hhlComponent - {{t}}</h1>
                </div>
            `,
            methods: {
                hide() {
                    this.isShow = false;
                }
            }
        }
        
        let app = new Vue({
            el: '#app',
            data: {
                title: '标题'
            },
            components: {
                'hhl-component': hhlComponent
            },
            mounted() {
                console.log(this.$refs.hhl);
            },
            methods: {
                getBoxHeight() {
                    console.log( this.$refs.box.clientHeight );
                },
                gethhlComponent() {
                    this.$refs.hhl.hide();
                }
            }
        });
    </script>
</body>
</html>

ref

给元素或组件添加 ref 属性,则该元素或组件实例对象将被添加到当前组件实例对象的 $refs 属性下面

$refs

该属性的是一个对象,存储了通过 ref 绑定的元素对象或者组件实例对象

nextTick

当数据更新的时候,视图并不会立即渲染,这个时候我们期望获取到视图更新后的数据,可以通过 nextTick 来进行操作

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>

    <div id="app">
        <h1>{{title}}</h1>
        <button @click="setBoxContent">设置新的内容</button>
        <hr>
        <div ref="box" style="background: red" v-html="content"></div>
    </div>
    
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>

    <script>
        
        let app = new Vue({
            el: '#app',
            data: {
                title: '标题',
                n: 1
            },
            computed: {
                content() {
                    return new Array(this.n).fill(this.title).join('<br>');
                }
            },
            methods: {
                setBoxContent() {
                    this.n++;
                    this.$nextTick(_=>{
                        console.log( this.$refs.box.clientHeight );
                    })
                }
            }
        });
    </script>
</body>
</html>

nextTick 方法将在更新队列循环结束之后立即调用