Vue:实例生命周期钩子

一、简介

每个 Vue 实例在被创建时都要经过一系列的初始化过程------例如,需要设置数据监听、编译模板、将实例挂载到 DOM 并在数据变化时更新 DOM 等。同时在这个过程中也会运行一些叫做生命周期钩子的函数 ,这给了用户在不同阶段添加自己的代码的机会。

比如 created 钩子可以用来在一个实例被创建之后执行代码:

bash 复制代码
new Vue({
  data: {
    a: 1
  },
  created: function () {
    // `this` 指向 vm 实例
    console.log('a is: ' + this.a)
  }
})
// => "a is: 1"

也有一些其它的钩子,在实例生命周期的不同阶段被调用,如 mounted、updated 和 destroyed。生命周期钩子的 this 上下文指向调用它的 Vue 实例。
注意: 不要在选项 property 或回调上使用箭头函数 ,比如 created: () => console.log(this.a) 或 vm.$watch('a', newValue => this.myMethod())。因为箭头函数并没有 this,this 会作为变量一直向上级词法作用域查找 ,直至找到为止,经常导致 Uncaught TypeError: Cannot read property of undefined 或 Uncaught TypeError: this.myMethod is not a function 之类的错误。

所有生命周期钩子的 this 上下文将自动绑定至实例中,因此你可以访问 data、computed 和 methods。这意味着你不应该使用箭头函数来定义一个生命周期方法 (例如 created: () => this.fetchTodos()) 。因为箭头函数绑定了父级上下文,所以 this 不会指向预期的组件实例,并且this.fetchTodos 将会是 undefined。

二、生命周期图示

三、生命周期钩子详细

3.1 beforeCreate
  • 类型:Function
    在实例初始化之后,进行数据侦听和事件/侦听器的配置之前同步调用。
  • 参考:生命周期图示
3.2 created
  • 类型:Function
    在实例创建完成后被立即同步调用。在这一步中,实例已完成对选项的处理,意味着以下内容已被配置完毕:数据侦听、计算属性、方法、事件/侦听器的回调函数。然而,挂载阶段还没开始,且 $el property 目前尚不可用。
  • 参考:生命周期图示
3.3 beforeMount
  • 类型:Function
    在挂载开始之前被调用:相关的 render 函数首次被调用。
    该钩子在服务器端渲染期间不被调用。
  • 参考:生命周期图示
