对vue生命周期的深入理解


Posted in Vue.js onDecember 03, 2020

一.Vue生命周期简介

官网:https://cn.vuejs.org/v2/api/#beforeCreate

Vue实例从创建到销毁的过程,就是生命周期。详细来说也就是从开始创建、初始化数据、编译模板、挂载Dom、渲染→更新→渲染、卸载等一系列过程。

首先我们来看一下官网的生命周期图(我自己做了一点点注释):

对vue生命周期的深入理解 

Vue提供给我们的钩子为上图的红色的文字

二.钩子详解

 1.beforeCreate

在实例初始化之后,数据观测(data observer) 和 event/watcher 事件配置之前被调用。

<!DOCTYPE html>
<html lang="en">
<head>
 <meta charset="UTF-8">
 <title>Document</title>
 <!-- 引入vue.js -->
 <script type="text/javascript" src='./vue.js'></script>
</head>
<body>
 <div id="app">
 <input type="text" name="" v-model="message">
 {{message}} 
 </div>
 <script type="text/javascript">
 //实例化Vue
 var app = new Vue({
  el:'#app',
  data:{
  message:'this is mseeage'
  },
  //时刻监测数据message的变化,一但那变化就会吊该函数
  watch:{
  //message必须和监测的data名字一样
  message:function(){
   console.log('watch:','message 变了')
  }
  },
  methods:{
  init:function(){
   console.log('这是初始化方法')
  }
  },
  //我们在beforeCreate钩子中调用Vue的data和method
  beforeCreate:function(){
  console.log("beforeCreate",this.message);
  this.init();
  }
 })
 </script> 
</body>
</html>

我们在上面的例子中在的beforeCreate钩子中调用Vue的data和method,来看一下结果

对vue生命周期的深入理解 

可以看到Vue中的data和方法都是去不到的,并且是在wath之前执行

2.created

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

主要应用:调用数据,调用方法,调用异步函数

<div id="app">
 <ul>
  <li v-for="(item,index) of list" key="index">{{item}}--{{message}}</li>
 </ul>

 <p>p1</p>
 <p>p1</p>
 <p>p1</p>
</div>
<script type="text/javascript">
 //实例化Vue
 var app = new Vue({
  el:'#app',
  data:{
   message:'this is mseeage',
   list:['aaaaaaaa','bbbbbbb','ccccccc']
  },
  //时刻监测数据message的变化,一但那变化就会吊该函数
  watch:{
   //message必须和监测的data名字一样
   message:function(){
    console.log('watch:','message 变了')
   }
  },
  methods:{
   foo:function(){
    console.log('foo : ','这是初始化方法')
   }
  },
  //created钩子
  created:function(){
   //调用Vue的data
   console.log("created : ",this.message);
   //调用Vue方法
   this.foo();
   //因为我们是通过v-for循环遍历li,所以created之前挂载阶段还没开始.是无法获取li的个数的
   console.log('li数量:',document.getElementsByTagName('li').length);
   //直接加载出来的DOM是可以直接获取到的
   console.log('p个数:',document.getElementsByTagName('p').length);
  },
 })
</script>

结果

对vue生命周期的深入理解 

可以看到:created钩子可以获取Vue的data,调用Vue方法,获取原本HTML上的直接加载出来的DOM,但是无法获取到通过挂载模板生成的DOM(例如:v-for循环遍历Vue.list生成li)

3.beforeMount

在挂载开始之前被调用:相关的 render 函数(模板)首次被调用。

例如通过v-for生成的html还没有被挂载到页面上

(接 2created的代码)

beforeMount: function () {
  console.log('beforeMount:',document.getElementsByTagName('li').length);
 },

结果 beforeMount: 1

4.mounted

el 被新创建的 vm.$el 替换,并挂载到实例上去之后调用该钩子。

有初始值的DOM渲染,例如我们的初始数据list,渲染出来的li,只有这里才能获取

(接 2created的代码)

mounted: function () {
 console.log('mounted:',document.getElementsByTagName('li').length);
},

结果 mounted: 3

可以看到到这里为止,挂载到实例上了,我们可以获取到li的个数了

5.beforeUpdate

数据更新时调用,发生在虚拟 DOM 重新渲染和打补丁之前。 你可以在这个钩子中进一步地更改状态,这不会触发附加的重渲染过程。

当我们更改Vue的任何数据,都会触发该函数

beforeUpdate: function () {
  console.log('beforeUpdate 钩子执行...');
  console.log('beforeUpdate:'+this.message)
 },

6.updated

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

当这个钩子被调用时,组件 DOM 已经更新,所以你现在可以执行依赖于 DOM 的操作。然而在大多数情况下,你应该避免在此期间更改状态,因为这可能会导致更新无限循环。

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

