几行代码实现vue3数据大屏自适应~~

简介: 几行代码实现vue3数据大屏自适应~~

一:适用场景

最近在搭建vue3+ts+vite的一个后台模板,再做数据大屏的时候,放大或缩小浏览器会导致页面盒子无法铺满以及不能按照初始比例渲染;最后找到了以下这个方法可以很好地让大屏按照比例放大缩小,希望可以帮到大家。

二:先看效果

2023-04-16 (4).png

大屏自适应

三:代码实现

<script setup lang='ts'>
  import {onMounted, ref} from 'vue';
  import {useRouter} from "vue-router";
  import * as echarts from 'echarts';
  import {init, EChartsOption} from 'echarts';
  import mapJson from './modules/china.json'
  const loading = ref(true)
  // 获取自适应的盒子,也就是包裹echarts的最外层父级盒子
  const dataScreenRef = ref<HTMLElement | null>(null);
  onMounted(() => {
    // 重点一:
    // 初始化时为外层盒子加上缩放属性,防止刷新界面时就已经缩放
    if (dataScreenRef.value) {
      dataScreenRef.value.style.transform = `scale(${getScale()}) translate(-50%, -50%)`;
      dataScreenRef.value.style.width = `1920px`;
      dataScreenRef.value.style.height = `1080px`;
    }
    // 初始化echarts
    initChart();
    // 重点二:
    // 为浏览器绑定事件
    window.addEventListener("resize", resize);
  });
  // 重点三:
  // 根据浏览器大小推断缩放比例
  const getScale = (width = 1920, height = 1080) => {
    let ww = window.innerWidth / width;
    let wh = window.innerHeight / height;
    return ww < wh ? ww : wh;
  };
  // 重点四:
  // 监听浏览器 resize 事件
  const resize = () => {
    if (dataScreenRef.value) {
      dataScreenRef.value.style.transform = `scale(${getScale()}) translate(-50%, -50%)`;
    }
    // 使用了 scale 的echarts其实不需要需要重新计算缩放比例
    // Object.values(dataScreen).forEach(chart => {
    //   chart && chart.resize();
    // });
  };
  // 注册echarts
  function initChart() {
    const myChart = init(document.getElementById('map') as HTMLDivElement)
    const myChart2 = init(document.getElementById('map2') as HTMLDivElement)
    const myChart3 = init(document.getElementById('map3') as HTMLDivElement)
    const myChart4 = init(document.getElementById('map4') as HTMLDivElement)
    const myChart5 = init(document.getElementById('map5') as HTMLDivElement)
    const myChart6 = init(document.getElementById('map6') as HTMLDivElement)
    echarts.registerMap('china', mapJson)
    const option = <EChartsOption>{
      backgroundColor: "transparent",
      series: [
        {
          type: "map",
          roam: false,
          top: 100,
          label: {
            normal: {
              show: true,
              textStyle: {
                color: "#fff",
              },
            },
            emphasis: {
              textStyle: {
                color: "#fff",
              },
            },
          },
          itemStyle: {
            normal: {
              borderColor: "#2ab8ff",
              borderWidth: 1.5,
              areaColor: "#12235c",
            },
            emphasis: {
              areaColor: "#2AB8FF",
              borderWidth: 0,
              color: "green",
            },
          },
          zoom: 1.5,
          roam: true,
          map: "china", //使用
        },
      ],
    }
    myChart.setOption(option)
    myChart2.setOption(option)
    myChart3.setOption(option)
    myChart4.setOption(option)
    myChart5.setOption(option)
    myChart6.setOption(option)
    window.addEventListener("resize", function () {
      myChart.resize();
      myChart2.resize();
      myChart3.resize();
      myChart4.resize();
      myChart5.resize();
      myChart6.resize();
    });
    setTimeout(() => {
      loading.value = false
    }, 2000)
  }
  // 返回首页
  const router = useRouter();
  function backIndex() {
    // console.log('关闭');
    router.push('/')
  }
  // 获取当前时间
  const currentDate = ref('');
  const a = ["日", "一", "二", "三", "四", "五", "六"];
  const week = ref(null);
  const str = ref('');
  const timeInterval = setInterval(()=>{
    currentDate.value = new Date().toLocaleString()
    week.value = new Date().getDay();
    str.value = "今天是星期"+ a[week.value]
  },1000)
