序言:
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 仍需探索。
原文地址:https://www.cnblogs.com/cc-freiheit/p/9876565.html