数据更新就会触发(vue所有的数据只有有更新就会触发),如果想数据一遍就做统一的处理,可以用这个,如果想对不同数据的更新做不同的处理可以用nextTick,或者是watch进行监听

updated: function () {
  console.log('updated 钩子执行...');
  console.log('updated:',this.message)
},

7.beforeDestroy

实例销毁之前调用。在这一步,实例仍然完全可用。

8.destroyed

Vue 实例销毁后调用。调用后,Vue 实例指示的所有东西都会解绑定,所有的事件监听器会被移除,所有的子实例也会被销毁。 该钩子在服务器端渲染期间不被调用。

<div id="app">
</div>
<script type="text/javascript">
 //实例化Vue
 var app = new Vue({
  el:'#app',
  data:{
   message:'this is mseeage',
  },
  beforeDestroy: function () {
   console.log('beforeDestroy 钩子执行...',this.message)
  },
  destroyed: function () {
   console.log('destroyed 钩子执行...',this.message)
  }
 })
 //销毁Vue实例,触发beforeDestroy和destroyed函数
 app.$destroy()
</script>

结果:

对vue生命周期的深入理解 

可以看打到销毁Vue实例时会调用这两个函数

补充$mount

当你vue没有挂在el时,我们可以用$mount

var app = new Vue({
 data:{
   message:'this is mseeage',
  },
}).$mount('#app')

三.钩子的一些实战用法

1.异步函数

这里我们用定时器来做异步函数

<div id="app">
 <ul>
  <li v-for="(item,index) of list" key="index">{{item}}</li>
 </ul>
</div>

<script type="text/javascript">
 var app = new Vue({
  el:'#app',
  data:{
   list:['aaaaaaaa','bbbbbbb','ccccccc']
  },
  created:function(){
   consoloe.log('created异步:aaaaa');
   //异步获取数据
   // 因为是异步,就和我们ajax获取数据一样
   setTimeout(()=>{
    this.list=['111','222','333','444'],
    console.log('created异步:',document.getElementsByTagName('li').length);
   },0)
  },
  mounted: function () {
   console.log('mounted:',document.getElementsByTagName('li').length);
  },
  updated: function () {
   console.log('updated:',document.getElementsByTagName('li').length)
  },
 })
</script>

结果为:

create: aaaaaaaa
mounted: 3
created异步函数: 3
updated: 4

解释:

可以看到因为是在created的钩子中加入异步函数,所以函数的执行顺序为:

ceated钩子,mounted钩子,异步函数,updated钩子(根据事件队列原理,只有在updated后,li才是真的DOM渲染为4个,所以异步函数中获取的li的个数时是没有变化的li的个数)。

因为mounted获取到的是我们在Vue的data中设置初始值渲染的DOM,而我们是在异步函数中变化的list数据,所以mounted获取的li的个数为3。

update函数是只要数据vue绑定的数据变化就会触发,所以最后执行,为4

这是不是意味着可以直接在update函数中操作呢,其实不是,因为update函数是针对vue的所有数据的变化,而我们也有可能会有其他数据的变化。

例如下面的例子:

//我们利用异步函数改变了两次list,会发现update被触发了2次
created:function(){
  //异步获取数据
  // 因为是异步,就和我们ajax获取数据一样
  setTimeout(()=>{
    this.list=['111','222','333','444'],
    console.log('created异步:',document.getElementsByTagName('li').length);
  },0)
  setTimeout(()=>{
    this.list=['快乐大本营','脚踏实地','300033','天天向上','好好学习'],
    console.log('created异步:',document.getElementsByTagName('li').length);
  },1000)
},
mounted: function () {
  console.log('mounted:',document.getElementsByTagName('li').length);
},
updated: function () {
  console.log('updated:',document.getElementsByTagName('li').length)
},

结果为:

对vue生命周期的深入理解

2.Vue.nextTick对异步函数的结果进行操作

我们想要改变数据时,各自触发各自的方法

created:function(){
//异步获取数据
// 因为是异步,就和我们ajax获取数据一样

 //为了在数据变化之后等待 Vue 完成更新 DOM ,可以在数据变化之后立即使用 Vue.nextTick(callback) 。这样回调函数在 DOM 更新完成后就会调用。
 setTimeout(()=>{
  this.list=['111','222','333','444'],
  console.log('created异步:',document.getElementsByTagName('li').length);
  this.$nextTick(function(){
   console.log("created$nextTick:",document.getElementsByTagName('li').length)
  });
 },0)
 setTimeout(()=>{
  this.list=['快乐大本营','脚踏实地','300033','天天向上','好好学习'],
  console.log('created异步:',document.getElementsByTagName('li').length);
  this.$nextTick(function(){
   console.log("created$nextTick:",document.getElementsByTagName('li').length)
  });
 },1000)
},
mounted: function () {
 console.log('mounted:',document.getElementsByTagName('li').length);
},
updated: function () {
 console.log('updated:',document.getElementsByTagName('li').length)
},

