可视化大屏开发,知道这些解决方案,效率至少提升2倍!(中)

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=16px,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,就这么简单!再也不用忍受事件回调的苦难了!

下篇预告

由于篇幅过长,阅读体验不佳,还有一部分汇总我将放到下篇文章,有需要的可以关注起来:

  1. 地图(GIS)相关开源框架推荐以及开源实战案例
  2. 三维开发资料整理(模型下载,学习资料汇总)
  3. 大屏常用组件封装(数字翻牌器、跑马灯、3D旋转菜单、滚动列表等)

另外,有需要进技术产品开发交流群(可视化&GIS)可以加我:brown_7778,也欢迎数字孪生领域的商业合作。

最后,如果觉得文章对你有帮助,也希望可以一键三连👏👏👏,你的鼓励是支持我持续分享下去的动力~

相关推荐
滚雪球~15 分钟前
npm error code ETIMEDOUT
前端·npm·node.js
沙漏无语17 分钟前
npm : 无法加载文件 D:\Nodejs\node_global\npm.ps1,因为在此系统上禁止运行脚本
前端·npm·node.js
supermapsupport18 分钟前
iClient3D for Cesium在Vue中快速实现场景卷帘
前端·vue.js·3d·cesium·supermap
brrdg_sefg20 分钟前
WEB 漏洞 - 文件包含漏洞深度解析
前端·网络·安全
胡西风_foxww26 分钟前
【es6复习笔记】rest参数(7)
前端·笔记·es6·参数·rest
m0_7482548827 分钟前
vue+elementui实现下拉表格多选+搜索+分页+回显+全选2.0
前端·vue.js·elementui
星就前端叭1 小时前
【开源】一款基于Vue3 + WebRTC + Node + SRS + FFmpeg搭建的直播间项目
前端·后端·开源·webrtc
m0_748234521 小时前
前端Vue3字体优化三部曲(webFont、font-spider、spa-font-spider-webpack-plugin)
前端·webpack·node.js
Web阿成1 小时前
3.学习webpack配置 尝试打包ts文件
前端·学习·webpack·typescript
jwensh2 小时前
【Jenkins】Declarative和Scripted两种脚本模式有什么具体的区别
运维·前端·jenkins