Large screen adaptation solution - vw and vh adaptation solution

the whole idea

  • The overall width and height layout is 100vw, 100vh. The width and height of each module: use vw, vh
  • Font size adaptation: px converted to vw, vh
  • Process public styles: Create a new rem.scss file
  • Charts automatically resize() according to screen size changes: custom instructions
  • Text in the chart, such as legend, abscissa, etc. font size adaptation: public method
  • Subcomponents monitor data changes and refresh charts in real time
  • websocket: increasing interval reconnection
  • Order statistics list data carousel switching

1. According to the size of the design draft, convert px to vw and vh in proportion.

util.scss(Just modify the default width and height of the design draft

//假设设计稿尺寸为1920x*1080px的屏幕分辨率
//1920px = 100vw
//1080px = 100vh

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

view.config.js

// 配置一下utils.scss的路径,就可以全局使用了
module.exports={
    
    
	publicPath: '', 
	configureWebpack: {
    
    
	  name: "app name",
	  resolve: {
    
    
	    alias: {
    
    
	      '@': resolve('src')
	    }
	  }
	},
	css:{
    
     //全局配置utils.scss
         loaderOptions:{
    
     
            sass:{
    
    
                     prependData:`@import "@/styles/utils.scss";`
                }
          }
	}
}

Used in .vue files

<style lang="scss" scoped="scoped">
    /* 
     直接使用vw和vh函数,将像素值传进去,得到的就是具体的vw vh单位		 
     */
    .box{
    
    
        width: vw(300);
        height: vh(100);
        font-size: vh(16);
        background-color: black;
        margin-left: vw(10);
        margin-top: vh(10);
        border: vh(2) solid red;
    }
</style>

2. Process public styles: create a new rem.scss file

== The class name needs to be distinguished from the project's public class name, otherwise it will affect each other==

//默认设计稿的宽度
$designWidth:1920;
//默认设计稿的高度
$designHeight:1080;
@for $value from 1 through 100 {
    
    
    .pdRem-#{
    
    $value},
    .ptbRem-#{
    
    $value},
    .ptRem-#{
    
    $value} {
    
    
      padding-top: $value/$designHeight * 1vh;
    }
    .pdRem-#{
    
    $value},
    .ptbRem-#{
    
    $value},
    .pbRem-#{
    
    $value} {
    
    
      padding-bottom: $value/$designHeight * 1vh;
    }
    .pdRem-#{
    
    $value},
    .plrRem-#{
    
    $value},
    .plRem-#{
    
    $value} {
    
    
      padding-left: $value/$designWidth * 1vw;
    }
    .pdRem-#{
    
    $value},
    .plrRem-#{
    
    $value},
    .prRem-#{
    
    $value} {
    
    
      padding-right: $value/$designWidth * 1vw;
    }
    .mgRem-#{
    
    $value},
    .mtbRem-#{
    
    $value},
    .mtRem-#{
    
    $value} {
    
    
      margin-top: $value/$designHeight * 1vh;
    }
    .mgRem-#{
    
    $value},
    .mtbRem-#{
    
    $value},
    .mbRem-#{
    
    $value} {
    
    
      margin-bottom: $value/$designHeight * 1vh;
    }
    .mgRem-#{
    
    $value},
    .mlrRem-#{
    
    $value},
    .mlRem-#{
    
    $value} {
    
    
      margin-left: $value/$designWidth * 1vw;
    }
    .mgRem-#{
    
    $value},
    .mlrRem-#{
    
    $value},
    .mrRem-#{
    
    $value} {
    
    
      margin-right: $value/$designWidth * 1vw;
    }
  }

@for $value from 10 through 40 {
    
    
  .sizeRem-#{
    
    $value} {
    
    
    font-size: $value/$designHeight * 1vh;
  }
}