结果:

对vue生命周期的深入理解 

我们可以看到通过$nextTick我们可以对异步函数的结果进行各自的操作

到此这篇关于对vue生命周期深入理解的文章就介绍到这了,更多相关vue生命周期的理解内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章希望大家以后多多支持三水点靠木!

Vue.js 相关文章推荐
详解vue实现坐标拾取器功能示例
Nov 18 Vue.js
VUE项目实现主题切换的多种方法
Nov 26 Vue.js
vue实现验证用户名是否可用
Jan 20 Vue.js
vue 计算属性和侦听器的使用小结
Jan 25 Vue.js
Vue中使用wangeditor富文本编辑的问题
Feb 07 Vue.js
Vue多选列表组件深入详解
Mar 02 Vue.js
使用Vue.js和MJML创建响应式电子邮件
Mar 23 Vue.js
vue实现可拖拽的dialog弹框
May 13 Vue.js
vue中 this.$set的使用详解
Nov 17 Vue.js
vue cli4中mockjs在dev环境和build环境的配置详情
Apr 06 Vue.js
vue中this.$http.post()跨域和请求参数丢失的解决
Apr 08 Vue.js
Vue组件化(ref,props, mixin,.插件)详解
May 15 Vue.js
用vue设计一个日历表
Dec 03 #Vue.js
实用的 vue tags 创建缓存导航的过程实现
Dec 03 #Vue.js
如何实现vue的tree组件
Dec 03 #Vue.js
Vue实现图书管理小案例
Dec 03 #Vue.js
Vue router安装及使用方法解析
Dec 02 #Vue.js
vue3.0中setup使用(两种用法)
Dec 02 #Vue.js
vue3.0+vue-router+element-plus初实践
Dec 02 #Vue.js
You might like
PHP对象转换为数组函数(递归方法)
2012/02/04 PHP
yii框架配置默认controller和action示例
2014/04/30 PHP
php使用Image Magick将PDF文件转换为JPG文件的方法
2015/04/01 PHP
PHP的CURL方法curl_setopt()函数案例介绍(抓取网页,POST数据)
2016/12/14 PHP
Javascript学习笔记9 prototype封装继承
2010/01/11 Javascript
javascript 二分法(数组array)
2010/04/24 Javascript
javascript 判断数组是否已包含了某个元素的函数
2010/05/30 Javascript
jquery不会自动回收xmlHttpRequest对象 导致了内存溢出
2012/06/18 Javascript
深入理解JavaScript系列(19):求值策略(Evaluation strategy)详解
2015/03/05 Javascript
zepto与jquery的区别及zepto的不同使用8条小结
2016/07/28 Javascript
js addDqmForPP给标签内属性值加上双引号的函数
2016/12/24 Javascript
vue音乐播放器插件vue-aplayer的配置及其使用实例详解
2017/07/10 Javascript
[34:44]Liquid vs TNC Supermajor 胜者组 BO3 第二场 6.4
2018/06/05 DOTA
详解Python中with语句的用法
2015/04/15 Python
Python实现查找匹配项作处理后再替换回去的方法
2017/06/10 Python
Python tkinter模块弹出窗口及传值回到主窗口操作详解
2017/07/28 Python
python实现NB-IoT模块远程控制
2018/06/20 Python
python读取文本中的坐标方法
2018/10/14 Python
安装好Pycharm后如何配置Python解释器简易教程
2019/06/28 Python
python各层级目录下import方法代码实例
2020/01/20 Python
python设置代理和添加镜像源的方法
2020/02/14 Python
Nginx+Uwsgi+Django 项目部署到服务器的思路详解
2020/05/08 Python
django 连接数据库出现1045错误的解决方式
2020/05/14 Python
HTML5拖拽文件上传的示例代码
2021/03/04 HTML / CSS
全球高级音频和视频专家:HiDef Lifestyle
2019/08/02 全球购物
方正Java笔试题
2014/07/03 面试题
Unix如何在一行中运行多个命令
2015/05/29 面试题
2014最新实习证明模板
2014/10/02 职场文书
旷工检讨书1000字
2015/01/01 职场文书
监考失职检讨书
2015/01/26 职场文书
2015年维修电工工作总结
2015/04/25 职场文书
MySQL系列之开篇 MySQL关系型数据库基础概念
2021/07/02 MySQL
Java实现聊天机器人完善版
2021/07/04 Java/Android
Nginx使用Lua模块实现WAF的原理解析
2021/09/04 Servers
使用Apache Camel表达REST服务的方法
2022/06/10 Servers
如何利用python实现Simhash算法
2022/06/28 Python