前言
提到数据可视化,那么相信大家第一反应想到的都是各种的图表,毕竟可视化需求一般都是由地图、饼图、柱状图、折线图等之类的各种图表组成。也就是将各种数据组合拆解成直观的通过大屏幕展示各项数据信息,简而言之就是数据可视化大屏项目。那大家肯定多多少少也参与或接触过可视化大屏项目,在项目中,那我么作为开发者来说更多关注的大多都是布局问题
,图表的兼容性问题
,窗口变化后图表样式问题
,还有什么(???)补充一下
2022年完成的最后一个项目,嗯没错,就是数据可视化大屏项目,其实在这之前我有了解过大屏项目,却没有亲自实践过。当时激动的心颤抖的手,我来和你喝杯酒,呵tui,跑题了,这个年还是有味的(清香型)
事实呢,可把我搞的头破血流,每天都是什么鬼,怎么会这样,哎呦我去,怎么又出问题了,快被干趴了。哎呀我服,我服了,大师快来救救我。
大师:
需求明述
那到底什么问题把我搞成这样呢,那就来讲讲是什么需求实现起来让我疯狂。
通俗点说就是两个浏览器之间通信吗。很简单😆😆是吧
解决方案
跨页面通信呢,实现方式还是比较多的,那我也不列举了
就说一下我的实现方式:是大家经常会用到的方式
那就是localStorage
了,当然跨域就不适用了,emmmm
就是这个跨域,咱也不清楚为什么,当时这个项目公司接到了,但是呢,甲方把项目分成了两部分,还有另一公司在负责另一部分。这都没问题,毕竟人家甲方吗。问题来了,交接完成之后,甲方把这来两部分分别部署在了两个 ip(Don't know why),五雷轰顶,两方的数据通信顿时垮了,怎么办,大师说还得继续干,哎加了好几晚的班
实现步骤
刚开始呢,我的想法很简单没有太多的逻辑,不就是左屏页面发送消息
,右屏页面接收消息
吗
项目的开发框架 Vue3
第一版
来看下第一版实现,当时想法也比较简单,待我翻一翻代码提交记录😡
映入眼帘的都是流泪的日子,天天修复,没完没了
看看左右屏页面怎么发送与接收消息的
左屏页面发送消息
localStorage.setItem('页面路径', JSON.stringify('参数信息'))
复制代码
右瓶页面接收消息
window.addEventListener('storage', function (event) {
console.log(event);
localStorage.getItem('event.key')
window.open('')
})
复制代码
这写法看着中规中矩的,但是过于简单了点,也太不够格了。
事实是页面还是比较多的,总不能满眼都是localStorage
吧
第二版
除了localStorage
还需要改什么呢,之前说了右侧页面是需要根据左侧跳转的,那也用到了keep-alive
保存页面状态,那大家这个时候应该都会想到vue
的钩子函数吧onActivated
,是的,必须要用到它,在页面切换时,需要接着渲染数据并且重新让右侧屏幕监听数据通信
const WebStorage = {
set: (key: string, value: any) => {
localStorage.setItem(key, JSON.stringify(value));
},
get: (key: string) => {
const val = localStorage.getItem(key);
if (val) {
return JSON.parse(val);
}
return '';
},
remove: (key: string) => {
localStorage.removeItem(key);
},
};
复制代码
左屏页面发送消息
WebStorage.set('页面路径', '参数信息');
复制代码
右屏页面接收消息
onActivated(() => {
window.addEventListener('storage', function (event) {
console.log(event);
WebStorage.get('event.key')
window.open('')
})
}
复制代码
完善需求问题优化
第二版其实大概的实现方向已经完成了,数据通信也没问题,剩下的就是往里填充一些逻辑了。
那我们在想想,还有哪些问题需要优化完善
当页面组件被切换移出keep-alive
时,还需要清掉window.addEventListener('storage',()=>{})
,需要用到 onDeactivated
还有个需求,当右屏没被打开时,左屏时可以操作直接打开右屏的,关闭右屏左屏不受影响
关闭网页时,需要清空所有存储信息,防止对下次进入网页有影响
两个浏览器 tabs 在切换窗口后失活问题
之前localStorage.setItem('页面路径','')
已页面路径作为参数的原因呢,一是因为页面比较多,二是因为切换页面通过onActivated
激活后,方便通过当前页面的路径作为参数继续监听数据通信
问题解决方案
那我们按照上边几点内容逐个解决下
第一点
只需要在移出时,移除对 storage 的监听事件
onDeactivated(() => {
window.removeEventListener('storage', ()=>{});
});
复制代码
第二点
就是需要来判断下右屏的状态
既然要控制右屏,那最好还是用单独的一个 localstorage 来存储右屏状态
给定义个名称SCREEN-RIGHT-STATUS
在操作打开右屏时判断下右屏状态,已经打开的话,是不需要在新开窗口的
if (!WebStorage.get(SCREEN-RIGHT-STATUS)) {
window.open(obj.url);
}
复制代码
那我们在关闭右屏时呢,只需给它移除
WebStorage.remove(SCREEN-RIGHT-STATUS);
复制代码
第三点
就是清空所有存储吗
第四点
需要在页面上解决窗口失活问题
window.document.addEventListener('visibilitychange', () => {
if (window.document.visibilityState === 'visible') {
// 做一些数据的获取
}
});
复制代码
最终版
以上几点内容解决后呢,只需要将它们填充在适当位置,放在对应的页面就可以了,但是呢,体现不出编码能力
最后还是给它来整理一下整成一个 hooks
import { onDeactivated } from 'vue';
// 上边优化的localStorage文件
import WebStorage from '/storage';
// 初始页面的路径
let originalUrl = '';
// 右侧屏幕状态管理器
const SCREEN_RIGHT_SHOW = 'SCREEN-RIGHT-STATUS';
/**
* @param {*} bridgeName 存储状态的KEY值
* @param {*} hasDestroy 是否需要在移除组件时移除监听
* @returns
*/
export function useScreen(bridgeName = 'SCREEN-INTERACTION', hasDestroy = true) {
let listenStoreCb;
// 设置存储信息
function setScreenBridgeValue(obj) {
// obj为跳转页面的路径以及其它参数
// !WebStorage.get(SCREEN_RIGHT_SHOW) 判断右屏是否存在
if (obj.url && !WebStorage.get(SCREEN_RIGHT_SHOW)) {
window.open(obj.url);
}
WebStorage.set(bridgeName, obj);
}
// 获取存储内容
function getScreenBridgeValue() {
return WebStorage.get(bridgeName);
}
// 清除存储内容
function clearScreenBridge() {
WebStorage.remove(bridgeName);
}
// 监听storage动态
function listenScreenBridge(fn, cb?) {
const back = () => {
const data = getScreenBridgeValue();
if (data && data.url) {
// 跳转新页面
if (originalUrl !== data.url) {
// 将路径回传
fn && fn(data.url);
originalUrl = data.url;
}
if (data.data) {
// 存在其他参数,将其他参数回传
cb && cb(data.data);
}
} else {
window.close();
}
};
listenStoreCb = back;
window.addEventListener('storage', listenStoreCb);
//解决window在切换窗口后失活问题
window.document.addEventListener('visibilitychange', () => {
if (window.document.visibilityState === 'visible') {
listenStoreCb();
}
});
}
// 页面跳转
function jumpHref(url) {
window.location.href = url;
}
// 右屏页面方法
function screenDestroy() {
WebStorage.set(SCREEN_RIGHT_SHOW, true);
window.onbeforeunload = function () {
WebStorage.remove(SCREEN_RIGHT_SHOW);
};
}
window.onbeforeunload = function () {
setTimeout(() => {
clearScreenBridge();
}, 300);
};
// 组件移除时出发
onDeactivated(() => {
if (listenStoreCb && hasDestroy) {
window.removeEventListener('storage', listenStoreCb);
}
});
return {
setScreenBridgeValue,
getScreenBridgeValue,
listenScreenBridge,
clearScreenBridge,
jumpHref,
screenDestroy,
};
}
复制代码
主要说明
Key:SCREEN_RIGHT_SHOW; 维护右屏的状态管理
key:SCREEN-INTERACTION; 维护左右两屏的数据通信
使用方法
那最后如何使用呢,我们先看下左右两屏分别需要做的事情
左屏幕需要做的事情
const { setScreenBridgeValue } = useScreen();
setScreenBridgeValue({
url: '页面路径',
data: { xxxxxx:'xxxxxx' },
});
// 打开右侧屏幕在setScreenBridgeValue() 方法内部已处理
复制代码
右屏幕需要做的事情
接收左屏幕传输的数据
根据 url 跳转相应的页面
监听存储数据变化
组件移出时移除监听
onActivated(() => {
// 获取存储书记处
const res = getScreenBridgeValue();
// 对数据根据需求逻辑做些处理
// xxxxxxxxxx
//监听storage更新
listenScreenBridge(
(url) => {
//跳转相应页面
jumpHref(url);
},
(data) => {
// 对数据变化后需求逻辑做些处理
// xxxxxxxxxx
},
);
// 右屏关闭时清除右屏状态
screenDestroy();
});
复制代码
至于上述碰到的问题localStorage
跨域通信
我改用的解决方式是通过url
参数的形式进行了数据的传输,只需要在有需求的地方单独处理这种传输方式
不过应该很大概率不会碰到这个问题
结语
如果感觉此文的大屏数据交互方式对你帮助的话,请不吝点个赞🥺🥺🥺,支持一下
评论