vue2.x之生命周期
生命周期
生命周期是指组件从创建,运行到销毁的阶段。而生命周期函数(也叫生命周期钩子)是vue在关键的时刻帮我们调用的一些特殊名称的函数,会根据生命周期的阶段,依次执行。
从上图可以看出,vue的生命周期分为以下几个阶段:
- beforeCreate
- created
- beforeMount
- mounted
- beforeUpdate
- updated
- beforeDestroy
- destroyed
vue的具体生命周期如下图所示:
其中生命周期函数的名字不可更改,但是函数里面的内容可以自定义编写。 所有的钩子中的this上下文都是自动指向vm实例的,因此在使用钩子函数的时候最好不要使用箭头函数。
组件初始化和挂载
组件初始化和挂载主要是beforeCreate -> created -> beforeMount -> mounted这几个钩子,现在我们了解一下这块的流程。
beforeCreate
在实例初始化之后,进行数据侦听和事件侦听器的配置之前同步调用。 下面我们来看一下这个流程。
❗️ 注意:所有测试效果都必须打断点查看哦
<template> <div id="app"> <div>number的值: {{ number }}</div> <button @click="addNumber">增加number</button> </div> </template> <script> export default { name: 'App', data() { return { number:1 } }, beforeCreate(){ console.log('beforeCreate'); console.log(this); }, methods:{ addNumber(){ this.number++ } } } </script>
效果如下:
此时页面上没有加载出任何内容,无法通过vm访问到data中的数据、methods中的方法
created
在实例创建完成后被立即同步调用。这一步中,实例已经完成对选项的处理,意味着一下内容已被配置完毕:数据侦听、计算属性、方法、事件/侦听器的回调函数。但是这一步挂载阶段还没开始,且$el property目前尚不可用。
<template> <div id="app"> <div>number的值: {{ number }}</div> <button @click="addNumber">增加number</button> </div> </template> <script> export default { name: 'App', data() { return { number:1 } }, /*生命周期*/ beforeCreate(){ console.log('beforeCreate'); console.log(this); }, created(){ console.log('created'); console.log(this); }, /*配置项-方法*/ methods:{ addNumber(){ this.number++ } } } </script>
效果如下:
可以通过vm访问到data中的数据、methods中的方法 如果请求不需要处理DOM节点,其实请求也可以放到这个钩子中完成,这是最早的时间。
beforeMount
在挂载开始之前被调用:相关的render函数首次被调用。
❗️需要注意的是该钩子在服务器渲染期间不被调用。
<template> <div id="app"> <div>number的值: {{ number }}</div> <button @click="addNumber">增加number</button> </div> </template> <script> export default { name: 'App', data() { return { number:1 } }, /*生命周期函数*/ beforeCreate(){ console.log('beforeCreate'); console.log(this); }, created(){ console.log('created'); console.log(this); }, beforeMount(){ console.log('beforeMount'); console.log(document.querySelector('#app')); }, /*配置项-方法*/ methods:{ addNumber(){ this.number++ } } } </script>
效果如下:
1.页面呈现的是未经Vue编译的DOM结构
2.所有对DOM的操作都不奏效
mounted
实例被挂载后调用,这时el被新创建的vm.el替换了。如果根实例挂载到了一个文档内的元素上,当mounted被调用时vm.el也在文档内。
⏰ 需要注意的是mounted不能保证所有的子组件也都被挂载完成。如果你希望整个视图都渲染出来再执行某些操作,建议在mounted钩子中使用vm.$nextTick
<template> <div id="app"> <div>number的值: {{ number }}</div> <button @click="addNumber">增加number</button> </div> </template> <script> export default { name: 'App', data() { return { number:1 } }, /*生命周期函数*/ beforeCreate(){ console.log('beforeCreate'); console.log(this); }, created(){ console.log('created'); console.log(this); }, beforeMount(){ console.log('beforeMount'); console.log(document.querySelector('#app')); }, mounted() { console.log('mounted'); console.log(document.querySelector('#app')); }, /*配置项-方法*/ methods:{ addNumber(){ this.number++ } } } </script>
效果如下:
-
页面中呈现的是经过Vue编译的DOM
-
对DOM的操作均有效(尽可能避免)。至此初始化过程结束。一般在此进行:开启定时器,发送网络请求,订阅消息,绑定自定义事件等初始化操作
组件更新
组件更新主要是beforeUpdate -> updated,现在介绍一下这块的流程。
beforeUpdate
在数据发生改变后,DOM被更新之前被调用。这里适合在现有DOM将要被更新之前访问它,比如移除手动添加的事件监听器。需要注意的是该钩子在服务端渲染期间不被调用,因为只有初次渲染会在服务器端进行。
<template> <div id="app"> <div>number的值: {{ number }}</div> <button @click="addNumber">增加number</button> </div> </template> <script> export default { name: 'App', data() { return { number: 1 } }, /*生命周期函数*/ beforeCreate() { console.log('beforeCreate'); console.log(this); }, created() { console.log('created'); console.log(this); }, beforeMount() { console.log('beforeMount'); console.log(document.querySelector('#app')); }, mounted() { console.log('mounted'); console.log(document.querySelector('#app')); }, beforeUpdate() { console.log('beforeUpdate'); console.log(this.number); }, /*配置项-方法*/ methods: { addNumber() { this.number++ } } } </script>
效果如下:
数据是新的,页面是旧的。即:页面尚未和数据保持同步
updated
在数据更新导致的虚拟DOM重新渲染和更新完毕之后被调用。当这个钩子被调用时,组件DOM已经更新,所以你现在可以执行依赖于DOM的操作。然而在大多数情况下,最好不要在这个钩子里更改状态,最好是借助计算属性和watch来更改。
⏰ 需要注意的是,和mounted一样,updated不会保证所有的子组件也都被重新渲染完毕。如果你希望等到整个视图都渲染完毕,可以在updated里使用vm.$nextTick
<template> <div id="app"> <div>number的值: {{ number }}</div> <button @click="addNumber">增加number</button> </div> </template> <script> export default { name: 'App', data() { return { number: 1 } }, /*生命周期函数*/ beforeCreate() { console.log('beforeCreate'); console.log(this); }, created() { console.log('created'); console.log(this); }, beforeMount() { console.log('beforeMount'); console.log(document.querySelector('#app')); }, mounted() { console.log('mounted'); console.log(document.querySelector('#app')); }, beforeUpdate() { console.log('beforeUpdate'); console.log(this.number); }, updated() { console.log('updated'); console.log(this.number); }, /*配置项-方法*/ methods: { addNumber() { this.number++ } } } </script>
效果如下:
数据是新的,页面也是新的。即:页面和数据保持同步
组件销毁
组件销毁主要是beforeDestroy -> destroyed,这块主要会经历下面的流程。
beforeDestroy
在实例销毁之前调用。在这一步,实例可用。需要注意的是该钩子在服务端渲染期间不被调用。
<template> <div id="app"> <div>number的值: {{ number }}</div> <button @click="addNumber">增加number</button> </div> </template> <script> export default { name: 'App', data() { return { number: 1 } }, /*生命周期函数*/ beforeCreate() { console.log('beforeCreate'); console.log(this); }, created() { console.log('created'); console.log(this); }, beforeMount() { console.log('beforeMount'); console.log(document.querySelector('#app')); }, mounted() { console.log('mounted'); console.log(document.querySelector('#app')); }, beforeUpdate() { console.log('beforeUpdate'); console.log(this.number); }, updated() { console.log('updated'); console.log(this.number); }, beforeDestroy() { console.log('beforeDestroy'); console.log(this); }, /*配置项-方法*/ methods: { addNumber() { this.number++ } } } </script>
效果如下:
vm中所有的data,methods, 指令等等,都处于可用状态,马上要执行销毁过程,一般在此过程:关闭定时器,取消订阅消息,解绑自定义事件等收尾操作
⏰ 有点临死前,交代后世的意思
destroyed
在实例销毁后调用。该钩子被调用后,对应Vue实例的所有指令都被解绑,所有的事件监听器被移除,所有的子实例也都被销毁。
<template> <div id="app"> <div>number的值: {{ number }}</div> <button @click="addNumber">增加number</button> </div> </template> <script> export default { name: 'App', data() { return { number: 1 } }, /*生命周期函数*/ beforeCreate() { console.log('beforeCreate'); console.log(this); }, created() { console.log('created'); console.log(this); }, beforeMount() { console.log('beforeMount'); console.log(document.querySelector('#app')); }, mounted() { console.log('mounted'); console.log(document.querySelector('#app')); }, beforeUpdate() { console.log('beforeUpdate'); console.log(this.number); }, updated() { console.log('updated'); console.log(this.number); }, beforeDestroy() { console.log('beforeDestroy'); console.log(this); }, destroyed() { console.log('destroyed'); console.log(this); }, /*配置项-方法*/ methods: { addNumber() { this.number++ } } } </script>
效果如下: 此时页面按钮已经不能点击了。还能在页面中看到内容是因为页面缓存。