前言
最近碰到了这么一个需求变动:在当前页点击一个按钮打开一个新的页签(本来是在当前页通过路由跳转进入一个新的组件),对于传统jq项目来说这个应该是不费吹灰之力可以实现的,但是对于vue项目来说就要好好斟酌一下了,当时我想到了3种方法来实现:
- 首先,最容易理解的就是构建一个简单的多页应用,即新建一个html入口,不过由于之前没有这样做过,对于要踩哪些坑没有什么把握,同时需要后台进行相关的配置,而这个需求需要马上上线,于是我决定先放弃这个待以后研究。
- 直接使用
window.open
打开新的路由再从vuex种读取之前保存的状态,这种方法直接打开新的页签是无法获取到上一个页面保存在vuex中的信息的。(由于这个项目是多人同时开发而且有些思想不太统一,导致我接手的时候发现有好多路由跳转之前都将一些信息存到了vuex中,个人认为在pc端跨路由最好不要使用vuex,否则刷新页面就啥也没了...) - 既然前两种都暂时行不通,我又想到了使用
localStorage
保存vuex中的信息,因为之前就面临过刷新页面的尴尬,所以使用了sessionStorage
来保存当前登录用户的信息,而sessionStorage
存在时效性,故而选择了localStorage
。(后来发现直接打开新页签,之前页签的sessionstorage还是存在的)
实现过程
1.在打开新页签之前将需要用的vuex状态保存到localStorage
中去,由于这部分内容都在一个模块里面,故可以直接将一个Module
保存到localStorage
,保存Module
对象的时候需要转为JSON字符串(JSON.stringify()
)。
- 读取存入的vuex状态,使用
localStorage.getItem()
读取之后再用JSON.parse()
即可拿到存入的对象。 - 那么问题来了,如何将取出的state,action,mutation等以最小的代价放入写好的组件中呢?我为了仿造vuex的引入甚至参考了一下他的源码(真是高大上,读起来真切感觉到了境界的差距)。
- 引入
state
我们一般在组件中引入的时候用到了扩展运算符,这一部分的原理我以前一直不懂,通过做这个需求也研究了一二。
观摩vuex的源码发现其mapstate函数返回的是一个对象,那么运行以下代码我们可以发现扩展运算符(解构赋值)可以将值'插入'到原对象中
let fn = ()=> {
return{
b: 1,
c: 2
}
}
let obj = {
a: 0,
...fn()
}
console.log(obj);// {a: 0, b: 1, c: 2}
剩下的就是仿照vuex编写自己用的mapstate辅助函数
const PVLISTSTR = localStorage.getItem('pvList');
const PVLIST = JSON.parse(PVLISTSTR);
const MAPSTATE = () => {
let res = {};
Object.keys(PVLIST.state).forEach((k, i) => {
res[k] = function() {
return PVLIST.state[k];
};
});
return res;
};
之后在组件中常规引入,成功取到了!
- 引入
mutation
和action
就在我准备依葫芦画瓢准备搞定mutation和action的时候却漠然发现,原来localStorage并没有将这两个东西真正存进去,从浏览器中看到的localStorage里面action和mutation都是空对象...,查阅相关资料发现了这么一句话:JSON 不允许包含函数,JSON.stringify() 会删除 JavaScript 对象的函数,包括 key 和 value。不过我们可以先将函数转化为字符串再将整个对象转化为JSON字符串。这样的话就得先遍历一遍mutation和action了,到这里往后又出现了两个新的问题:
1>怎么在组件中读取mutation,vuex官网上是这样定义的:Vuex 中的 mutation 非常类似于事件:每个 mutation 都有一个字符串的 事件类型 (type) 和 一个 回调函数 (handler)。类似事件但又不是事件,导致我不知道怎么将他放到组件中去。(原谅我实在看不懂源码了)
2>怎么使用mutation,在mutation中提交载荷来改变state这是vuex的一套逻辑,但是现在毕竟是仿造的(还不是高仿那种),想在短时间内实现和vuex一样的逻辑对我来说有点不现实。
综上所述我还是果断放弃了localStorage
...
重回方法二
前文所述的第三种方案失败了之后,我打算尝试一下第二种方法,如果不行就只好用第一种了,第二种方法使用window.open
直接打开新的页签虽然无法将上一个路由中保存的vuex状态带入下一个路由中,但是我打开调式工具发现新的页签中仍然可以使用vuex,这也就为第二种方法创造了无限的可能!接下来的事就简单而繁琐了,将前一个路由要保存的state全部作为vue-router的params传入新页签路由,再通过新页签组件中的created
将这些参数存入vuex中。(因为新路由中大量使用了上一个路由保存的state,所以我尽量不改变之前的逻辑)这一个过程比较繁琐但也没有什么难点了,只需要不断测试检查是否有遗漏之处。最后介绍一个小技巧:打开新页签可以这样用window.open(${window.location.origin}${window.location.pathname}#/)
在#/后面加上自己的路由。
写在后面
仓促实现这个需求的过程中也暴露出了自己的一些问题,最大的问题就是考虑不周全,使用方法三的时候并没有先充分实验调查就开始写代码,结果浪费了一个晚上的时间写出来的代码都作废了,如果开始写之前就了解到了mutation的问题或许会少走些弯路。
题外话
'失败狮'这个词一出现在我的脑海中我第一个反应是皇家海军,结果百度了一下发现——好吧,我还是提督当久了。
网友评论