当前位置: 首页 > news >正文

初探 Vue 生命周期和钩子函数

生命周期

生命周期函数就是 Vue 实例在某一个时间点会自动执行的函数。

简单来说就是好像把人的出生到死亡分成一个个阶段,你取名字肯定是在你出生阶段,而不是在成年阶段;你结婚肯定是在成年阶段,而不是在出生阶段;如果说你在出生阶段想去阶段,那肯定是不行的。
组件也是一样,在实例化的时特定阶段调用特定方法,调用的这个方法就是钩子函数。

钩子函数

钩子函数和回调函数有什么区别吗?

它们区别是:

js派函数监听事件 => 监听函数就是所谓的钩子函数 => 函数钩取事件:函数主动找事件 => 钩子函数

js预留函数给dom事件,dom事件调用js预留的函数 => 事件派发给函数:事件调用函数 => 回调函数

打个比方:

钩子函数:一个房间里的监控摄像头监控着每一个进入的人的面部特征,识别出了符合条件的人就触发警告(执行函数事件);

回调函数:可以看做是在一片地区埋了许许多多的地雷,一旦踩中了某个地雷(触发事件),地雷就会爆炸(执行函数事件)。

可以简单的理解为:

钩子函数是事件被动的监听,一旦条件触发就执行

回调函数是主动事件,执行函数体内容

生命周期探究

<template>
    <div>{{msg}}</div>
</template>

<script>
export default {
  name: 'HelloWorld',
  data () {
    return {
      msg: 'hello world',
      msg1: ''
    }
  },
  beforeCreate () {
    console.groupCollapsed('beforeCreate 创建前状态')
    console.log('%c%s', 'color:MediumVioletRed', 'el     : ' + this.$el)
    console.log(this.$el)
    console.log('%c%s', 'color:MediumVioletRed', 'data   : ' + this.$data)
    console.log(this.$data)
    console.log('%c%s', 'color:MediumVioletRed', 'msg: ' + this.msg)
    console.groupEnd()
  },
  created () {
    console.groupCollapsed('created 创建前状态')
    console.log('%c%s', 'color:MediumVioletRed', 'el     : ' + this.$el)
    console.log(this.$el)
    console.log('%c%s', 'color:MediumVioletRed', 'data   : ' + this.$data)
    console.log(this.$data.msg)
    console.log('%c%s', 'color:MediumVioletRed', 'msg: ' + this.msg)
    console.groupEnd()
  },
  beforeMount () {
    console.groupCollapsed('beforeMount 挂载前状态')
    console.log('%c%s', 'color:MediumVioletRed', 'el     : ' + this.$el)
    console.log(this.$el)
    console.log('%c%s', 'color:MediumVioletRed', 'data   : ' + this.$data)
    console.log(this.$data.msg)
    console.log('%c%s', 'color:MediumVioletRed', 'msg: ' + this.msg)
    console.groupEnd()
  },
  mounted () {
    console.groupCollapsed('mounted 挂载后状态')
    console.log('%c%s', 'color:MediumVioletRed', 'el     : ' + this.$el)
    console.log(this.$el)
    console.log('%c%s', 'color:MediumVioletRed', 'data   : ' + this.$data)
    console.log(this.$data.msg)
    console.log('%c%s', 'color:MediumVioletRed', 'msg: ' + this.msg)
    console.groupEnd()
    setTimeout(() => {
      this.$data.msg = '123'
    }, 5000)
  },
  activated () {
    console.groupCollapsed('activated 挂载后状态')
    console.log('%c%s', 'color:MediumVioletRed', 'el     : ' + this.$el)
    console.log(this.$el)
    console.log('%c%s', 'color:MediumVioletRed', 'data   : ' + this.$data)
    console.log(this.$data.msg)
    console.log('%c%s', 'color:MediumVioletRed', 'msg: ' + this.msg)
    console.groupEnd()
    setTimeout(() => {
      this.$data.msg = 'hello tiantian'
    }, 10000)
  },
  beforeUpdate () {
    console.groupCollapsed('beforeUpdate 更新前状态')
    console.log('%c%s', 'color:MediumVioletRed', 'el     : ' + this.$el)
    console.log(this.$el)
    console.log('%c%s', 'color:MediumVioletRed', 'data   : ' + this.$data)
    console.log(document.getElementById('app').innerHTML)
    console.log('%c%s', 'color:MediumVioletRed', 'msg: ' + this.msg)
    console.groupEnd()
  },
  updated () {
    console.groupCollapsed('updated 更新后状态')
    console.log('%c%s', 'color:MediumVioletRed', 'el     : ' + this.$el)
    console.log(this.$el)
    console.log('%c%s', 'color:MediumVioletRed', 'data   : ' + this.$data)
    console.log(document.getElementById('app').innerHTML)
    console.log('%c%s', 'color:MediumVioletRed', 'msg: ' + this.msg)
    console.groupEnd()
    setTimeout(() => {
      this.$destroy()
    }, 5000)
  },
  beforeDestroy () {
    console.groupCollapsed('beforeDestroy 实例销毁前状态')
    console.log('%c%s', 'color:MediumVioletRed', 'el     : ' + this.$el)
    console.log(this.$el)
    console.log('%c%s', 'color:MediumVioletRed', 'data   : ' + this.$data)
    console.log(document.getElementById('app').innerHTML)
    console.log('%c%s', 'color:MediumVioletRed', 'msg: ' + this.msg)
    console.groupEnd()
  },
  destroyed () {
    console.groupCollapsed('destroyed 实例销毁后状态')
    console.log('%c%s', 'color:MediumVioletRed', 'el     : ' + this.$el)
    console.log(this.$el)
    console.log('%c%s', 'color:MediumVioletRed', 'data   : ' + this.$data)
    console.log(document.getElementById('app').innerHTML)
    console.log('%c%s', 'color:MediumVioletRed', 'msg: ' + this.msg)
    console.groupEnd()
  }
}
</script>

