目录看这里😊
- 方法:postcss-pxtorem结合amfe-flexible
- 介绍
- amfe-flexible
- amfe-flexiable.js的源码
- postcss-pxtorem
- 注意事项
- 2. 使用
- 2.1 在main.js入口文件引入
- 2.2 创建postcss.config.js配置文件
- 大屏改进方案
- scale
- 1. 如何缩放
- 2. 如何居中
- 偷懒方法-插件
- 图表适配
- 思路
- 其他方法
方法:postcss-pxtorem结合amfe-flexible
介绍
amfe-flexible
amfe-flexible 是一个由阿里巴巴前端团队开发的 JavaScript 库,用于实现移动端页面的自适应布局。
它通过动态设置 HTML 根元素的 font-size 来根据屏幕宽度进行适配。这个库是 lib-flexible 的升级版本。
简言之:
- amfe-flexible会自动将html的font-size设置为屏幕宽度clientWidth的1/10,将body的font-size设置为12 * dpr 像素(一般为24px),单位为px。
- 动态监听resize事件,调整html/body的fontsize
下图可以看到,在main.js中引入amfe-flexible,为自动在html和body上设置行内样式 font-size
下图可以看到,pc端调整屏幕大小resize时,html的font-size会根据屏幕宽度自动变更,大小始终为屏幕宽度clientWidth的1/10
amfe-flexiable.js的源码
// 以2.2.1版本为例 (function flexible (window, document) { var docEl = document.documentElement var dpr = window.devicePixelRatio || 1 // adjust body font size function setBodyFontSize () { if (document.body) { document.body.style.fontSize = (12 * dpr) + 'px' } else { document.addEventListener('DOMContentLoaded', setBodyFontSize) } } setBodyFontSize(); // set 1rem = viewWidth / 10 function setRemUnit () { var rem = docEl.clientWidth / 10 docEl.style.fontSize = rem + 'px' } setRemUnit() // reset rem unit on page resize window.addEventListener('resize', setRemUnit) window.addEventListener('pageshow', function (e) { if (e.persisted) { setRemUnit() } }) // detect 0.5px supports if (dpr >= 2) { var fakeBody = document.createElement('body') var testElement = document.createElement('div') testElement.style.border = '.5px solid transparent' fakeBody.appendChild(testElement) docEl.appendChild(fakeBody) if (testElement.offsetHeight === 1) { docEl.classList.add('hairlines') } docEl.removeChild(fakeBody) } }(window, document))
复制
postcss-pxtorem
ostCSS 插件,它用于将 CSS 中的像素单位(px)转换为 rem 单位。这个插件对于创建响应式设计特别有用,因为它允许开发者使用 px 单位编写样式,然后在构建过程中自动转换成相对单位 rem,这样可以更方便地通过改变根元素(html)的字体大小来调整整个页面的布局尺寸(使得再写css时,可以依据设计图直接使用px作为单位,编译时插件自动将单位由px转为rem)
注意事项
- 不能使用行内样式
对于行内样式,阿里手淘并不能将px转rem,所以对于需要自适应的样式,如font-size、width、height等请不要写在行内。同理,对于不需要转化的样式可以写在行内,或者使用PX(大写)作为单位。 - 字号不使用rem
我们都知道chrome的最小显示的字体是12px,如果字体用rem,计算出来小于12px,那么就也会以12px显示,而且我们不希望出现13px或者15px这样的奇葩尺寸,所以字体最好是用PX(大写)来表示,至于适应,我们可以写媒体查询。
.item { border-bottom: 1PX #8d8d8d dashed; font-size: 12PX; line-height: 16PX; @media screen and (min-width: 576PX) { font-size: 14PX; line-height: 18PX; } @media screen and (min-width: 768PX) { font-size: 16PX; line-height: 28PX; } @media screen and (min-width: 992PX) { font-size: 16PX; line-height: 32PX; } @media screen and (min-width: 1200PX) { font-size: 18PX; line-height: 64PX; } } // PC端响应式媒体断点: ```css @media (min-width: 1024px){ body{font-size: 18px} } @media (min-width: 1100px) { body{font-size: 20px} } @media (min-width: 1280px) { body{font-size: 22px;} } @media (min-width: 1366px) { body{font-size: 24px;} } @media (min-width: 1440px) { body{font-size: 25px !important;} } @media (min-width: 1680px) { body{font-size: 28px;} } @media (min-width: 1920px) { body{font-size: 33px;} } ### amfe-flexible不是已经给html自动设置了font-size,为什么还需要它通过pxtorem设置rootValue + pxtorem是将代码中的px转为rem,转换比例就是根据rootValue来计算的(1rem = rootValue的值+‘px’) 这样可以根据设计图量的的尺寸px,直接写到代码中,而不需要计算并手动折算成rem。比如设计图宽度是750px,那么rootValue=75,即按照75px=1rem,在编译的时候,将px转为rem单位,保证尺寸大小是个相对值 + 渲染到页面上时,需要再将编译后的rem值转为px,这时候的转换比例就是1rem = 实际展示容器html的font-size值。amfe-flexible就是用来动态设置这个基准值的( 如果屏幕大小固定,其实就不需要amfe-flexible,手动设置html的font-size值就行了。但前端渲染的屏幕尺寸不同,因此需要根据屏幕尺寸大小动态的调整基准值。) + 简言之:pxtorem是方便我们"按照相对值复刻"设计图上的尺寸,即把px绝对值转为相对值rem(转换比例就是rootValue),保证比例不失真,渲染时需要再将相对值rem转为绝对值px(转换比例就是amfe-flexible自动设置的html的font-size) ## 安装和使用 ### 1. 安装 ```js npm install amfe-flexible --save npm install postcss-pxtorem --save-dev
复制
2. 使用
2.1 在main.js入口文件引入
import 'amfe-flexible'
复制
2.2 创建postcss.config.js配置文件
可在
vue.config.js、.postcssrc.js、postcss.config.js
其中之一配置,权重从左到右降低,没有则新建文件,只需要设置其中一个即可。
module.exports = { plugins:{ autoprefixer:{} //f1exible配置 'postcss-pxtorem': { rootVa1ue: 75, //设计稿宽度的1/10 propList: ["*"], //需要做转化处理的属性,如`hight`、`width`、`margin`等,`*`表示全部 //selectorBlackList: ['van-'], // 忽略的选择器 //replace: true, // 直接替换原来的单位,不添加备选单位 //mediaQuery: false, // 是否在媒体查询中转换 px //minPixelValue: 2, // 最小的转换数值 } }, },
复制
注意点:
- rootValue根据设计稿宽度除以10进行设置,这边假设设计稿为375,即rootValuei设为37.5:
- propList是设置需要转换的属性,这边*为所有都进行转换。
补充报错:
如果出现报错,请降低版本后重装依赖 ( 在package.json文件中将版本修改为如下,然后终端运行命令npm install即可 )
"dependencies":{ "amfe-flexible":"^2.2.1", "postcss-pxtorem":"^5.1.1", },
复制
function setRem() { // 获取视口宽度 const htmlWidth = document.documentElement.clientWidth || document.body.clientWidth; // 设置最小宽度,防止字体大小过小 const minWidth = 320; if (htmlWidth < minWidth) { htmlWidth = minWidth; } // 获取 html 元素 const htmlDom = document.getElementsByTagName('html')[0]; // 设置 html 元素的 font-size htmlDom.style.fontSize = (htmlWidth / 10) + 'px'; } // 初始化时调用 setRem 函数 setRem(); // 监听窗口大小变化 let resizeTimeout; window.addEventListener('resize', () => { // 使用 requestAnimationFrame 来减少频繁的计算 if (resizeTimeout) { clearTimeout(resizeTimeout); } resizeTimeout = setTimeout(() => { setRem(); }, 100); // 延迟 100 毫秒执行,避免频繁触发 });
复制
大屏改进方案
- 限制rem的最大值
- 通过媒体查询,限制内容最大宽度
- 图片使用SVG 和 Icon Font:使用 SVG 和 Icon Font 可以保证图标和图形在不同分辨率下的清晰度,避免位图在大屏上的失真问题。
scale
通过 css 的 scale 属性,根据屏幕大小,对图表进行整体的等比缩放,从而达到自适应效果
- 缺点: 在任意屏幕下保持固定比例,上下/左右会留白
- 优化办法:对内容剧中,保证左右留白大小一致,在父容器中,设置背景颜色,从而"实现"全屏展示
1. 如何缩放
当屏幕宽高比 < 设计稿宽高比,我们需要缩放的比例是屏幕宽度 / 设计稿宽度当屏幕宽高比 > 设计稿宽高比,我们需要缩放的比例是屏幕高度 / 设计稿高度
const scale = document.documentElement.clientWidth / document.documentElement.clientHeight < designDraftWidth / designDraftHeight ? (document.documentElement.clientWidth / designDraftWidth) : (document.documentElement.clientHeight / designDraftHeight);
复制
如果我们拿到的设计稿宽高为: 1920 * 960 px ,而我们的屏幕大小是 1440 * 900 px,那么 1440/900 = 1.6,920/960 = 2
因为 1.6 < 2 (当前屏幕宽高比小于设计稿宽高比)
所以我们需要缩放的比例是:屏幕宽度除以设计稿宽度 = 1440/1920 = 0.75
2. 如何居中
首先我们利用 transform:translate(-50%,-50%) ,将动画的基点设为左上角
transform-origin:设置动画的基点(中心点),默认点是元素的中心点 //语法 transform-origin: x-axis y-axis z-axis;
复制
然后利用transform:translate(-50%,-50%),将图表沿 x,y 轴移动 50%
接下来利用绝对定位将图表定位到中间位置
position: absolute; left: 50%; top: 50%;
复制
偷懒方法-插件
v-scale-screen是使用 css 属性 transform 实现缩放效果的一个大屏自适应组件,通过 scale 进行等比例计算,达到等比例缩放的效果,同时也支持铺满全屏,宽度等比,高度等比,等自适应方案,具体可查大屏自适应终极解决方案
图表适配
思路
- 首先容器盒子大小要使用相对值,比如%、vh、vm
- 默认情况下,这里以你的设计稿是 1920*1080 为例,即网页宽度是 1920px (做之前一定问清楚 ui 设计稿的尺寸)
- 把这个函数写在一个单独的工具文件dataUtil.js里面,在需要的时候调用
- 其原理是计算出当前屏幕宽度和默认设计宽度的比值,将原始的尺寸乘以该值
- 另外,其它 echarts 的配置项,比如间距、定位、边距也可以用该函数
- 编写 dataUtil.js 工具函数
export const fitChartSize = (size,defalteWidth = 1920) => { let clientWidth = window.innerWidth||document.documentElement.clientWidth||document.body.clientWidth; if (!clientWidth) return size; let scale = (clientWidth / defalteWidth); return Number((size*scale).toFixed(3));
复制
- 将函数挂载到vue原型上
import {fitChartSize} from '@src/utils/dataUtil.js' Vue.prototype.fitChartFont = fitChartSize;
复制
- 使用fitChartFont调整echar中的尺寸大小
有两种方法:
1. echart的option中涉及到尺寸大小的,均调用fitChartFont方法,转换一下尺寸
2. option中还是使用绝对数值px,另外封装一个处理option的方法(绝对值转为相对值),好处是可以批量处理,坏处是每次监听resize时,都需要先调用该方法,再执行echart.resize()
方法1:
<template> <div class="chartsdom" ref="chart" v-chart-resize></div> </template> <script> export default { name: "dashboardChart", data() { return { option: null, }; }, mounted() { this.getEchart(); }, methods: { getEchart() { let myChart = this.$echarts.init(this.$refs.chart); const option = { backgroundColor: "transparent", tooltip: { trigger: "item", formatter: "{a} <br/>{b} : {c}%", }, grid: { left: this.fitChartSize(10), right: this.fitChartSize(20), top: this.fitChartSize(20), bottom: this.fitChartSize(10), containLabel: true, }, calculable: true, series: [ { color: ["#0db1cdcc"], name: "计划投入", type: "funnel", width: "45%", height: "70%", x: "5%", minSize: "10%", funnelAlign: "right", center: ["50%", "50%"], // for pie data: [ { value: 30, name: "下单30%", }, { value: 55, name: "咨询55%", }, { value: 65, name: "点击65%", }, { value: 60, name: "访问62%", }, { value: 80, name: "展现80%", }, ].sort(function (a, b) { return a.value - b.value; }), roseType: true, label: { normal: { formatter: function () {}, position: "inside", }, }, itemStyle: { normal: { borderWidth: 0, shadowBlur: this.fitChartSize(20), shadowOffsetX: 0, shadowOffsetY: this.fitChartSize(5), shadowColor: "rgba(0, 0, 0, 0.3)", }, }, }, { color: ["#0C66FF"], name: "实际投入", type: "funnel", width: "45%", height: "70%", x: "50%", minSize: "10%", funnelAlign: "left", center: ["50%", "50%"], // for pie data: [ { value: 35, name: "下单35%", }, { value: 40, name: "咨询40%", }, { value: 70, name: "访问70%", }, { value: 90, name: "点击90%", }, { value: 95, name: "展现95%", }, ].sort(function (a, b) { return a.value - b.value; }), roseType: true, label: { normal: { position: "inside", }, }, itemStyle: { normal: { borderWidth: 0, shadowBlur: this.fitChartSize(20), shadowOffsetX: 0, shadowOffsetY: this.fitChartSize(5), shadowColor: "rgba(0, 0, 0, 0.3)", }, }, }, ], }; myChart.setOption(option, true); // 监听窗口大小变化,重新应用适配 window.addEventListener('resize', () => { myChart.setOption(option); myChart.resize(); // 重新布局图表 }); }, beforeDestroy() {}, }; </script> <style lang="scss" scoped> .chartsdom { width: 100%; height: 100%; } </style>
复制
方法2:
// 假设你已经初始化了一个 ECharts 实例 const myChart = echarts.init(document.getElementById('main')); // 定义默认的配置项 const option = { title: { text: '示例图表', left: 'center', top: 20, textStyle: { fontSize: 18, // 默认字体大小 } }, tooltip: { trigger: 'axis' }, xAxis: { type: 'category', data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'], axisLabel: { interval: 0, rotate: 30, margin: 15, // 默认间距 fontSize: 12, // 默认字体大小 } }, yAxis: { type: 'value', axisLabel: { fontSize: 12, // 默认字体大小 } }, series: [{ name: '销量', type: 'line', data: [820, 932, 901, 934, 1290, 1330, 1320] }] }; // 应用 fitChartSize 函数调整字体大小和间距 function applyFitChartSize(option) { const defalteWidth = 1920; // 调整标题字体大小 if (option.title && option.title.textStyle) { option.title.textStyle.fontSize = fitChartSize(option.title.textStyle.fontSize, defalteWidth); } // 调整 x 轴标签字体大小和间距 if (option.xAxis && option.xAxis.axisLabel) { option.xAxis.axisLabel.fontSize = fitChartSize(option.xAxis.axisLabel.fontSize, defalteWidth); option.xAxis.axisLabel.margin = fitChartSize(option.xAxis.axisLabel.margin, defalteWidth); } // 调整 y 轴标签字体大小 if (option.yAxis && option.yAxis.axisLabel) { option.yAxis.axisLabel.fontSize = fitChartSize(option.yAxis.axisLabel.fontSize, defalteWidth); } // 其他需要调整的部分... } // 在设置选项之前应用适配 applyFitChartSize(option); // 设置 ECharts 选项 myChart.setOption(option); // 监听窗口大小变化,重新应用适配 window.addEventListener('resize', () => { applyFitChartSize(option); myChart.setOption(option); myChart.resize(); // 重新布局图表 });
复制