数据大屏最简单适配方案2023-03-21 02:03:39

前言
最近公司有个大屏的项目,之前没咋接触过。
就在掘金上看了许多大佬各种方案,最常见的方案无外乎一下 3 种?,优缺点呢也比较明显

方案实现方式优点缺点vw, vh按照设计稿的尺寸,将px按比例计算转为vw和vh1.可以动态计算图表的宽高,字体等,灵活性较高 2.当屏幕比例跟 ui 稿不一致时,不会出现两边留白情况1.需要编写公共转换函数,为每个图表都单独做字体、间距、位移的适配,比较麻烦scale通过 scale 属性,根据屏幕大小,对图表进行整体的等比缩放1.代码量少,适配简单 2.一次处理后不需要在各个图表中再去单独适配1.因为是根据 ui 稿等比缩放,当大屏跟 ui 稿的比例不一样时,会出现周边留白情况 2.当缩放比例过大时候,字体和图片会有一点点失真.3.当缩放比例过大时候,事件热区会偏移。rem + vw vh1.获得 rem 的基准值2.动态的计算html根元素的font-size 3.图表中通过 vw vh 动态计算字体、间距、位移等1.布局的自适应代码量少,适配简单1.因为是根据 ui 稿等比缩放,当大屏跟 ui 稿的比例不一样时,会出现周边留白情况2.图表需要单个做字体、间距、位移的适配
这 3 种方案中,最简单的也最容易抽离为下次使用的当属 scale 方案了。
它优点是:

代码量少,编写公共组件,套用即可,可以做到一次编写,任何地方可用,无需重复编写。
使用 flex grid 百分比 还有 position 定位或者完全按照设计稿的 px 单位进行布局,都可以,不需要考虑单位使用失误导致适配不完全。实现数据大屏在任何分辨率的电脑上均可安然运作。

至于说缺点:

比例不一样的时候,会存在留白,开发大屏基本上都是为对应分辨率专门开发,我觉得这个缺点可以基本忽略,因为我们可以将背景色设置为大屏的基础色,这样留白部分不是太大基本没影响啦,哈哈

关于失真,失真 是在你设置的 分辨率比例 与 屏幕分辨率比例 不同的情况下,依然采用 铺满全屏 出现 拉伸 的时候,才会出现,正常是不会出现的。

电视看电影比例不对,不也会出现上下黑边吗,你设置拉伸,他也会失真,是一个道理

? 开发
让我们先来看下效果吧!?

既然选择了 scale 方案,那么我们来看看它的原理,以及如何实现吧!
原理
scale 方案是通过 css 的 transform 的 scale 属性来进行一个 等比例缩放 来实现屏幕适配的,既然如此我们要知道一下几个前提:

设设计稿的 宽高比 为 1,则在任意显示屏中,只要展示内容的容器的 宽高比 也是 1,则二者为 1:1 只要 等比缩放/放大 就可以做到完美展示并且没有任何白边。
如果设计稿的 宽高比 为 1, 而展示容器 宽高比 不是 1 的时候,则存在两种情况。

宽高比大于 1,此时宽度过长,计算时基准值采用高度,计算出维持 1 宽高比的宽度。
宽高比小于 1,此时高度过长,计算时基准值采用宽度,计算出维持 1 宽高比的高度。