beforeCreatecreated

beforeCreate:在实例初始化完成时,被执行

created:在初始化结束之后会再初始化一些外部注入和一些双向绑定相关的事情时,被执行

这两个钩子函数执行完之后,初始化基本完成了。

beforeCreate阶段,eldata都没有被挂载;而在created阶段,el还没被挂在,但data已经被挂载了,如下图所示:

这里el为啥没有被挂载呢?

看上图,在created执行完毕后,它会询问一个条件:你这个Vue实例里是否有el这个选项。

如果有就又会询问是否有template这个选项:

  • 如果没有template就会走右侧的分支,

    • 如果这个实例没有template,就会将el这个根节点当做模版,来进行渲染
  • 如果有template就会走左侧的分支

    • template作为模版去渲染

beforeMountmounted

beforeMount:执行时,页面还没有被渲染
mounted:执行时,页面已经被渲染了

从图中也可以看出,在beforeMount执行时,el还没有被挂在;当mounted执行时,el被挂载到页面了。

beforeUpdateupdated

beforeUpdate:数据被改变,还没渲染之前会被执行

updated:数据被改变,渲染完成后会被执行

这张图中有个奇怪的现象,为什么在beforeUpdateupdated两个钩子函数中,elmsg都是一样呢?beforeUpdate执行是不应该是老数据嘛,怎么这里也是最新的数据了?

因为这里的el是虚拟dom,不是真实的dom,和data都是对象,在加上console.log这里是个异步操作,当你点开console.log时,其实代码早就跑完了,数据已经是最新的了,所以就会看到在这两个函数中输出结果是一样的了。

可以用document.getElementById('app').innerHTML获取真实的Dom结构,这时我们就可以看到这两处不一样的地方了。

beforeDestroydestroyed

调用vm.$destroy()方法可对实例销毁

beforeDestroy:实例被销毁前被执行

destroyed:实例被销毁后被执行