3.4 mounted
  • 类型:Function
    实例被挂载后调用,这时 el 被新创建的 vm.el 替换了。如果根实例挂载到了一个文档内的元素上,当 mounted 被调用时 vm.el 也在文档内。
    注意 mounted 不会 保证所有的子组件也都被挂载完成。如果你希望等到整个视图都渲染完毕再执行某些操作,可以在 mounted 内部使用 vm.$nextTick:

    mounted: function () { this.$nextTick(function () { // 仅在整个视图都被渲染之后才会运行的代码 }) }

    该钩子在服务器端渲染期间不被调用。

  • 参考:生命周期图示

3.5 beforeUpdate
  • 类型:Function
    在数据发生改变后,DOM 被更新之前被调用。这里适合在现有 DOM 将要被更新之前访问它,比如移除手动添加的事件监听器

    该钩子在服务器端渲染期间不被调用,因为只有初次渲染会在服务器端进行。

  • 参考:生命周期图示

3.6 updated
  • 类型:Function
    在数据更改导致的虚拟 DOM 重新渲染和更新完毕之后被调用。

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

    注意,updated 不会保证所有的子组件也都被重新渲染完毕。如果你希望等到整个视图都渲染完毕,可以在 updated 里使用 vm.$nextTick:

    updated: function () { this.$nextTick(function () { // 仅在整个视图都被重新渲染之后才会运行的代码 }) }

    该钩子在服务器端渲染期间不被调用。

  • 参考:生命周期图示

3.7 activated
3.8 deactivated
3.9 beforeDestroy
  • 类型:Function
    实例销毁之前调用。在这一步,实例仍然完全可用。

    该钩子在服务器端渲染期间不被调用。

  • 参考:生命周期图示

3.10 destroyed
  • 类型:Function
    实例销毁后调用。该钩子被调用后,对应 Vue 实例的所有指令都被解绑,所有的事件监听器被移除,所有的子实例也都被销毁。

    该钩子在服务器端渲染期间不被调用。

  • 参考:生命周期图示

3.11 errorCaptured(2.5.0+ 新增)
  • 类型:(err: Error, vm: Component, info: string) => ?boolean
    在捕获一个来自后代组件的错误时被调用。此钩子会收到三个参数:错误对象、发生错误的组件实例以及一个包含错误来源信息的字符串。此钩子可以返回 false 以阻止该错误继续向上传播。

    提醒: 你可以在此钩子中修改组件的状态。因此在捕获错误时,在模板或渲染函数中有一个条件判断来绕过其它内容就很重要;不然该组件可能会进入一个无限的渲染循环。

  • 错误传播规则

    • 默认情况下,如果全局的 config.errorHandler 被定义,所有的错误仍会发送它,因此这些错误仍然会向单一的分析服务的地方进行汇报。
    • 如果一个组件的 inheritance chain (继承链)或 parent chain (父链)中存在多个 errorCaptured 钩子,则它们将会被相同的错误逐个唤起。
    • 如果此 errorCaptured 钩子自身抛出了一个错误,则这个新错误和原本被捕获的错误都会发送给全局的 config.errorHandler。
    • 一个 errorCaptured 钩子能够返回 false 以阻止错误继续向上传播。本质上是说"这个错误已经被搞定了且应该被忽略"。它会阻止其它任何会被这个错误唤起的 errorCaptured 钩子和全局的 config.errorHandler。

四、测试结果图

五、代码

bash 复制代码
<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<script src="../vue.js" type="text/javascript">

		</script>
		<!-- https://v2.cn.vuejs.org/v2/guide/instance.html#%E5%AE%9E%E4%BE%8B%E7%94%9F%E5%91%BD%E5%91%A8%E6%9C%9F%E9%92%A9%E5%AD%90 -->
		<!-- https://v2.cn.vuejs.org/v2/api/#%E9%80%89%E9%A1%B9-%E7%94%9F%E5%91%BD%E5%91%A8%E6%9C%9F%E9%92%A9%E5%AD%90 -->
		<!-- https://cn.vuejs.org/v2/api/#%E9%80%89%E9%A1%B9-%E7%94%9F%E5%91%BD%E5%91%A8%E6%9C%9F%E9%92%A9%E5%AD%90 -->
		<title>实例生命周期钩子</title>
	</head>
	<body>

		<div id="vm1">
			{{message}} --- {{a}}
		</div>

		<script>
			//数据对象
			var data = {
				message: '实例生命周期钩子',
				a: 1
			}
			
			var lifeCycleFun = function(funName){
				// console.log('声明周期 ', beforeCreate)// 声明周期里本地函数不能这样写
					console.log('声明周期 '+funName)
			}

			var beforeCreateFun = function() {
				
				console.log('声明周期 beforeCreate ')
			}

			var createdFun = function() {

				console.log('声明周期 created ')
			}

			var beforeMountFun = function() {
				console.log('声明周期 beforeMount ')
			}

			var mountedFun = function() {
				console.log('声明周期 mounted ')
				
				// vm1.$nextTick(function {
				// 	// Code that will run only after the
				// 	// entire view has been rendered
				// })
			}

			var beforeUpdateFun = function() {
				console.log('声明周期 beforeUpdate ')
			}

			var updatedFun = function() {
				console.log('声明周期 updated ')
			}
			
			//每个 Vue 实例在被创建时都要经过一系列的初始化过程------例如,需要设置数据监听、编译模板、将实例挂载到 DOM 并在数据变化时更新 DOM 等。
			//同时在这个过程中也会运行一些叫做生命周期钩子的函数,这给了用户在不同阶段添加自己的代码的机会。

			//也有一些其它的钩子,在实例生命周期的不同阶段被调用,如 mounted、updated 和 destroyed。生命周期钩子的 this 上下文指向调用它的 Vue 实例
			new Vue({
				data:{
					a:1
				},
				created:function(){
					console.log('a is '+this.a)
				},
				// created: () => {
				// 	console.log('a is '+this.a)
				// 	//a is undefined,因为箭头函数并没有 this
				// },
				
			})
			//注意:不要在选项 property 或回调上使用箭头函数,比如 created: () => console.log(this.a) 或 vm.$watch('a', newValue => this.myMethod())。
			//因为箭头函数并没有 this,this 会作为变量一直向上级词法作用域查找,直至找到为止,经常导致 Uncaught TypeError: Cannot read property of undefined 或 Uncaught TypeError: this.myMethod is not a function 之类的错误。

			//该对象被加入到一个Vue实例
			var vm1 = new Vue({
				el: '#vm1',
				data: data,
				// 在实例(Vue)初始化之后,数据观测 (data observer) 和 event/watcher 事件配置之前被调用。整个页面创建之前
				beforeCreate: lifeCycleFun('beforeCreate'),

				//在实例创建完成后被立即调用。在这一步,实例已完成以下的配置:数据观测 (data observer),property 和方法的运算,watch/event 事件回调。然而,挂载阶段还没开始,$el property 目前尚不可用。
				created: lifeCycleFun('created'),

				//在挂载开始之前被调用:相关的 render 函数首次被调用。
				//该钩子在服务器端渲染期间不被调用。
				beforeMount: lifeCycleFun('beforeMount'),

				//实例被挂载后调用,这时 el 被新创建的 vm.$el 替换了。如果根实例挂载到了一个文档内的元素上,当 mounted 被调用时 vm.$el 也在文档内。
				//注意 mounted 不会保证所有的子组件也都一起被挂载。如果你希望等到整个视图都渲染完毕,可以在 mounted 内部使用 vm.$nextTick:
				//该钩子在服务器端渲染期间不被调用。
				mounted: lifeCycleFun('mounted'),

				//数据更新时调用,发生在虚拟 DOM 打补丁之前。这里适合在更新之前访问现有的 DOM,比如手动移除已添加的事件监听器。
				//该钩子在服务器端渲染期间不被调用,因为只有初次渲染会在服务端进行。
				// beforeUpdate: lifeCycleFun('beforeUpdate'), // 共用一个出现一个问题:没有等setTimeout执行三秒钟后就被调用了
					beforeUpdate: beforeUpdateFun,


				//由于数据更改导致的虚拟 DOM 重新渲染和打补丁,在这之后会调用该钩子。
				//当这个钩子被调用时,组件 DOM 已经更新,所以你现在可以执行依赖于 DOM 的操作。然而在大多数情况下,你应该避免在此期间更改状态。如果要相应状态改变,通常最好使用计算属性或 watcher 取而代之。
				//注意 updated 不会保证所有的子组件也都一起被重绘。如果你希望等到整个视图都重绘完毕,可以在 updated 里使用 vm.$nextTick:
				// updated: lifeCycleFun('updated'),// 共用一个出现一个问题:没有等setTimeout执行三秒钟后就被调用了
					updated: updatedFun,
			})
			
			methods: setTimeout(function(){
				vm1.message="三秒之后change..."
			},3000)//执行之后,调用beforeUpdate、updated声明周期
			
		</script>

	</body>
</html>

六、LearnVue 源码

点击查看LearnVue 源码

七、推荐阅读

Vue教程

相关推荐
沈梦研1 小时前
【Vscode】Vscode不能执行vue脚本的原因及解决方法
ide·vue.js·vscode
轻口味2 小时前
Vue.js 组件之间的通信模式
vue.js
fmdpenny4 小时前
Vue3初学之商品的增,删,改功能
开发语言·javascript·vue.js
涔溪5 小时前
有哪些常见的 Vue 错误?
前端·javascript·vue.js
亦黑迷失7 小时前
vue 项目优化之函数式组件
前端·vue.js·性能优化
计算机-秋大田7 小时前
基于SpringBoot的高校教师科研的设计与实现(源码+SQL脚本+LW+部署讲解等)
java·vue.js·spring boot·后端·课程设计
eason_fan8 小时前
分析vue3源码23(异步组件实现)
vue.js·前端框架·源码阅读
BigData-010 小时前
vue视频流播放,支持多种视频格式,如rmvb、mkv
前端·javascript·vue.js
工业互联网专业11 小时前
基于springboot+vue的高校社团管理系统的设计与实现
java·vue.js·spring boot·毕业设计·源码·课程设计
白宇横流学长12 小时前
基于SpringBoot+Vue的旅游管理系统【源码+文档+部署讲解】
vue.js·spring boot·旅游