</script>
<template>
  <div class="screen-bg" v-loading="loading">
    <div class="container" ref="dataScreenRef">
      <div class="header">
        <div class="date">{{currentDate + '&nbsp; &nbsp; &nbsp; ' + str}}</div>
        <div class="title">国内贫富差距分布图</div>
            <div class="light" @click="backIndex">
              <div></div>
              <div></div>
              <div></div>
              <div></div>
              X
            </div>
      </div>
      <div class="body">
        <div class="map-box">
          <div id="map"></div>
        </div>
        <div class="right-data">
          <div class="item-box">
            <div id="map2"></div>
          </div>
          <div class="item-box">
            <div id="map3"></div>
          </div>
        </div>
      </div>
      <div class="footer">
        <div class="item-box">
          <div id="map4"></div>
        </div>
        <div class="item-box">
          <div id="map5"></div>
        </div>
        <div class="item-box">
          <div id="map6"></div>
        </div>
      </div>
    </div>
  </div>
</template>
<style scoped lang='scss'>
  // 背景
  .screen-bg {
    width: 100%;
    height: 100%;
    background: url('@/assets/dataScreen/background-6.png') no-repeat;
    background-repeat: no-repeat;
    background-attachment: fixed;
    background-position: center;
    background-size: 100% 100%;
    background-size: cover;
    .light {
      width: 40px;
      height: 30px;
      position: absolute;
      top: 42px;
      right: 40px;
      z-index: 99999;
      transform: translate(-50%, -50%);
      /* width: fit-content; */
      text-align: center;
      line-height: 30px;
      color: #ffffff;
      font-size: 20px;
      text-transform: uppercase;
      transition: 0.5s;
      letter-spacing: 4px;
      cursor: pointer;
      overflow: hidden;
    }
    .light:hover {
      background-color: #ffffff;
      color: #050801;
      box-shadow: 0 0 5px #ffffff,
      0 0 25px #ffffff,
      0 0 50px #ffffff,
      0 0 200px #ffffff;
    }
    .light div {
      position: absolute;
    }
    .light div:nth-child(1) {
      width: 100%;
      height: 2px;
      top: 0;
      left: -100%;
      background: linear-gradient(to right, transparent, #ffffff);
      animation: animate1 1s linear infinite;
    }
    .light div:nth-child(2) {
      width: 2px;
      height: 100%;
      top: -100%;
      right: 0;
      background: linear-gradient(to bottom, transparent, #ffffff);
      animation: animate2 1s linear infinite;
      animation-delay: 0.25s;
    }
    .light div:nth-child(3) {
      width: 100%;
      height: 2px;
      bottom: 0;
      right: -100%;
      background: linear-gradient(to left, transparent, #ffffff);
      animation: animate3 1s linear infinite;
      animation-delay: 0.5s;
    }
    .light div:nth-child(4) {
      width: 2px;
      height: 100%;
      bottom: -100%;
      left: 0;
      background: linear-gradient(to top, transparent, #ffffff);
      animation: animate4 1s linear infinite;
      animation-delay: 0.75s;
    }
    @keyframes animate1 {
      0% {
        left: -100%;
      }
      50%,
      100% {
        left: 100%;
      }
    }
    @keyframes animate2 {
      0% {
        top: -100%;
      }
      50%,
      100% {
        top: 100%;
      }
    }
    @keyframes animate3 {
      0% {
        right: -100%;
      }
      50%,
      100% {
        right: 100%;
      }
    }
    @keyframes animate4 {
      0% {
        bottom: -100%;
      }
      50%,
      100% {
        bottom: 100%;
      }
    }
    // 中心容器
    .container {
      position: fixed;
      top: 50%;
      left: 50%;
      z-index: 999;
      display: flex;
      flex-direction: column;
      overflow: hidden;
      transition: all 0.3s;
      transform-origin: left top;
      /*!* 设置一个最小的宽度 *!*/
      min-width: 1500px;
      /* 设置一个最大的宽度 */
      max-width: 1500px;
      margin: 0 auto;
      padding-top: 20px;
      .header {
        position: relative;
        height: 77px;
        margin-bottom: 20px;
        background-image: url('@/assets/dataScreen/pic-12.png');
        background-repeat: no-repeat;
        background-size: cover;
        .date {
          position: absolute;
          left: 100px;
          top: 55%;
          transform: translateY(-50%);
          font-family: FZHei-B01S, Arial, sans-serif;
          font-size: 20px;
          color: rgb(255, 255, 255);
          font-weight: normal;
          justify-content: center;
          text-align: center;
        }
        .title {
          position: absolute;
          left: 50%;
          top: 50%;
          transform: translate(-50%, -50%);
          font-family: FZHei-B01S, Arial, sans-serif;
          font-size: 30px;
          color: rgb(255, 255, 255);
          font-weight: normal;
          justify-content: center;
          text-align: center;
        }
      }
      .body {
        display: flex;
        justify-content: space-between;
        .map-box {
          width: 700px;
          height: 430px;
          margin-right: 20px;
          border-width: 2px;
          border-color: rgb(14, 71, 143);
          border-style: solid;
          // background-color: rgba(14, 71, 143, 0.32);
          // background-clip: padding-box;
          background-image: url('@/assets/dataScreen/border-2.gif');
          background-size: 100% 100%;
          background-repeat: no-repeat;
          filter: blur(0px);
          #map {
            width: 100%;
            height: 100%;
          }
        }
        .right-data {
          flex: 1;
          display: flex;
          justify-content: space-between;
          background-color: transparent;
          .item-box {
            width: 350px;
            border-width: 2px;
            border-color: rgb(14, 71, 143);
            border-style: solid;
            background-image: url('@/assets/dataScreen/border-2.gif');
            background-size: 100% 100%;
            background-repeat: no-repeat;
            filter: blur(0px);
            &:last-child {
              margin-right: 0;
            }
            #map2,
            #map3 {
              width: 100%;
              height: 100%;
            }
          }
        }
      }
      .footer {
        margin-top: 20px;
        display: flex;
        justify-content: space-between;
        .item-box {
          width: 440px;
          height: 250px;
          border-width: 2px;
          border-color: rgb(14, 71, 143);
          border-style: solid;
          background-image: url('@/assets/dataScreen/border-2.gif');
          background-size: contain;
          background-repeat: no-repeat;
          filter: blur(0px);
          #map4,
          #map5,
          #map6 {
            width: 100%;
            height: 100%;
          }
        }
      }
    }
  }</style>


目录
相关文章
|
1天前
|
JavaScript API UED
Vue3中的Suspense组件有什么用?
Vue3中的Suspense组件有什么用?
16 6
|
1天前
|
JavaScript 前端开发 索引
Vue3基础之v-if条件与 v-for循环
Vue3基础之v-if条件与 v-for循环
6 0
|
1天前
|
JavaScript
Vue3基础之v-bind与v-on
Vue3基础之v-bind与v-on
9 0
|
1天前
|
JavaScript 测试技术 API
Vue3中定义变量是选择ref还是reactive?
Vue3中定义变量是选择ref还是reactive?
12 2
|
1天前
|
移动开发 前端开发
ruoyi-nbcio-plus基于vue3的flowable为了适配文件上传改造VForm3的代码记录
ruoyi-nbcio-plus基于vue3的flowable为了适配文件上传改造VForm3的代码记录
17 1
|
1天前
|
JavaScript 前端开发
vue2升级到vue3的一些使用注意事项记录(四)
vue2升级到vue3的一些使用注意事项记录(四)
12 0
|
1天前
|
移动开发 前端开发
ruoyi-nbcio-plus基于vue3的flowable收回任务后重新进行提交表单的处理
ruoyi-nbcio-plus基于vue3的flowable收回任务后重新进行提交表单的处理
13 0
|
1天前
|
移动开发 前端开发
ruoyi-nbcio-plus基于vue3的flowable多租户机制
ruoyi-nbcio-plus基于vue3的flowable多租户机制
|
1天前
|
移动开发 前端开发
ruoyi-nbcio-plus基于vue3的flowable的消息中心我的消息的升级修改
ruoyi-nbcio-plus基于vue3的flowable的消息中心我的消息的升级修改
|
1天前
|
JavaScript 前端开发
vue3中使用动态组件
vue3中使用动态组件
10 0