activateddeactivated

使用keep-alive标签后,会有两个生命周期函数分别是:activateddeactivated

activated:页面展示的时候被执行

deactivated:页面被隐藏或者页面即将被替换成新的页面时被执行

总结

created:挂载之前需要做的一些事情可以在放在这里面,比如页面加载时loading动画

mounted:向后端发请求,可以放在这个函数中。

这两个钩子函数使用时机重叠部分很多,反正是怎么方便怎么来就是了。

参考资源

  1. Vue2.0 探索之路——生命周期和钩子函数的一些理解
  2. vue2 为什么beforeUpdate时的$el 和$data与updated时的一样
  3. JavaScript:钩子函数与回调函数的区别

相关文章:

  • 关于AWS的Firecracker,技术人应该知道的十件事
  • spring boot 2.0单元测试
  • ansible API 常用模块
  • 追踪解析 FutureTask 源码
  • 再次简单明了总结flex布局,一看就懂...
  • 倒计时3天,公链黑马YOUChain正式开启节点测试
  • 那些被忽略的 JavaScript 数组方法细节
  • 如何抓住下一波零售风口?看RPA玩转零售自动化
  • 可达性分析算法
  • MySQL的sql语言分类DML、DQL、DDL、DCL、
  • 在IIS上部署ASP.NET Core项目出现错误 500.19
  • poj 1088(dfs+dp)
  • flutter的key在widget list的作用以及必要性
  • 深入 Nginx 之配置篇
  • 干货!手把手教你打造自己的seo生态资源,让排名不在是梦想
  • C++11: atomic 头文件
  • css系列之关于字体的事
  • ERLANG 网工修炼笔记 ---- UDP
  • export和import的用法总结
  • Git同步原始仓库到Fork仓库中
  • HashMap ConcurrentHashMap
  • JSONP原理
  • Sublime Text 2/3 绑定Eclipse快捷键
  • Yeoman_Bower_Grunt
  • 测试开发系类之接口自动化测试
  • 讲清楚之javascript作用域
  • 可能是历史上最全的CC0版权可以免费商用的图片网站
  • 如何合理的规划jvm性能调优
  • 思否第一天
  • ​决定德拉瓦州地区版图的关键历史事件
  • ​软考-高级-系统架构设计师教程(清华第2版)【第12章 信息系统架构设计理论与实践(P420~465)-思维导图】​
  • # 日期待t_最值得等的SUV奥迪Q9:空间比MPV还大,或搭4.0T,香
  • #[Composer学习笔记]Part1:安装composer并通过composer创建一个项目
  • %check_box% in rails :coditions={:has_many , :through}
  • (1)常见O(n^2)排序算法解析
  • (4)事件处理——(6)给.ready()回调函数传递一个参数(Passing an argument to the .ready() callback)...
  • (多级缓存)多级缓存
  • (附源码)springboot 个人网页的网站 毕业设计031623
  • (规划)24届春招和25届暑假实习路线准备规划
  • (转)nsfocus-绿盟科技笔试题目
  • (转)重识new
  • .NET 3.0 Framework已经被添加到WindowUpdate
  • .NET CORE使用Redis分布式锁续命(续期)问题
  • .NET 反射 Reflect
  • .NET开源快速、强大、免费的电子表格组件
  • .net项目IIS、VS 附加进程调试
  • .Net中wcf服务生成及调用
  • @require_PUTNameError: name ‘require_PUT‘ is not defined 解决方法
  • @SuppressWarnings(unchecked)代码的作用
  • [100天算法】-实现 strStr()(day 52)
  • [2018/11/18] Java数据结构(2) 简单排序 冒泡排序 选择排序 插入排序
  • [20180224]expdp query 写法问题.txt
  • [ACTF2020 新生赛]Upload 1
  • [C++ 从入门到精通] 12.重载运算符、赋值运算符重载、析构函数
  • [C++]命名空间等——喵喵要吃C嘎嘎