Vue2.0生命周期的理解


Posted in Javascript onAugust 20, 2018

网上已经有很多关于vue生命周期的文章,我的这篇文章的由来,其实是我对官网上描述的一句话的思考与理解:“el被新创建的vm.$el替换”,所以文章更多的内容可能是在对vue生命周期中“created -> beforeMount -> mounted” 过程的理解。

beforeCreate --> created 之间

在这个阶段初始化事件,进行数据观测。

created

vue实例创建完后被调用,此时已经完成了数据观测(data observer),属性和方法的运算,watch/event 事件回调的配置。

可调用methods中的方法,访问和修改data中的数据,并触发响应式变化使DOM渲染更新,触发watch中相应的方法,computed相关属性进行重新计算。

一般在created时,进行ajax请求初始化实例数据。

此时,vm.$el不可见。

created --> beforeMount 之间

Vue2.0生命周期的理解

 在这个过程中,

a、首先判断实例中是否有el选项,有的话继续向下编译,没有的话会停止编译,直到vm.$mount(el)被调用时才继续(el是挂载的DOM节点);

b、接下来判断实例中是否有template,有的话将其作为模板编译成rander函数;

c、没有template的话就,就将挂载DOM元素的html(即el所对应的DOM元素及其内部的元素)提取出来作为模板编译;

*注:el所对应的DOM元素不能为body/html元素,因为在后面vue实例挂载时,el所对应的DOM元素及其内部的元素会被模板渲染出来的新的DOM所替换。

d、如果实例对象中有rander函数,就直接通过它进行渲染操作。

优先级:rander函数 > template > 外部html

此时,rander函数已经准备好并首次被调用。

在这个过程中,$el被初始化为实例中el选项所对应的DOM元素,所以在beforeMount时,用vm.$el获取到的是挂载DOM元素的html。

beforeMount

 beforeMount被调用时,此时$el可见。

beforeMount --> mounted 之间

在这个过程中,el被新创建的vm.$el所替换,并完成实例的挂载。即实例中的el选项被模板渲染创建出来的DOM元素所替换,页面中的挂载点被渲染出的vue实例代码段所替换。

Mounted

此时实例已挂载到DOM上,可以通过DOM API获取实例中DOM节点。在控制台打印vm.$el,发现之前的挂载点及内容已被替换成新的DOM。

下面通过栗子看一下这两个过程。

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Title</title>
  <script src="https://cdn.bootcss.com/vue/2.5.13/vue.min.js"></script>
</head>
<body>
<div id="app">
  <a id='ela' href="">{{message}}</a>
