😮‍💨大屏适配搞砸了 3 个项目,最后居然被 5 行代码救回来

0 阅读5分钟

先说去年底闹的一个事。

给某政务项目做数据大屏。稿子定好了 1920×1080,蓝黑配色,几个地区指标加一张中国地图,看着还行。

公司机器上跑了两天,没啥 bug。打包上线,去现场搭环境。

大会议室那块屏一开——我操。

标题飞了。右下角那个实时告警面板直接折到屏幕外面去了。中间的地图还好端端在正中间,但是小了,周围一坨留白,看着像贴了个贴纸。

客户没吭声。她看了大概十秒,说了句"这个页面需要再调一下对吧"。

声音很平静。但是我知道完了。

回公司我就开始啃适配这事。讲真,前后试过不下五种方案。

rem 那套。手写媒体查询。一个页面三四百行样式,切一个分辨率加一个断点,妈的搞到后面断点比自己写的业务逻辑都多。

vw/vh。间距的问题,控不住。30px 换算成 1.5625vw,设计稿改了数字就得全盘重算。眼要瞎。

手写 transform:scale()。更惨。组件少还行,一上十几个模块,每个 offset 要自己推,改一处全局都得重调。熬到凌晨两三次,同事以为我在加班改 BUG,其实我是在算 56 除以 1080 等于多少。

年底的时候在 GitHub 逛,首页推荐了个库 vfit.js。扫了眼 README,感觉它把我想干但是懒得干的活全干了。

装上试了下。那天晚上八点开始写 demo,十点就把之前的适配代码全删了换它的组件。同事过来看愣了一下,说"你这两天产出有点快"。

我跟他说不是我快,是这个东西让我不用写那些傻逼 offset 了。

配置。

就一个文件,main.ts 里插几行:

import { createFitScale } from 'vfit'

app.use(createFitScale({
  target: '#app',
  designWidth: 1920,
  designHeight: 1080,
  scaleMode: 'auto'
}))

它做的事情简单到说出来有点不值钱——拿 ResizeObserver 盯着你的 #app,宽高变了就去算 min(容器宽/1920, 容器高/1080),出来的 scale 塞进 provide/inject。

没了,就这。

但是好用。是真特么好用。

因为它把 scale 全程静默地注入到全局,你页面里所有用它那套组件的地方自动生效,不用传不用算不用 watch,忘了还有这事都行。

好,配置聊完了。重点是怎么用它摆东西。

大屏布局其实非常套路。我做了四五个项目,没有一次逃出这几个位置:左上 Logo,右上时间,左下放几张辅助图表,右下塞点监控数据,正中央永远是一张大地图或者主可视化。

这个库把每个位置做成了独立的 Vue 组件。就这么几个:vfit-lt(左上),vfit-rt(右上),vfit-lb(左下),vfit-rb(右下),vfit-center(居中)。

名字一眼就知道干啥。

放个 Logo:

<vfit-lt :top="80" :left="40">
  <LogoWidget />
</vfit-lt>

放个时钟:

<vfit-rt :top="20" :right="30">
  <ClockWidget />
</vfit-rt>

地图居中:

<vfit-center>
  <MainMap />
</vfit-center>

这段代码我从旧项目复制来的。一个字没改,换了三个屏跑:笔记本 14 寸、27 寸 2K、然后那个 4K 大屏,全部对齐。

原理说穿了就一句话——topleftrightbottom,这四个值它自动乘全局 scale。你传 80,屏缩一半自动变 40。放大到 1.3 倍就变 104。

我特意测过 rightbottom 会不会偷懒不乘——因为很多搞适配的库确实只乘 top/left。它没有,四个边全乘。右下角那种本来最容易歪的地方,反而是最准的。这点我挺服。

然后路上还遇到一些用得着的小功能,碎着列一下。

百分比。默认是 px,你想钉死在相对位置就别让值乘 scale,写 unit="%" 就完事:

<vfit-lt :top="10" :left="10" unit="%">
  <Widget />
</vfit-lt>

自定义缩放。全局 scale 不是所有模块都适用。有时候一个角落里的迷你面板你就想它别那么大,:scale 盖掉全局值就行:

<vfit-lt :top="50" :left="50" :scale="0.7">
  <MiniWidget />
</vfit-lt>

不传或者传 0,走全局。传了,就按你写的走。

层级。面板偶尔会叠起来,z 大在上,z 小在下。默认 300:

<vfit-lt :top="10" :left="10" :z="999">
  <TopPanel />
</vfit-lt>

然后还有个 FitContainer。适合你需要四个边一块使的情况。比如说一个面板要贴着容器四个边各空 20px:

<FitContainer :top="20" :right="20" :bottom="20" :left="20" unit="px">
  <FullPanel />
</FitContainer>

这个我一般当后备方案,常规场景还是用 vfit-*。命名太直白了,下回打开项目不至于忘了哪个是哪个。

踩过的坑也不多,三个。

第一回我外层容器忘了 position: relativevfit-* 全是 absolute,它往上找参照物,没找到就奔 body 去了,然后所有东西摞在左上角。那种感觉怎么形容,就像你明明把餐具摆好了,回头一看全堆厨房门口。

补上就正常了:

.view {
  position: relative;
  width: 100%;
  height: 100vh;
}

第二回是 ECharts。你们应该也一样,大屏里少不了几个图表。scale 变了图表没反应,因为它不知道要 resize。用 useFitScale() 捞出来 watch 一下,自己调 resize

import { useFitScale } from 'vfit'
const scale = useFitScale()
watch(scale, () => chart?.resize())

第三回比较弱智。老文档有个 import 'vfit/style.css',我照抄了,报错。翻 issue 发现早就不用手动引了,样式走内部注入。白折腾半小时。

好,收一下。

vfit 这个东西不是啥革命性发明。说穿了就是 transform + absolute 的组件化封装。

但是有人帮你把算 origin、乘 scale、区分 px 和 percent 这些烂事处理好以后,你写大屏页面忽然就变得像拼乐高。

我现在开新项目基本就是 npm i vfit 然后页面里 <vfit-lt> 起手。已经成肌肉记忆了。


npm:npmjs.com/package/vfi…

GitHub:github.com/v-plugin/vf…

公众号:土豆的孪生可视化(已认证自媒体)