*{
    
    
  box-sizing: border-box;
}
.s-yellow{
    
    
  color: #FFC300;
}
.s-red{
    
    
  color: #CB272C;
}
.s-blue{
    
    
  color: #00CDCF;
}
.s-gray{
    
    
  color: #979797;
}
.line-1 {
    
    
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

// 引入即可使用
<style lang="scss" scoped>
@import "./components/css/rem.scss";
</style>

3. Echarts chart adaptation automatic resize()

Encapsulation directive directive.js

npm install element-resize-detector --save
// directive.js
import * as ECharts from "echarts";
import elementResizeDetectorMaker from "element-resize-detector";
import Vue from "vue";
const HANDLER = "_vue_resize_handler";
function bind(el, binding) {
    
    
  el[HANDLER] = binding.value
    ? binding.value
    : () => {
    
    
        let chart = ECharts.getInstanceByDom(el);
        if (!chart) {
    
    
          return;
        }
        chart.resize();
      };
  // 监听绑定的div大小变化,更新 echarts 大小
  elementResizeDetectorMaker().listenTo(el, el[HANDLER]);
}
function unbind(el) {
    
    
  // window.removeEventListener("resize", el[HANDLER]);
  elementResizeDetectorMaker().removeListener(el, el[HANDLER]);
  delete el[HANDLER];
}
// 自定义指令:v-chart-resize 示例:v-chart-resize="fn"
Vue.directive("resize", {
    
     bind, unbind });

It can be used after introducing it into main.js

import '@/directive/directive';

<template>
  <div class="linechart">
    <div ref="chart" v-resize class="chart"></div>
  </div>
</template>

4. Text in the chart, such as legend, abscissa, etc. font size adaptation: public method

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

The function can be mounted to the prototype and used

import {
    
    fitChartSize} from '@src/utils/dataUtil.js'
Vue.prototype.fitSize = fitChartSize;

textStyle: {
    
    
    color: "green",
    fontSize: this.fitSize(18) //字体自适应
},

5. Subcomponents monitor data changes and refresh charts in real time: deep monitoring + setOption

props: ["list"],
  watch: {
    
    
    list: {
    
    
      handler(val) {
    
    
        // 深度监听没有旧值
        this.month = val.map((item) => {
    
    
          return item.month + "月";
        });
        this.orderNum = val.map((item) => {
    
    
          return item.orderCount;
        });
        this.oldNum = val.map((item) => {
    
    
          return item.servedCount;
        });
        this.goodRate = val.map((item) => {
    
    
          return item.favorableRate;
        });
        let option = {
    
    
          xAxis: [
            {
    
    
              data: this.month,
            },
          ],
          series: [
            {
    
    
              data: this.orderNum, // 订单量
            },
            {
    
    
              data: this.oldNum, // 服务人数
            },
            {
    
    
              data: this.goodRate, //折线图数据
            },
          ],
        };
        this.chart.setOption(option);
      },
      // 这里是关键,代表递归监听的变化
      deep: true,
    },
  },

6、websocket

// index.vue page
When running locally, the same port number is used by both the websocket and the interface, which will cause the port number to be occupied and an error will be reported when running. The test environment is fine.

<script>
export default {
    
    
  data() {
    
    
    return {
    
    
      lockReconnect: false, //禁止重连
      time: 1, // 断开重连的时间间隔
      websock: null,
      // 对象分析 30秒切换tab,最新订单10条,30秒滚动,更新天气
      timerId: null,
      // websocket
      open: false, //是否真正建立连接
      res: {
    
    }, // 所有数据
      ],
    };
  },
  created() {
    
    
    this.initWebSocket();
  },
  mounted() {
    
    
    this.timerId = setInterval(() => {
    
    
      this.timeOperated();
    }, 30000);
  },
  // 销毁定时器
  beforeDestroy() {
    
    
    clearInterval(this.timerId); // 在Vue实例销毁前,清除时间定时器
    this.timerId = null;
  },

  destroyed() {
    
    
    this.websock.close(); //离开路由之后断开websocket连接
  },
  methods: {
    
    
    // 定时30s操作
    timeOperated() {
    
    
      if (this.open) {
    
    
        this.websock.send("ping");
      }
      // 切换tab
      this.$refs.chart5.tab =
        this.$refs.chart5.tab == 3 ? 1 : this.$refs.chart5.tab + 1;
      // 切换最近订单
      this.$refs.chart7.tab = this.$refs.chart7.tab == 1 ? 2 : 1;
      // TODO更新天气
      this.$refs.header.getWeather();
    },
    //初始化weosocket
    initWebSocket() {
    
    
     const url=window.location.host
    
      this.websock = new WebSocket(
        `ws://${
      
      url}${
      
      process.env.VUE_APP_BASE_API}/report/webSocket/screen/2`
      );

      // 连接建立时触发
      this.websock.onopen = () => {
    
    
        console.log("连接成功");
        this.open = true;
        this.time = 1;
      };

      // 客户端接收服务端数据时触发
      this.websock.onmessage = (e) => {
    
    
        if (e.data != "ping") {
    
    
          console.log(JSON.parse(e.data));
          this.res = JSON.parse(e.data);
        } else {
    
    
          console.log("接收数据:", e.data);
        }
      };

      // 通信发生错误时触发
      this.websock.onerror = () => {
    
    
        console.log("出现错误");
        this.open = false;
        this.reconnect();
      };
      // 连接关闭时触发
      this.websock.onclose = () => {
    
    
        console.log("断开连接");
        this.open = false;
        this.reconnect();
      };
    },
    // 断开重连
    reconnect(url) {
    
    
      // 防止错误和断开重复重连
      if (this.lockReconnect) return;
      this.lockReconnect = true;
      setTimeout(() => {
    
    
        //没连接上会一直重连,设置延迟避免请求过多
        this.initWebSocket();
        this.lockReconnect = false;
        this.time++;
      }, this.time * 1000);
    },
  },
};
</script>

7. Order statistics list data carousel switching: carousel chart 10s switching + double-layer array (4 per page)

<template>
  <div class="w100 sizeRem-14 white">
    <el-carousel indicator-position="none" height="100%" autoplay interval="10000">
      <el-carousel-item v-for="(items, index) in newList" :key="index">
        <div style="height: 20%" class="flex1 w100" v-for="(item, i) in items" :key="i">
          <div class="flex-2 line-1">{
    
    {
    
     item.providerName }}</div>
          <div class="flex-1 text-right">{
    
    {
    
     item.totalOrderCount }}</div>
        </div>
      </el-carousel-item>
    </el-carousel>
  </div>
</template>

<script>
export default {
    
    
  props: ["list"],
  data() {
    
    
    return {
    
    
      newList: []
    };
  },
  watch: {
    
    
    list: {
    
    
      handler(val) {
    
    
        let arr = []
        for (var i = 0; i < val.length; i += 4) {
    
    
          arr.push(val.slice(i, i + 4));
        }
        this.newList = arr
        console.log(111, this.newList)
      },
      // 这里是关键,代表递归监听的变化
      deep: true,
    },
  },
};
</script>


Guess you like

Origin blog.csdn.net/weixin_43848576/article/details/131515200