vue实现pc端、移动端、大屏适配

21,847次阅读
没有评论

共计 8688 个字符,预计需要花费 22 分钟才能阅读完成。

目录看这里😊

  • 方法: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

vue 实现 pc 端、移动端、大屏适配

下图可以看到,pc 端调整屏幕大小 resize 时,html 的 font-size 会根据屏幕宽度自动变更,大小始终为屏幕宽度 clientWidth 的 1 /10

vue 实现 pc 端、移动端、大屏适配

amfe-flexiable.js 的源码

(function flexible (window, document) {
  var docEl = document.documentElement
  var dpr = window.devicePixelRatio || 1

  
  function setBodyFontSize () {
    if (document.body) {
      document.body.style.fontSize = (12 * dpr) + 'px'
    }
    else {
      document.addEventListener('DOMContentLoaded', setBodyFontSize)
    }
  }
  setBodyFontSize();

  
  function setRemUnit () {
    var rem = docEl.clientWidth / 10
    docEl.style.fontSize = rem + 'px'
  }

  setRemUnit()

  
  window.addEventListener('resize', setRemUnit)
  window.addEventListener('pageshow', function (e) {
    if (e.persisted) {
      setRemUnit()
    }
  })

  
  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:{}
		
		'postcss-pxtorem': {
			rootVa1ue: 75, 
			propList: ["*"], 
			
		    
		    
		    
		}
    },
  },

注意点

  • 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;
    }

    
    const htmlDom = document.getElementsByTagName('html')[0];

    
    htmlDom.style.fontSize = (htmlWidth / 10) + 'px';
}


setRem();


let resizeTimeout;
window.addEventListener('resize', () => {
    
    if (resizeTimeout) {
        clearTimeout(resizeTimeout);
    }
    resizeTimeout = setTimeout(() => {
        setRem();
    }, 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 所以我们需要缩放的比例是:屏幕宽度除以设计稿宽度 = 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%
vue 实现 pc 端、移动端、大屏适配
接下来利用绝对定位将图表定位到中间位置

position: absolute;
left: 50%;
top: 50%;

偷懒方法 - 插件

v-scale-screen 是使用 css 属性 transform 实现缩放效果的一个大屏自适应组件,通过 scale 进行等比例计算,达到等比例缩放的效果,同时也支持铺满全屏,宽度等比,高度等比,等自适应方案, 具体可查大屏自适应终极解决方案

图表适配

思路

  • 首先容器盒子大小要使用相对值,比如 %、vh、vm
  • 默认情况下,这里以你的设计稿是 1920*1080 为例,即网页宽度是 1920px (做之前一定问清楚 ui 设计稿的尺寸)
  • 把这个函数写在一个单独的工具文件 dataUtil.js 里面,在需要的时候调用
  • 其原理是计算出当前屏幕宽度和默认设计宽度的比值,将原始的尺寸乘以该值
  • 另外,其它 echarts 的配置项,比如间距、定位、边距也可以用该函数
  1. 编写 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));
  1. 将函数挂载到 vue 原型上
import {fitChartSize} from '@src/utils/dataUtil.js'
Vue.prototype.fitChartFont = fitChartSize;
  1. 使用 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} 
{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%"], 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%"], 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:


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]
  }]
};


function applyFitChartSize(option) {
  const defalteWidth = 1920;

  
  if (option.title && option.title.textStyle) {
    option.title.textStyle.fontSize = fitChartSize(option.title.textStyle.fontSize, defalteWidth);
  }

  
  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);
  }

  
  if (option.yAxis && option.yAxis.axisLabel) {
    option.yAxis.axisLabel.fontSize = fitChartSize(option.yAxis.axisLabel.fontSize, defalteWidth);
  }

  
}


applyFitChartSize(option);


myChart.setOption(option);


window.addEventListener('resize', () => {
  applyFitChartSize(option);
  myChart.setOption(option);
  myChart.resize(); 
});

其他方法

原文地址: vue 实现 pc 端、移动端、大屏适配

    正文完
     0
    Yojack
    版权声明:本篇文章由 Yojack 于2024-11-10发表,共计8688字。
    转载说明:
    1 本网站名称:优杰开发笔记
    2 本站永久网址:https://yojack.cn
    3 本网站的文章部分内容可能来源于网络,仅供大家学习与参考,如有侵权,请联系站长进行删除处理。
    4 本站一切资源不代表本站立场,并不代表本站赞同其观点和对其真实性负责。
    5 本站所有内容均可转载及分享, 但请注明出处
    6 我们始终尊重原创作者的版权,所有文章在发布时,均尽可能注明出处与作者。
    7 站长邮箱:laylwenl@gmail.com
    评论(没有评论)