跳转到内容

优化

刀刀

12/31/2024

0 字

0 分钟

在项目中,优化也是一个不可或缺的环节,在业务中,我涉及到的优化有以下几点:

  • 代码优化:通过引入第三方库或方法实现同样的功能,代码量更少,易读性更好
  • 性能优化:通过引入第三方库等方法实现地图渲染加载速度优化
  • 体验优化:通过引入第三方库等方法实现用户体验优化

关于优化,在项目中我涉及到的分别有以下几点。

性能优化

数据抽稀

有一个图层需求是渲染地图面,UI效果如下所示:

效果

根据地图官网可以使用 Polygon 方法渲染面。不过由于后端返回的数据量过于庞大,因此在渲染的时候耗时很长,长达半分钟左右才能加载完毕。

这显然是不合理的,因此需要做点优化。在搜索时,发现有一个集成库 Turf.js 用于处理地图数据,其中它有一个 simplify 方法可以简化数据。官网指路:简化多边形 | Turf.js中文网 (fenxianglu.cn)

根据官方文档指示,需要先使用库的 polygon 方法获取需要的数据。该方法传入一个首尾相同数据的三维数组。然后设置抽稀程度、是否允许修改等参数。最后调用 simplify 方法获取到抽稀后的简化版本。

抽稀函数封装如下所示:

js
// 抽稀
export const lessDataFn = arr => {
    // 首尾相同
    arr.forEach(item => item.push(item[0]));
    const option = {tolerance: 0.009, highQuality: false, mutate: true};
    const newArr = arr.map(p => {
        // 如果当前数据长度大于4,则抽稀
        if (p.length >= 4) {
            const arrHandle = simplify(polygon([p]), option);
            return arrHandle.geometry.coordinates[0];
        }
        return p;
    });
    return newArr;
};

接口请求次数

由于数据量过于庞大,后端接口请求速度也会有所变慢,如果网络环境稍差,还会请求失败。此处也可以做一个缓存优化。

一般情况下提到缓存,都会想到浏览器缓存 localStorage ,不过数据量庞大浏览器缓存也未必能够存的下,因此这里可以通过 new Map 缓存到内存中。

如果 new Map().has() 能够拿到数据,说明之前已经调用过接口获取数据并保存,此时直接获取数据即可,不再需要调接口;反之才需要调用接口获取数据并保存。

代码如下所示:

js
const polygonDataMap = new Map();

export const setArea = async payload => {
    if (polygonDataMap.has(payload.areaName + '-search')) {
        xxx.value = polygonDataMap.get(payload.areaName + '-search');
        return;
    }
    const {data} = await yyy(payload);
    districtPolygonList.value = data;
    polygonDataMap.set(payload.areaName + '-search', districtPolygonList.value);
};

保存后运行,可以发现后续页面渲染速度变快很多。

细粒度追踪响应式数据变化

地图产生的相关元素变量,在保存成响应式时,不使用 ref 保存,而是用 shallowRef

在 Vue 3 中,shallowRef 替换掉 ref 的优化是对响应式数据进行更加细粒度的追踪,从而提高性能的优化。

在 Vue 2 中,ref 的实现方式是双向绑定,即当数据变化时,会触发更新视图的操作。然而,这种实现方式有一个缺点:它会追踪整个对象或数组的变化,即使只有其中一个属性发生了变化,也会重新渲染整个对象或数组。这样就会导致性能问题,特别是在处理大型对象或数组时。

Vue 3 中引入了 shallowRef,它通过使用 Proxy 对象来实现,可以进行比较精细的响应式追踪。与 ref 不同的是,shallowRef 只会追踪对象或数组的第一层属性,当第一层属性发生变化时,才会触发更新视图的操作。这样就可以避免不必要的重新渲染,提高性能。

适用场景:

  • 当需要追踪一个简单对象或数组的变化时,可以使用 shallowRef
  • 当需要追踪一个复杂对象或数组的变化时,可以使用 reactiveref 来实现深层次的响应式追踪。

体验优化

Animate.css

在项目中,会需要实现一些交互效果,如打开关闭弹窗、鼠标悬停等等,只是简单的 v-showv-if 或样式 display:hover 自然可以实现功能,但是显得有点单调。如果加上动画效果会给用户更好的体验。

但是纯手写动画效果会消耗一定的时间,前期开发是以效果为主,用时间在动画上显得本末倒置,因此可以使用第三方库 Animate.css 来实现动画效果。官网指路:动画 .css |CSS 动画的跨浏览器库。 (animate.style)

使用流程如下:

  1. 安装依赖

    • npm 安装

      shell
      npm install animate.css --save
      shell
      yarn add animate.css
      shell
      pnpm install animate.css --save
    • cdn 安装

      html
      <head>
        <link
          rel="stylesheet"
          href="https://cdnjs.cloudflare.com/ajax/libs/animate.css/4.0.0/animate.min.css"
        />
      </head>
  2. 引入使用

    js
    import 'animate.css'
    html
    <h1 class="animate__animated animate__fadeIn">An animated element</h1>

    使用时需要加上 animate__animated 类名,然后 animate__ 动画类名前缀加动画名称 fadeIn ,就能实现效果。

  3. 自定义修改动画属性

    • 直接修改 style

      css
      /* 只更改一个动画的持续时间 */
      .animate__animated.animate__bounce {
        --animate-duration: 2s;
      }
      
      /* 更改所有动画的持续时间 */
      :root {
        --animate-duration: 800ms;
        --animate-delay: 0.9s;
      }
    • 特殊类名修改

      html
      <div class="animate__animated animate__bounce animate__delay-2s">Example</div>

接口调用调整

在微观二维的场景下,用户可以通过点击类型筛选按钮筛选结构物,在之前的做法是点击后调用接口获取新的数据,把扎点清空后重新渲染。

后续产品提出清空后渲染不利于用户体验,需要改进。

修改后的逻辑为在最开始统一获取全部的数据,通过 filter 依次保存,后续用户点击时通过 v-if 显隐对应的扎点即可。