注册
web

数据大屏最简单适配方案


根据本文内容,开发了以下三个 npm 包,希望大家能用得到



  1. @fit-screen/shared: 提供计算自适应比例相关内容的工具包
  2. @fit-screen/vue:Vue 自适应组件
  3. @fit-screen/react:React 自适应组件

如果本文对你有帮助,希望大佬能给个 star~



前言


最近公司有个大屏的项目,之前没咋接触过。


就在掘金上看了许多大佬各种方案,最常见的方案无外乎一下 3 种👇,优缺点呢也比较明显


方案实现方式优点缺点
vw, vh按照设计稿的尺寸,将px按比例计算转为vwvh1.可以动态计算图表的宽高,字体等,灵活性较高
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 方案了。


它优点是:



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

至于说缺点:




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




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



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





🚀 开发


让我们先来看下效果吧!👇


5f0358f4aaf94947ad173630addb0b6f~tplv-k3u1fbpfcp-zoom-in-crop-mark:3024:0:0:0.image?

既然选择了 scale 方案,那么我们来看看它的原理,以及如何实现吧!


原理


scale 方案是通过 css 的 transform 的 scale 属性来进行一个 等比例缩放 来实现屏幕适配的,既然如此我们要知道一下几个前提:



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

    1. 宽高比大于 1,此时宽度过长,计算时基准值采用高度,计算出维持 1 宽高比的宽度。
    2. 宽高比小于 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,
}
}

其实一个基本的共用方法已经写好了,但是我们实际情况中,有可能会出现奇怪比例的大屏。


例如:



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

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



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

Vue logo 集成到 Vue


通过以上的的原理和工具包实现,接下来我们接入 Vue 将会变得非常简单了,只需要我们用 Vue 的 ref 将对应的 dom 元素提供给工具包,就可以实现啦~


不过在这个过程中我遇到的问题是,既然是一次编写,任意使用,我们需要集成 Vue2 和 Vue3,如何做呢?


说道这一点想必各位大佬也知道我要用什么了吧,那就是偶像 Anthony Fuvueuse 中使用的插件 vue-demi


好的,开发完毕之后,一样将它上传到 npm ,这样以后就可以直接下载使用了



大家也可以这样使用


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


<template>
<FitScreen :width="1920" :height="1080" mode="fit">
<div>
<a href="https://vitejs.dev" target="_blank">
<img src="/vite.svg" class="logo" alt="Vite logo">
</a>
<a href="https://vuejs.org/" target="_blank">
<img src="./assets/vue.svg" class="logo vue" alt="Vue logo">
</a>
</div>
<HelloWorld msg="Vite + Vue" />
</FitScreen>
</template>

在 SFC 中单独使用


<script setup>
import FitScreen from '@fit-screen/vue'
</script>

<template>
<FitScreen :width="1920" :height="1080" mode="fit">
<div>
<a href="https://vitejs.dev" target="_blank">
<img src="/vite.svg" class="logo" alt="Vite logo">
</a>
<a href="https://vuejs.org/" target="_blank">
<img src="./assets/vue.svg" class="logo vue" alt="Vue logo">
</a>
</div>
<HelloWorld msg="Vite + Vue" />
</FitScreen>
</template>

react logo 集成到 React


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



大佬们可以这样使用:


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 (
<FitScreen width={1920} height={1080} mode="fit">
<div className="App">
<div>
<a href="https://vitejs.dev" target="_blank" rel="noreferrer">
<img src="/vite.svg" className="logo" alt="Vite logo" />
</a>
<a href="https://reactjs.org" target="_blank" rel="noreferrer">
React logo
</a>
</div>
<h1>Vite + React</h1>
<div className="card">
<button onClick={() => setCount(count => count + 1)}>
count is {count}
</button>
<p>
Edit <code>src/App.tsx</code> and save to test HMR
</p>
</div>
<p className="read-the-docs">
Click on the Vite and React logos to learn more
</p>
</div>
</FitScreen>

)
}

export default App

结尾



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

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


作者:jpliu
来源:juejin.cn/post/7202598910337138748

0 个评论

要回复文章请先登录注册