Hello大家好,我是日拱一卒的攻城师不浪,专注前端、后端、AI学习、二三维可视化、GIS等学习沉淀,这是2024年输出的第15/100篇文章,欢迎志同道合的朋友交流合作;
前言
之前写了一篇可视化大屏开发,知道了这些经验以及解决方案,效率至少提升2倍!(上)
经验总结,发现有7千
多人比较感兴趣,看来还是有不少人有这方面需求的。
今天我将继续将我的经验全盘托出,毫无保留的奉献出来,希望能够帮助有需要的朋友。
响应式方案
rem
上次已经说了2个
响应式方案,都是基于缩放
去做的,今天我们来讲下rem
方案。
rem原理 :rem单位是基于HTML
元素的font-size
来计算的,这意味着所有使用rem单位的元素的大小都是相对于根元素(即HTML元素)的字体大小来确定的。
举个栗子:
html
<html style="fontSize: 16px">
<head>
<style>
.box {
width: 2rem;
}
</style>
</head>
<body>
<div class='box'>文字</div>
</body>
</html>
此时html的fontSize=16p
x,box元素的宽度是2rem
单位;也就是说,如果1rem = 16px
的话,此时box的渲染宽度应该是2*16=32px
。
那么如果浏览器大小发生变化,此时html的fontSize也会动态改变
。例如浏览器变大,html的fontsize=20px
了,那此时box的宽度就会动态变更成20*2=40px
;
所以说页面内的所有元素我们都使用rem作为单位,然后只需要监听屏幕的缩放,动态去修改html的fontsize即可实现响应式。
Ok,原理明白了,我们接下来直接封装一个基于rem方案的响应式hooks
,方便在vue3的项目里使用,注释我已经写的很清楚了。
js
/*
* @Description: rem响应式方案hooks
*/
import { shallowReadonly, ref } from 'vue'
const flexiableRatio = ref(1)
const SCREEN_WIDTH = 1440 // 设定的浏览器的基准宽度
/**
* 启用自适应
* @param window
* @param document
*/
export const useFlexible = (window, document) => {
const docEl = document.documentElement // 返回文档的root元素
const dpr = window.devicePixelRatio || 1 // 获取设备的dpr,即当前设置下物理像素与虚拟像素的比值
/**
* 设置默认字体大小,默认的字体大小继承自body
*/
function setBodyFontSize() {
if (document.body) {
document.body.style.fontSize = 12 * dpr + 'px'
} else {
document.addEventListener('DOMContentLoaded', setBodyFontSize)
}
}
setBodyFontSize()
/**
* 更新分辨率尺寸
*/
function updateScreenSize() {
const rem = docEl.clientWidth / 10
docEl.style.fontSize = rem + 'px'
flexiableRatio.value = docEl.clientWidth / SCREEN_WIDTH
}
updateScreenSize()
// reset rem unit on page resize
window.addEventListener('resize', updateScreenSize)
window.addEventListener('pageshow', function (e) {
if (e.persisted) {
updateScreenSize()
}
})
return {
flexiableRatio: shallowReadonly(flexiableRatio)
}
}
如何使用?直接在应用的入口文件
,例如main.js
中调用
js
import { createApp } from 'vue'
import App from './App.vue'
import { useFlexible } from '@/hooks/useFlexible'
// 创建并挂载根实例
const app = createApp(App)
// 响应式
useFlexible(window, document)
app.mount('#app')
OK,一处封装,到处使用,感兴趣的还可以把他封装成NPM包,开源使用。
有的公司后台管理系统
也要求做响应式,那么rem是一个不错的方案。
事件监听辅助
eventemmiter
eventemmiter
是一个轻量级的高性能的事件发布/订阅库
,**强推!**它主要有以下优势:
-
事件发布/订阅:允许对象在内部发生某些事件时通知其他对象,这些对象可以订阅这些事件并响应它们。
-
解耦:它帮助实现发布者和订阅者之间的解耦,发布者不需要知道谁在监听事件,订阅者也不需要知道事件是如何产生的。
-
异步事件处理:EventEmitter3 支持异步事件处理,可以提高性能,尤其是在高并发场景下。
-
性能优化:相比于 Node.js 内置的 EventEmitter,EventEmitter3 进行了性能优化,尤其是在处理大量事件监听器时。
在做大屏开发的时候,经常会用到一些二维或者三维的框架,这些框架部分API经常会有事件回调onEvent
,回调是非常难用的,特别遇到跨组件
或者跨类
通信的时候,更是鸡肋。
但是有了eventemmiter,就方便了很多。
安装:
js
npm i eventemitter3
二次封装一个EventEmit类
,当然你也可以直接用,根据个人需求,我这里是兼容做了Promise
的处理:
js
import { EventEmitter } from 'eventemitter3';
/**
* 事件监听触发类
*/
export default class EventEmit {
#ee: EventEmitter; // eventEmitter实例
constructor() {
this.#ee = new EventEmitter();
}
/**
* 一次性事件监听
* @param eventName 事件名称
* @param fn 事件回调
* @returns Promise
*/
once(eventName: string, fn?: (...args: any[]) => void): Promise<unknown> {
if (fn) {
this.#ee.once(eventName, fn);
} else {
return new Promise((resolve) => {
return this.#ee.once(eventName, resolve);
});
}
}
/**
* 事件监听
* @param eventName 事件名称
* @param fn 事件回调
* @returns Promise
*/
on(eventName: string, fn?: (...args: any[]) => void): Promise<unknown> {
if (fn) {
this.#ee.on(eventName, fn);
} else {
return new Promise((resolve) => {
return this.#ee.on(eventName, resolve);
});
}
}
/**
* 移除事件监听
* @param eventName 事件名称
*/
removeListener(eventName: string) {
this.#ee.removeListener(eventName);
}
/**
* 事件触发
* @param eventName 事件名称,与on事件名称保持一致
* @param args 需要传递给on的参数
*/
emit(eventName: string, args?: any) {
this.#ee.emit(eventName, args);
}
}
在A类中做监听:
js
import EventEmit from './EventEmitter';
export const ee = new EventEmit();
export class A {
/**UE视频流实例 */
stream: any;
constructor(stream: any) {
this.stream = stream;
// 监听视频流返回的事件回调
this.stream.addResponseEventListener('handle_responses', this.#getUeRes);
}
/**
* UE返回的数据
* @param res 返回的数据
* @returns
*/
#getUeRes(res: any): void {
ee.emit('getUeResponse', res);
}
}
在B类中监听视频流返回的事件回调:
js
import { ee } from '../Base/Base';
export class B {
doSomeThing() {
// do some thing...
// 需要监听视频流的回调,此时就方便很多了
ee.on("getUeResponse", (e) => {
// 视频流返回的内容
})
}
}
OK,就这么简单!再也不用忍受事件回调
的苦难了!
下篇预告
由于篇幅过长,阅读体验不佳,还有一部分汇总我将放到下篇文章,有需要的可以关注起来:
地图(GIS)
相关开源框架推荐以及开源实战案例三维
开发资料整理(模型下载,学习资料汇总)- 大屏常用组件封装(数字翻牌器、跑马灯、3D旋转菜单、滚动列表等)
另外,有需要进技术产品开发交流群(可视化&GIS)可以加我:brown_7778,也欢迎
数字孪生领域
的商业合作。
最后,如果觉得文章对你有帮助,也希望可以一键三连👏👏👏,你的鼓励是支持我持续分享下去的动力~