概述
最近接到要做大屏首页的需求,要适配不同屏幕缩放比例合适,目前的大屏适配方案很多,如下是实际项目采用的方案vm+vh
实现思路
按照设计稿的尺寸,将px
按比例计算转为vw
和vh
,转换公式如下
scss
假设设计稿尺寸为 1920*1080(做之前一定问清楚 ui 设计稿的尺寸)
即:
网页宽度=1920px
网页高度=1080px
我们都知道
网页宽度=100vw
网页宽度=100vh
所以,在 1920px*1080px 的屏幕分辨率下
1920px = 100vw
1080px = 100vh
这样一来,以一个宽 300px 和 200px 的 div 来说,其所占的宽高,以 vw 和 vh 为单位,计算方式如下:
vwDiv = (300px / 1920px ) * 100vw
vhDiv = (200px / 1080px ) * 100vh
所以,就在 1920*1080 的屏幕分辨率下,计算出了单个 div 的宽高
当屏幕放大或者缩小时,div 还是以 vw 和 vh 作为宽高的,就会自动适应不同分辨率的屏幕
复制代码
新建util.scss
scss
@use "sass:math";
// 默认设计稿的宽度
$designWidth: 1920;
// 默认设计稿的高度
$designHeight: 1080;
// px 转为 vw 的函数
@function vw($px) {
@return math.div($px, $designWidth) * 100vw;
}
// px 转为 vh 的函数
@function vh($px) {
@return math.div($px, $designHeight) * 100vh;
}
vite配置
js
//vite.config.js
import { defineConfig,
type AliasOptions
} from 'vite'
import { fileURLToPath, URL } from 'node:url'
import UnoCSS from 'unocss/vite'
import vue from '@vitejs/plugin-vue'
const alias: AliasOptions = {
'@/my-vue-app': fileURLToPath(new URL('../../my-vue-app/src/main.js', import.meta.url)),
"@": fileURLToPath(new URL('./src', import.meta.url)),
}
// https://vite.dev/config/
export default defineConfig({
plugins: [vue(), UnoCSS()],
resolve: {
alias: {
...alias,
},
},
css: {
preprocessorOptions:{
scss:{
additionalData: `@use "@/style/util.scss" as *; @use "@/style/element-variables.scss" as *; `, // 替换为你的实际文件路径
}
}
},
})
使用
上面vite配置完成后即可项目全局使用计算样式
scss
<style lang="scss">
.box{
width: vw(800);
height: vh(400);
font-size: vh(16);
background-color: pink;
margin-left: vw(10);
margin-top: vh(10);
border: vh(2) solid red;
font-size: 20px;
border: 20px solid red;
}
</style>
存在的问题
- 上面的能处理我们项目自行写的样式,但是组件库内部的尺寸都是使用的scss变量,因此无法转化组件库内部的样式,解决办法就是将对应组件库的尺寸样式变量重写
- echarts相关图标通过配置式传入的尺寸无法变动
- 其他库里面写死的样式,没法改
解决组件库的问题
新建element-variables.scss,我以elementplus为例
scss
注意:这里不能像外面项目那样使用vm()和vh()函数,编译会报错,这里自动根据尺寸高计算好变量覆盖element样式即可
// 覆盖 Element Plus 的默认变量
@forward "element-plus/theme-chalk/src/common/var.scss" with (
// 修改默认尺寸变量(原本是 px,改成 vw/vh)
$button-padding-vertical: 0.2vw,
$button-padding-horizontal:0.4vw,
$input-height: 0.3vw,
// 其他需要修改的变量...
);
vite.config.js配置
js
// https://vite.dev/config/
export default defineConfig({
plugins: [vue(), UnoCSS()],
resolve: {
alias: {
...alias,
},
},
css: {
preprocessorOptions:{
scss:{
additionalData: `@use "@/style/util.scss" as *; @use "@/style/element-variables.scss" as *; `, // 替换为你的实际文件路径
}
}
},
})
问题2解决方案
2的问题其实也很简单,提取成函数,配置echarts相关属性的时候,将尺寸通过函数计算后传入即可,然后页面尺寸变化,重新调整echarts的尺寸即可 3的问题,我们借助postcss即可强制转化页面所有单位
问题3解决方案
对应非本项目其他库的组件的写死的样式,我们可以直接通过postscss在打包编译的时候,强制替换计算即可,下载postcss-px-to-viewport,然后新增postcss.config.js
js
module.exports = {
plugins: {
"postcss-px-to-viewport": {
unitToConvert: "px",
viewportWidth: 1920, // 设计稿宽度
viewportHeight: 1080, // 设计稿高度
unitPrecision: 5,
propList: ["*"], // 所有属性都转换
viewportUnit: "vw",
fontViewportUnit: "vw",
selectorBlackList: [], // 不转换的选择器
minPixelValue: 1,
mediaQuery: false,
replace: true,
exclude: [/node_modules/], // 不转换 node_modules(避免影响 Element Plus)
},
},
};
总结
上面的大屏方案不一定完全覆盖全部场景,可以根据自己项目需要,在做优化细节处理