可视化大屏开发,知道这些解决方案,效率至少提升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,也欢迎数字孪生领域的商业合作。

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

相关推荐
xiaoyalian4 小时前
R语言绘图过程中遇到图例的图块中出现字符“a“的解决方法
笔记·r语言·数据可视化
y先森5 小时前
CSS3中的伸缩盒模型(弹性盒子、弹性布局)之伸缩容器、伸缩项目、主轴方向、主轴换行方式、复合属性flex-flow
前端·css·css3
前端Hardy5 小时前
纯HTML&CSS实现3D旋转地球
前端·javascript·css·3d·html
susu10830189115 小时前
vue3中父div设置display flex,2个子div重叠
前端·javascript·vue.js
IT女孩儿6 小时前
CSS查缺补漏(补充上一条)
前端·css
吃杠碰小鸡7 小时前
commitlint校验git提交信息
前端
虾球xz7 小时前
游戏引擎学习第20天
前端·学习·游戏引擎
我爱李星璇8 小时前
HTML常用表格与标签
前端·html
疯狂的沙粒8 小时前
如何在Vue项目中应用TypeScript?应该注意那些点?
前端·vue.js·typescript
小镇程序员8 小时前
vue2 src_Todolist全局总线事件版本
前端·javascript·vue.js