一、大屏适配方案对比
常见的大屏适配方案有3种,对比如下:
方案 | 实现原理 | 优点 | 缺点 |
---|---|---|---|
scale | 通过 scale 属性,根据屏幕大小,对图表进行整体的等比缩放 | 1.代码量少,适配简单;;2.一次处理后不需要在各个图表中再去单独适配 | 1.当大屏跟 ui 稿的比例不一样时,会出现周边留白情况2.当缩放比例过大时候,字体和图片会有一点点失真.;3.当缩放比例过大时候,事件热区会偏移。(如地图上的点击事件) |
vw,vh | 按照设计稿的尺寸,将px按比例计算转为vw和vh | 1.可以动态计算图表的宽高,字体等,灵活性较高; 2.当屏幕比例跟 ui 稿不一致时,不会出现两边留白情况 | 1.需要编写公共转换函数,为每个图表都单独做字体、间距、位移的适配,比较麻烦 |
rem + vw vh | 1.获得 rem 的基准值2.动态的计算html根元素的font-size3.图表中通过 vw vh 动态计算字体、间距、位移等 | 1.灵活性高、兼容性好、适应性强 | 1.需要进行许多计算,可能存在误差问题,且代码复杂度较高 |
本篇分享的是 scale 的方法,适用场景:设备比例固定;无地图点击事件
没有哪种方案是最好或者哪种方案不好,方案选择,需要根据实际开发需求及场景来确定。
二、效果
http://192.168.2.46:3006/#/screen (未部署,本地服务地址)
三、原理思路
1.如何缩放:
通过css函数 :scale(缩放倍数)
https://codepen.io/csscodelct/pen/rNRzRov
通过以上demo我们了解到,实现缩放,我们只需要获取 缩放比例 即可。
2.获取缩放比例
- 确定设计稿尺寸,默认 1920 x 1080
- 分别计算浏览器和设计图宽高比
- 如果浏览器的宽高比大于设计稿的宽高比,就取浏览器高度:设计稿高度,否则取浏览器宽度:设计稿宽度
浏览器的宽高比大于设计稿的宽高比
浏览器的宽高比小于设计稿的宽高比
根据以上图片可知,我们无论怎么缩放,都不能超出可视范围(即浏览器区域)
3.使用防抖优化性能
防抖使用场景: 高频率触发的事件,在指定的单位时间内,只响应最后一次,如果在指定的时间内再次触发,则重新计算时间。如:按钮点击、输入框监听
function debounce(callback, delay) {
let timerId
return function (event) {
// 如果上次事件还没有真正处理, 清除
if (timerId) {
clearTimeout(timerId)
}
// 发事件发生指定事件后才调用处理事件的回调函数
// 启动定时器, 只是准备真正处理
timerId = setTimeout(() => {
// 正在处理事件
callback.call(null, event)
// 删除准备处理的标记
timerId = null
}, delay)
}
}
四、代码实现
封装一个公共方法 src/utils/useResize.ts
import { ref, onMounted, onBeforeUnmount } from "vue";
// 默认适配宽高
export const width = 1920;
export const height = 1080;
type ResizeType = {
w?: number;
h?: number;
delay?: number;
};
export const useResize = (options: ResizeType = {}) => {
const { w = width, h = height, delay = 100 } = options;
// 缩放元素
const screenRef = ref();
const scale = ref(1);
function resize() {
// 浏览器宽高
const clientWidth = document.body.clientWidth;
const clientHeight = document.body.clientHeight;
// 计算宽高缩放比例
const scaleW = clientWidth / w;
const scaleH = clientHeight / h;
if (clientWidth / clientHeight > w / h) {
// 如果浏览器的宽高比大于设计稿的宽高比,就取浏览器高度和设计稿高度之比
scale.value = scaleH;
} else {
// 如果浏览器的宽高比小于设计稿的宽高比,就取浏览器宽度和设计稿宽度之比
scale.value = scaleW;
}
screenRef.value.style.transform = "scale(" + scale.value + ")";
}
const resizeDelay = debounce(resize, delay);
onMounted(() => {
if (screenRef.value) {
resize();
window.addEventListener("resize", resizeDelay);
}
});
onBeforeUnmount(() => {
window.removeEventListener("resize", resizeDelay);
});
return {
scale,
screenRef,
};
};
/*
用来返回防抖函数的工具函数
*/
function debounce(callback, delay) {
let timerId;
return function (event) {
// 如果上次事件还没有真正处理, 清除
if (timerId) {
clearTimeout(timerId);
}
// 发事件发生指定事件后才调用处理事件的回调函数
// 启动定时器, 只是准备真正处理
timerId = setTimeout(() => {
// 正在处理事件
callback.call(null, event);
// 删除准备处理的标记
timerId = null;
}, delay);
};
}
页面中使用
<template>
<div ref="screenRef"></div>
</template>
<script setup lang='ts'>
import { useResize } from '@/utils/useResize'
const { screenRef } = useResize()
</script>
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。