</div>
</body>
<script>
  var app = new Vue({
    el: '#app',
    data: function () {
      return {
        message: 'hello'
      };
    },
    template: '<p id="elp">{{message}}</p>',
    beforeMount: function () {
      console.group('beforeMount 挂载前状态===============》');
      let state = {
        'el': this.$el,
        'data': this.$data,
        'message': this.message
      }
      let a = document.getElementById('ela');
      let p = document.getElementById('elp');
      console.log(this.$el);
      console.log(state);
      console.log(a);  // <a id='ela' href="">{{message}}</a>
      console.log(p);   // null
    },
    mounted: function () {
      console.group('mounted 挂载结束状态===============》');
      let state = {
        'el': this.$el,
        'data': this.$data,
        'message': this.message
      }
      let a = document.getElementById('ela');
      let p = document.getElementById('elp');
      console.log(this.$el);
      console.log(state);
      console.log(a);  // null
      console.log(p);   // <p id="elp">father</p>
    }
</script>
</html>

Vue2.0生命周期的理解

用template/rander选项可以在控制台清楚的看到:挂载完成后,el被新创建的vm.$el替换。

挂载前是以初始的el和虚拟DOM的形式存在的,此时以template中的内容为模板,模板内容不可见,打印p标签为null;

挂载后,模板渲染的新DOM替换原来的el,原el所对应的DOM不存在,打印a标签为null。

 beforeUpdate 和 updated

当data对象中数据更新时,会触发 beforeUpdate钩子,此时view层还没有更新。 beforeUpdate有下面几个需要注意的地方:

a、更新的数据必须在模板中直接或间接的使用,才会触发beforeUpdate;

b、在挂载之前,data中数据更新不会触发 beforeUpdate!即在created、beforeMount时改变数据不会触发更新流程;

c、如果在beforeUpdate中,再次修改了该数据的值,会再次触发beforeUpdate钩子,进行两次更新流程。

updated时,view层已更新完毕。

(在上面的代码中增加两个钩子)

mounted: function () {
  this.message = 'first';
//   this.show = false;    // 由于模板中没有用到show,所以show的改变不会触发beforeUpdate
},
beforeUpdate: function () {
  console.group('beforeUpdate 更新前状态===============》');
  let elp = document.getElementById('elp').innerHTML;
  console.log('message:' + this.message);
  console.log('DOM:' + elp);
},
updated: function () {
  console.group('updated 更新完成状态===============》');
  let elp = document.getElementById('elp').innerHTML;
  console.log('message:' + this.message);
  console.log('DOM:' + elp);
}

Vue2.0生命周期的理解

这里需要注意一点:view层我们需要通过innerHTML获取对应元素节点中的内容,而不能直接获取元素节点。直接获取元素节点,在控制台打印出来的view层中的数据都是更新之后的状态,不能打印出实时的正确的值,这应该和Chrome控制台的输出有关。

针对第三条,我们看一下下面的代码演示:

mounted: function () {
  this.message = 'first';
},
beforeUpdate: function () {
  console.group('beforeUpdate 更新前状态===============》');
  let elp = document.getElementById('elp').innerHTML;
  console.log('message:' + this.message);
  console.log('DOM:' + elp);
  this.message = 'second';  // 此时在beforeUpdate中再次修改了message的值
},
updated: function () {
  console.group('updated 更新完成状态===============》');
  let elp = document.getElementById('elp').innerHTML;
  console.log('message:' + this.message);
  console.log('DOM:' + elp);
}

Vue2.0生命周期的理解

这里我们可以清楚的看到进行了两次更新流程,但是对打印的结果有些疑问:第一次将message的值改为first,并且以first来渲染更新DOM,那么第一次调用updated时,message和DOM中的值都应该是first,而此时打印出来的时second。我理解的是,在第一次执行updated时,DOM就已经完成了第二次渲染更新,具体的过程还需要通过之后对源码的学习去理解。这里各位有不同的理解或者更详细的解释,可以在评论区留言,共同学习。

在这里,我们可以在beforeUpdate中加定时器去修改message的值,就可以等待第一次数据改变,DOM更新渲染完成后,进行第二次数据改变。

beforeUpdate: function () {
  console.group('beforeUpdate 更新前状态===============》');
  let elp = document.getElementById('elp').innerHTML;
  console.log('message:' + this.message);
  console.log('DOM:' + elp);
  var that = this;
  setTimeout(function(){
  that.message = 'second';
  });
//  this.message = 'second';  // 此时在beforeUpdate中再次修改了message的值
},

Vue2.0生命周期的理解

这里可以清楚看到两次数据改变时,数据和view层的更新状态。

beforeDestroy 和 destroyed

beforeDestroy:实例在销毁之前调用,此时实例仍然可用。

beforeDestroy -> destroyed: Vue 实例指示的所有东西都会解绑定,所有的事件监听器会被移除,所有的子实例也会被销毁。

destroyed:vue实例销毁后调用。

结尾:关于vue生命周期就总结完毕,有错误的地方烦请指出,会及时修改!

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
js不是基础的基础
Dec 24 Javascript
js实现日期级联效果
Jan 23 Javascript
ECMAScript5中的对象存取器属性:getter和setter介绍
Dec 08 Javascript
JavaScript用select实现日期控件
Jul 17 Javascript
JS判断来路是否是百度等搜索索引进行弹窗或自动跳转的实现代码
Oct 09 Javascript
js控制文本框禁止输入特殊字符详解
Apr 07 Javascript
用Webpack构建Vue项目的实践
Nov 07 Javascript
详解在微信小程序的JS脚本中使用Promise来优化函数处理
Mar 06 Javascript
JavaScript JSON数据处理全集(小结)
Aug 15 Javascript
原生js实现的金山打字小游戏(实例代码详解)
Mar 16 Javascript
vue-quill-editor 自定义工具栏和自定义图片上传路径操作
Aug 03 Javascript
OpenLayers实现图层切换控件
Sep 25 Javascript
JavaScript作用域、闭包、对象与原型链概念及用法实例总结
Aug 20 #Javascript
RequireJS用法简单示例
Aug 20 #Javascript
JavaScript实现多态和继承的封装操作示例
Aug 20 #Javascript
浅谈微信小程序之官方UI框架we-ui使用教程
Aug 20 #Javascript
Layui给数据表格动态添加一行并跳转到添加行所在页的方法
Aug 20 #Javascript
微信小程序 MinUI组件库系列之badge徽章组件示例
Aug 20 #Javascript
获取layer.open弹出层的返回值方法
Aug 20 #Javascript
You might like
PHP类中Static方法效率测试代码
2010/10/17 PHP
深入PHP magic quotes的详解
2013/06/17 PHP
php中自定义函数dump查看数组信息类似var_dump
2014/01/27 PHP
php 数组处理函数extract详解及实例代码
2016/11/23 PHP
PHP7实现和CryptoJS的AES加密方式互通示例【AES-128-ECB加密】
2019/06/08 PHP
jquery图片放大功能简单实现
2013/08/01 Javascript
JSON传递bool类型数据的处理方式介绍
2013/09/18 Javascript
JS不间断向上滚动效果代码
2013/12/25 Javascript
JavaScript基础语法、dom操作树及document对象
2014/12/02 Javascript
jQuery解析XML与传统JavaScript方法的差别实例分析
2015/03/05 Javascript
Bootstrap表单制作代码
2017/03/17 Javascript
如何利用@angular/cli V6.0直接开发PWA应用详解
2018/05/06 Javascript
bootstrap 路径导航 分页 进度条的实例代码
2018/08/06 Javascript
详解ES6 Promise对象then方法链式调用
2018/10/20 Javascript
如何基于vue-cli3.0构建功能完善的移动端架子
2019/04/24 Javascript
[47:20]DAC2018 4.4 淘汰赛 Optic vs Mineski 第一场
2018/04/05 DOTA
pyqt5简介及安装方法介绍
2018/01/31 Python
Django进阶之CSRF的解决
2018/08/01 Python
Django model反向关联名称的方法
2018/12/15 Python
Python math库 ln(x)运算的实现及原理
2019/07/17 Python
使用Python实现 学生学籍管理系统
2019/11/26 Python
Python CSV文件模块的使用案例分析
2019/12/21 Python
Python Tkinter图形工具使用方法及实例解析
2020/06/15 Python
Lime Crime官网:美国一家主打梦幻精灵系的彩妆品牌
2019/03/22 全球购物
美国摩托车头盔、零件、齿轮及配件商店:Cycle Gear
2019/06/12 全球购物
荷兰睡眠专家:Beter Bed
2020/11/23 全球购物
个人找工作的自我评价
2013/10/17 职场文书
国际贸易专业个人鉴定
2014/02/22 职场文书
《月光启蒙》教学反思
2014/03/01 职场文书
消防安全宣传口号
2014/06/10 职场文书
大学生就业求职信
2014/06/12 职场文书
家属慰问信
2015/02/14 职场文书
2015年幼儿园中班下学期工作总结
2015/05/22 职场文书
班级联欢会主持词
2015/07/03 职场文书
python中的sys模块和os模块
2022/03/20 Python
Python自动化实战之接口请求的实现
2022/05/30 Python