vue组件生命周期
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了vue组件生命周期相关的知识,希望对你有一定的参考价值。
参考技术A该函数执行在组件创建、数据观测 (data observer) 和 event/watcher 事件配置之前,实例初始化之后被调用。 数据还没有初始化
在该阶段组件未创建,不能访问数据,组件中的 data,ref 均为 undefined。
在组件创建完成后立即调用
在这一步 实例已经完成了数据观测 属性和方法的运算 watch、event事件回调
但是还没有渲染成html模板 组件中的data已经存在 可以进行操作了 但是el仍然是undefiend 因为挂载阶段还没有开始,$el属性尚不可用
数据已经完成了初始化 dom结构未生成
该函数在挂载之前被调用,该阶段页面上还没有渲染,data已经初始化完成 ref还不可以操作 render函数首次被调用
可以访问数据 编译模板结束 虚拟dom已经存在
该函数是在组件挂载完成之后执行的 这时候el被$el替换,已经可以操作ref了
一般在这个阶段请求数据 filter过滤器也是在这个阶段生效
服务器渲染期间不被调用
在数据更新时调用,在虚拟dom更新前,在特殊情况下,可以讲更新前的数据存起来,放到之后使用
这里适合在更新前访问现有的dom比如移除事件监听器
该钩子只有初次渲染会在服务端进行
data中的数据是最新的,且页面并未和最新的数据同步。
由于数据更改导致的虚拟 DOM 重新渲染和打补丁,在这之后会调用该钩子。当这个钩子被调用时,组件 DOM 已经更新,所以你现在可以执行依赖于 DOM 的操作。
页面也完成了更新,此时,data数据是最新的,同时,页面上呈现的数据也只最新的。
在实例销毁之前调用,这里依然可以操作,可以在这里清除定时器 防止内存泄漏
当执行该生命周期函数的时候,实例身上所有的data,所有的methods以及过滤器…等都处于可用状态,并没有真正执行销毁
在销毁后调用 所有子实例被销毁 所有的事件监听器会被移除
在服务器渲染期间不被调用
此时组件以及被完全销毁,实例中的所有的数据、方法、属性、过滤器…等都已经不可用了
和上面的beforeDestroy和destroyed用法差不多,但是如果我们需要一个实例,在销毁后再次出现的话,用 beforeDestroy和destroyed的话,就太浪费性能了。实例被激活时使用,用于重复激活一个实例的时候
被 keep-alive 缓存的组件激活时调用。
该钩子在服务器端渲染期间不被调用。
实例没有被激活时。
被 keep-alive 缓存的组件停用时调用。
该钩子在服务器端渲染期间不被调用。
当捕获一个来自子孙组件的错误时被调用。此钩子会收到三个参数:错误对象、发生错误的组件实例以及一个包含错误来源信息的字符串。此钩子可以返回 false 以阻止该错误继续向上传播。
vue 关于生命周期
序言:
1. vue 单组件的生命周期;
2. vue 父子组件的生命周期;
3. axios 异步请求 与 vue 的组件周期;
一、vue 每个组件的生命周期
关于每个组件的生命周期,官方文档里也提供了,网上也能搜到各路大神们的相关文章,这里不赘述,贴一个网址以及简单总结。
简单总结:
1.beforeCreate 此时 $el、data 的值都为 undefined ;
2.created 此时可以拿到 data 中的值,但是 this.$el 任然是 undefined ;
3.beforeMounte 此时可以打印 this.$el, 但是当中的 {{ data }} 还没有被替换,this.$el 是虚拟节点;
4.mounted data,$el 均可以被打印,{{ data }} 也已经被替换成正式的 Dom, vue实例被挂载在真实的 dom 树上;
5.beforeUpdate/updated ;
6.beforeDestroy/destroyed;
一张简单示意图:
二、父子组件的生命周期
在项目中,平时可能更多的是关心单个组件的生命周期。
最近手头的一个项目有一个优化:入口是一个平台(父系统),在这个父系统中点击按钮进入子系统的相应模块,当然,窗口打开方式是 _blank,父子系统之间的通信流程是,vue路由导航守卫根据 cookie 中的 token 设置,cookie 中如过有 token ,正常跳转,没有 token ,通过 H5 postMessage() / window.addEventListener(‘message‘, function(event){}, false) 来向父系统获取 toke, 在回调函数 function(event){} 中,将获取的token 首先放入 cookie 中,这样,下次 axios 请求时可以从 cookie 中取值并设置请求头,其他用户信息等在依此根据 token 去获取并存入 localStorage 中。
不过问题就出现在 _blank 上(这是技术选型的时候没有考虑的,vue 比较适合 spa 项目),如果我先以一个账号信息进入子系统的一个模块(打开了一个新标签页),然后不关闭这个页面回到父系统的窗口,切换账号登陆父系统,任然点击进入同一个子系统的模块,此时会发现,这次进入时拉取的数据是依据 localStorage 中存放的前一个 userId 拉取的,但是,F5 刷新一下就能拉取正确信息,这就不合理了。
后来阅读源码,发现,子系统中最基础的子组件中某些关键信息都是从 localStorage 中获取,而每个模块中都有 postMessage 方法,只不过这个方法是在父组件的 mounted 阶段才调用,这就是导致了上面的换账号后进入模块,子组件根据 localStorage/cookie 中的前账号信息先去拉取数据,完成初始化,到所有子组件的初始化完成后父组件才执行 mounted 中 postMessage 方法,获取并在 cookie 中设置后账号的 token ,然后 F5 刷新时,所用的请求头中是后账号的 token,才拉取到正确的数据。
这里面的父子组件的生命周期是:
1.加载渲染过程:
父 beforeCreate -> 父 created -> 父 beforeMount -> 子 beforeCreate -> 子 created -> 子 beforeMount -> 子 mounted -> 父 mounted
2.子组件更新过程
父 beforeUpdate -> 子 beforeUpdate -> 子 updated -> 父 updated
3.父组件更新过程
父 beforeUpdate -> 父 updated
4.销毁过程
父 beforeDestroy -> 子 beforeDestroy -> 子 destroyed -> 父 destroyed
明白了父子组件的渲染时间点,那在父组件 beforeCreate / created / beforeMount 时调用 postMessage 方法不就可以了吗?
答案是不行。为什么?因为异步。我尝试了,在 父组件 的上面三个阶段内调用 postMessage 方法,其回调函数的执行一定会落后于子组件的渲染挂载,即 子组件凭借 cookie / loaclStorage 里面的前账号信息拉取数据 一定会在 后账号的 token 被存放到 cookie 中之前执行,这是其一;其二,因为 vue 推荐的是 axios 请求模块,这是一个异步请求模块,即使在父组件三个阶段内去更新用户信息,这一步依然会落后于子组件的渲染挂载。
那么如何解决?
我的解决办法:组件内路由钩子 beforeRouteEnter(to, from, next)
在这个钩子中,调用 postMessage,获取 最新 token, 在其回调函数中,凭借新的 token, 使用 jquery(本来项目中有依赖)发送 一个拉取用户关键信息的 ajax 请求,这个请求设置成同步,获取到数据后,将相关信息更新到 cookie / localStorage 中,确保后续的请求都是依据最新的用户信息。在确保上面的操作全部完成之后,next() 到想要的路由上去。
尾声:
axios 中没有同步请求,$.ajax 也不推荐使用同步请求。需求如此,尚未找到更好的解决办法,vue 仍需探索。
以上是关于vue组件生命周期的主要内容,如果未能解决你的问题,请参考以下文章