代码实现
有了以上前提,我们可以得出以下代码
const el = document.querySelector(‘#xxx’)
// * 需保持的比例
const baseProportion = parseFloat((width / height).toFixed(5))
// * 当前屏幕宽高比
const currentRate = parseFloat((window.innerWidth / window.innerHeight).toFixed(5))

const scale = {
widthRatio: 1,
heightRatio: 1,
}

// 宽高比大,宽度过长
if(currentRate > baseProportion) {
// 求出维持比例需要的宽度,进行计算得出宽度对应比例
scale.widthRatio = parseFloat(((window.innerHeight * baseProportion) / baseWidth).toFixed(5))
// 得出高度对应比例
scale.heightRatio = parseFloat((window.innerHeight / baseHeight).toFixed(5))
}
// 宽高比小,高度过长
else {
// 求出维持比例需要的高度,进行计算得出高度对应比例
scale.heightRatio = parseFloat(((window.innerWidth / baseProportion) / baseHeight).toFixed(5))
// 得出宽度比例
scale.widthRatio = parseFloat((window.innerWidth / baseWidth).toFixed(5))
}

// 设置等比缩放或者放大
el.style.transform = scale(${scale.widthRatio}, ${scale.heightRatio})
复制代码
OK,搞定了。
哇!这也太简单了吧。
好,为了下次一次编写到处使用,我们对它进行封装,然后集成到我们常用的框架中,作为通用组件
function useFitScreen(options) {
const {
// * 画布尺寸(px)
width = 1920,
height = 1080,
el
} = options

// * 默认缩放值
let scale = {
widthRatio: 1,
heightRatio: 1,
}

// * 需保持的比例
const baseProportion = parseFloat((width / height).toFixed(5))
const calcRate = () => {
if (el) {
// 当前比例
const currentRate = parseFloat((window.innerWidth / window.innerHeight).toFixed(5))
// 比例越大,则越宽,基准值采用高度,计算出宽度
// 反之,则越高,基准值采用宽度,计算出高度
scale = currentRate > baseProportion
? calcRateByHeight(width, height, baseProportion)
: calcRateByWidth(width, height, baseProportion)
}

el.style.transform = `scale(${scale.widthRatio}, ${scale.heightRatio})`

}

// * 改变窗口大小重新绘制
const resize = () => {
window.addEventListener(‘resize’, calcRate)
}

// * 改变窗口大小重新绘制
const unResize = () => {
window.removeEventListener(‘resize’, calcRate)
}

return {
calcRate,
resize,
unResize,
}
}
复制代码
其实一个基本的共用方法已经写好了,但是我们实际情况中,有可能会出现奇怪比例的大屏。
例如:

超长屏,我们需要 x 轴滚动条。
超高屏,我们需要 y 轴滚动条。
还有一种情况,比如需要占满屏幕,不需要留白,适当拉伸失真也无所谓的情况呢。

所以,我们需要进行扩展这个方法,像 节流 节约性能,对上面是那种情况做适配等,文章篇幅有限,源码已经开源并且工具包已经上传了 npm 需要的可以去看源码或者下载使用

工具包源码:使用文档在这里,希望大佬们给一个小小的 star~
工具包NPM: 你可以通过 npm install @fit-screen/shared 下载使用

集成到 Vue
通过以上的的原理和工具包实现,接下来我们接入 Vue 将会变得非常简单了,只需要我们用 Vue 的 ref 将对应的 dom 元素提供给工具包,就可以实现啦~
不过在这个过程中我遇到的问题是,既然是一次编写,任意使用,我们需要集成 Vue2 和 Vue3,如何做呢?
说道这一点想必各位大佬也知道我要用什么了吧,那就是偶像 Anthony Fu 的 vueuse 中使用的插件 vue-demi。
好的,开发完毕之后,一样将它上传到 npm ,这样以后就可以直接下载使用了

源码地址:点击前往 使用文档在这里,希望大佬们给一个小小的 star~
npm 地址:点击前往
vue2示例:点击前往
vue3示例:点击前往

大家也可以这样使用
npm install @fit-screen/vue @vue/composition-api

or

yarn add @fit-screen/vue @vue/composition-api

or

pnpm install @fit-screen/vue @vue/composition-api
复制代码
当做全局组件使用
// In main.[jt]s
import { createApp } from ‘vue’
import FitScreen from ‘@fit-screen/vue’
import App from ‘./App.vue’

const app = createApp(App)
app.use(FitScreen)
app.mount(‘#app’)
复制代码
Use in any component

复制代码
在 SFC 中单独使用


复制代码
集成到 React
集成到 React 也是完全没毛病,而且好像更简单,不存在 vue2 和 vue3 这样版本兼容问题

源码地址:点击前往 使用文档在这里,希望大佬们给一个小小的 star~
npm 地址:点击前往
react示例:点击前往

大佬们可以这样使用:
npm install @fit-screen/react

or

yarn add @fit-screen/react

or

pnpm install @fit-screen/react
复制代码
import { useState } from ‘react’
import FitScreen from ‘@fit-screen/react’

function App() {
const [count, setCount] = useState(0)

return (

React logo

Vite + React

setCount(count => count + 1)}> count is {count}

Edit src/App.tsx and save to test HMR

Click on the Vite and React logos to learn more
)
}

export default App
复制代码
结尾

通过工具包可以在无框架和任意前端框架中开发自己的组件,比如说 Svelte,我也做了一个 Svelte 的版本示例,可以去 示例仓库 中查看。
目前就开发了 Vue 和 React 版本的自适应方案,大家可以根据需要进行使用。

感谢大家的阅读,希望大家能用得上,并且给上 star~

« »