问题:
通过window.open()新开页面,新页面无法读取到原有的state数据。
解决过程
查阅文档后发现,vuex存储的state数据无法在多页面中进行共享,也就是说新开标签页是无法读取到原页面的state数据的。貌似是因为vuex的故意设计如此,专门为了单页面应用共享数据使用;新开页面的时候会创建一个新的store实例,和原有页面非一个实例。
解决方案
新开页面时通过localStorage浏览器缓存传递数据
代码
// ---原页面,传递数据-------------------------------------------
// vue-router带参打开新页面
const href = this.$router.resolve({
path: '/bill-detail',
query: { ... },
}).href;
const newWindow = window.open(href, '_blank');
// 之所以写这么麻烦,是因为本司系统中部分模块state数据过大,超过了localStorage数据大小限额
// 所以分开模块进行传递
// 所有被缓存的state模块的key
const store_storage_keys = [];
for (const store_item_key in this.$store.state) {
// 捕获报错,防止某store模块state出现问题影响其他模块
try {
// 根据模块key生产跳转前临时存储缓存的key
const key = "STORE_STATE_" + store_item_key.toUpperCase();
// 分模块存储state数据至缓存中
localStorage.setItem(key, JSON.stringify(this.$store.state[store_item_key]));
// 成功存储后将本模块的storage.key存入数据key列表,方便接收页进行获取
store_storage_keys.push(key);
} catch (e) {
// 单模块数据缓存抛错
console.error(store_item_key + "超过数据大小限制,无法传输");
}
}
// 成功存储后将本模块的storage.key存入数据key列表,方便接收页进行获取
localStorage.setItem("STATE_STORAGE_KEYS", store_storage_keys.toString());
// 新标签页打开后发送单据数据
newBillWindow.onload = () => {
newBillWindow.postMessage({
key: 'newWindowKey',
type: 'newWindowKey',
data: { ... },
}, window.location.origin)
}
// ---新页面,接收数据-------------------------------------------
// 本页面是新开页面,需要监听接收父源页面给出的参数
window.addEventListener('message', this.linstenerParentMessage);
// 获取需要接收的所有store.state模块key
const stateKeys = localStorage.getItem("STATE_STORAGE_KEYS")?.split(',');
// 存储获取到的state值
const stateObj = {};
for (let i = 0; i < stateKeys?.length; i++) {
// 根据获取到的state模块storageItem.key还原获取到原本store.state模块key
const originKey = stateKeys[i].replace('STORE_STATE_', '').toLowerCase();
// 获取store每个模块的state数据
const stateItemData = JSON.parse(localStorage.getItem(stateKeys[i]) || {});
// 存入map
Reflect.set(stateObj, originKey, stateItemData);
}
// 保存至当前标签页的store实例数据
this.$store.replaceState(Object.assign({}, this.$store.state, stateObj));