Skip to content
目录

2022年度数据账单项目总结

有两三年没做过年度账单 H5 项目了,接到需求,要在 2022 年末上线,当即火急火燎进行技术调研。看了往年的年度账单,就是一张背景图加上文字渐入效果,相当简单。2022 年时间上还充裕,花了一周时间去了解平时不怎么用的 GSAP 和 animeJS,参考了网易云音乐的年度账单效果,发现需要用 AE 来进行场景的设计,可是自己和 UI 设计师也不熟悉 AE,无奈最后决定使用简单的方法来实现。

交互框架搭建

根据研发讨论,我们的交互应该是整屏的内容切换,切换方式就是上下滑动或者左右滑动,页面进场、离场或者用户操作的过程中页面中的元素应该有对应的动画效果。基于这些想法,想起了很久没用的 fullPage.js,貌似这个满足当前的需求,然而查看证书发现要收费才能使用了,由于平常使用场景比较少就不考虑付费使用,只能另找其它开源库。后来想了下,经常用的 swiperJs 不是也可以满足需求么,滑动就是这个库的强项,而且还开源,所以就选它了。

项目使用了 Vue3.x 版本,而 SwiperJS 也默认支持了 Vue3,所以使用时直接安装引入即可。

安装 swiper:

sh
pnpm i swiper

使用

vue
<swiper ref="swiperRef"
          :effect="'fade'"
          :observer="true"
          :slides-per-view="1"
          :spaceBetween="0"
          :direction="'vertical'"
          :parallax="true"
          :modules="modules"
          @init="onInit"
          @transition-end="onTransitionEnd">
    <swiper-slide class="slide-1"></swiper-slide>
    <swiper-slide class="slide-2"></swiper-slide>
    <swiper-slide class="slide-3"></swiper-slide>
  </swiper>
ts
import { watch, ref, inject } from 'vue'
import { Swiper, SwiperSlide } from 'swiper/vue'
import type { Swiper as SwiperType } from 'swiper'
import { Parallax, EffectFade } from 'swiper'
import 'swiper/css'
import 'swiper/css/effect-fade'

const swiperInstance = ref()
const modules = [Parallax, EffectFade]
const current = ref(0)

/**
 * 滑块初始化
 * @param swiper
 */
const onInit = (swiper: SwiperType) => {
  swiperInstance.value = swiper
  swiper.slideTo(current.value)
}

/**
 * 记录滑块索引
 * @param swiper
 */
const onTransitionEnd = (swiper: SwiperType) => (current.value = swiper.activeIndex)
css
.swiper {
  width: 100%;
  height: 100%;
}

.swiper-slide {
  height: 100%;
  width: 100%;
  font-size: 18px;
  display: flex;
  flex-direction: column;
  justify-content: flex-start;
  align-items: center;
}

.swiper-slide-content {
  width: 100%;
  height: 100%;
}

动画实现

要实现动画效果有很多选择,为了缩小项目体积,摒弃了 anime.jsGSAP 等相关动画库,选择单纯使用 CSS3 的 animation 来实现动画效果。动画库的话就使用 animate.css,再加上 SwiperJS 自带的视觉差效果和渐入渐出转场,也基本满足需求了。

Animate.css 使用

SwiperJS 中直接使用 animate.css 会存在一个问题,就是不会重复执行动画。要解决这个问题其实只需要让动画元素重新渲染即可,要重新渲染最直接的方法是通过 v-if 来控制 swiper-slide 的显示隐藏。如果通过监测 slide-change 事件来改变当前滑块的索引,这样做会出现滑块转场动画执行不完全的状态(比如 fade 转场透明度没执行完),解决这个问题直接通过监测 transition-end 事件进行当前滑块索引更新即可。

替换掉 Anime.js

前期考虑到如果时间充足的话可以使用 anime.js 来细化一些动画的执行,不过后来项目写到尾声才发现,时间不够充裕。前期用到 anime.js 的地方主要是图片资源加载百分比数字动画和文字逐行渐进动画,而在使用的过程中发现 anime.js 本身存在一些问题,加上考虑文件体积,故使用其它方法将其换掉。

百分比数字动画

如果直接修改百分比数字到话,因为网络延迟方面的原因,百分比可能会一下子由一个很小的数字直接变到很大的数字,这样用户看着就会觉得很突兀。

通过 setTimeout 实现

ts
import { ref } from 'vue'

const progressRef = ref(0)
/**
 * 更新进度条百分比
 */
let temp = 0
let timer: any = null
const updateProgress = (num: number) => {
	window.clearTimeout(timer)

	if (temp >= num) return

	temp++

	progressRef.value = temp

	timer = setTimeout(() => updateProgress(num), 16)
}

由于浏览器显示频率的问题,通过 setTimeout 来进行刷新百分比可能出现丢帧现象,我们可以通过 requestAnimation 来优化,具体可以看我的另一篇文章

一些优化

优化主要围绕代码体积、页面加载、渲染效率等方面进行。

可视化查看代码体积

要减少代码体积,我们首先要知道哪些地方代码体积太大了。可视化分析代码体积的库很多,vite 中可使用 rollup-plugin-visualizer

sh
pnpm i rollup-plugin-visualizer -D

安装完后,需要在 vite.config.ts 打包配置中引入。

ts
import vue from '@vitejs/plugin-vue'
import { visualizer } from 'rollup-plugin-visualizer'

export default () => {
    return defineConfig({
        plugins:[vue(), visualizer()]
    })
}

然后执行构建

sh
pnpm run build

构建后在项目根目录会生成一个 stats.html 的文件,直接浏览器打开就可以看到各个代码占的体积。

当然,没必要将分析文件上传到远程代码仓库,可在 .gitignore 中增加排除。

移除 vue-router

经过代码可视化分析,发现项目模板中引入了路由,但由于年度账单无需多页面跳转,没必要引入 vue-router ,移除后能减少几十 K 的代码体积。

去除 animate.css 多余类

项目中使用到的动画有限,没必要引入 animate.css 所有的动画文件。

要按需引入我们需要将 animate.css 的代码仓库拉取下来,在本地修改 animate.css/source/animate.css 中的引入文件,然后执行重新构建。

sh
pnpm run start

在需要使用的地方引入新构建的 animate.css/animate.min.css 文件就行。

遇到的问题

1. 分享出去是链接,不是卡片

微信开放全域名访问后出现的限制。目前可从 公众号菜单进入分享扫描二维码后分享添加到收藏然后从微信我的收藏进入分享 是正常的,其他地方进入分享都是链接。

2. 如何真机调试

由于一些效果在浏览器上复现不了,需要真机上调试。真机调试一般有两种方法,一种是安装 spy-debugger ,另一种是使用 Chrome 浏览器自带的远程调试 chrome://inspect 。 两者各有利弊,前者需要安装证书,后者需要通过 USB 连接调试。具体可参考我的另一篇文章

3. 上线前图片存到 OSS

图片务必存储到 OSS,不然普通服务器带宽承受不住,一上线访问数一多服务器就会奔溃。

4. 打包后样式不一致

这主要是使用了 autoprefixer 自动加浏览器前缀造成。解决方案是使用规范的样式,比如使用 Photoshop 复制的渐变背景 CSS 是自动添加了浏览器前缀,此时解析的时候就会出现异常,需要手动删掉无用的浏览器前缀并只保留规范的写法。