让你快速上手数据大屏

135 阅读1分钟

简单的大屏适配

无需特定编写rem单位,也不需要考虑单位使用失误导致适配不完全,只需导入一个js文件,即可实现大屏适配,效果如下

screen.gif

如何使用

使用 mixins: [ drawMixin ]实现

index.vue

<div id="index" ref="appRef"></div>
<script>
import drawMixin from "@/utils/drawMixin";
export default {
  mixins: [ drawMixin ],
	data(){return {}}
}
<style>
#app {
  width: 100vw;
  height: 100vh;
  background-color: #091520;
  overflow: hidden;
}
#index {
  color: #d3d6dd;
  width: 1920px;
  height: 1080px;
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  transform-origin: left top;
}
</style>

drawMixin.js

// 屏幕适配 mixin 函数

// * 默认缩放值
const scale = {
  width: '1',
  height: '1',
}

// * 设计稿尺寸(px)
const baseWidth = 1920
const baseHeight = 1080

// * 需保持的比例(默认1.77778)
const baseProportion = parseFloat((baseWidth / baseHeight).toFixed(5))

export default {
  data() {
    return {
      // * 定时函数
      drawTiming: null
    }
  },
  mounted () {
    this.calcRate()
    window.addEventListener('resize', this.resize)
  },
  beforeDestroy () {
    window.removeEventListener('resize', this.resize)
  },
  methods: {
    calcRate () {
      const appRef = this.$refs["appRef"]
      if (!appRef) return 
      // 当前宽高比
      const currentRate = parseFloat((window.innerWidth / window.innerHeight).toFixed(5))
      if (appRef) {
        if (currentRate > baseProportion) {
          // 表示更宽
          scale.width = ((window.innerHeight * baseProportion) / baseWidth).toFixed(5)
          scale.height = (window.innerHeight / baseHeight).toFixed(5)
          appRef.style.transform = `scale(${scale.width}, ${scale.height}) translate(-50%, -50%)`
        } else {
          // 表示更高
          scale.height = ((window.innerWidth / baseProportion) / baseHeight).toFixed(5)
          scale.width = (window.innerWidth / baseWidth).toFixed(5)
          appRef.style.transform = `scale(${scale.width}, ${scale.height}) translate(-50%, -50%)`
        }
      }
    },
    resize () {
      clearTimeout(this.drawTiming)
      this.drawTiming = setTimeout(() => {
        this.calcRate()
      }, 200)
    }
  },
}

关键在scale的使用

scale就是拿出 当前的电脑屏幕宽度像素除以当前屏幕高度像素 去和我们的设计稿宽度像素除以设计稿高度做一个比较。

当前屏幕比例<设计稿比例。那么我们需要缩放的比例就是屏幕宽度除以设计稿宽度

当前屏幕比例>设计稿比例。那么我们需要缩放的比例就是屏幕高度除以设计稿高度

排名滚动

tablescroll.gif

安装

npm install vue-seamless-scroll --save

main.js

import scroll from 'vue-seamless-scroll'
Vue.use(scroll)

index.vue

 <TableCarousel :rollTitle="sdTitle" :rollList="sdList" />

import TableCarousel from "@/components/starMap/TableCarousel.vue";
export default {
	data(){
    	sdTitle: ["头像", "姓名", "性别", "年龄", "执法证号", "学历", "是否在编"],
        sdList: [],
  }
}

TableCarousel.vue

<template>
  <div class="tableCarousel">
    <div class="rollTitle">
      <span v-for="item in rollTitle" :key="item.id">
        {{ item }}
      </span>
    </div>
    <div class="rollContent">
      <vue-seamless-scroll
        :data="rollList"
        class="seamless-warp"
        :class-option="classOption"
      >
        <div class="row" v-for="(item, index) in rollList" :key="item.ssbmid">
          <span :class="[index < 3 ? 'orange' : 'blue', 'orderNum']">{{
            index + 1
          }}</span>
          <span>{{item.name}}</span>
          <span>{{item.field2}}</span>
          <span>{{item.field3}}</span>
          <span>{{item.field4}}</span>
          <span>{{item.field5}}</span>
        </div>
      </vue-seamless-scroll>
    </div>
  </div>
</template>

<script>
export default {
  props: ["rollTitle","rollList"],
  data() {
    return {
    };
  },
  computed: {
    classOption() {
      return {
        step: 1, // 数值越大速度滚动越快
        limitMoveNum: 4, // 开始无缝滚动的数据量 this.dataList.length
        hoverStop: true, // 是否开启鼠标悬停stop
        direction: 1, // 0向下 1向上 2向左 3向右
        openWatch: true, // 开启数据实时监控刷新dom
        singleHeight: 0, // 单步运动停止的高度(默认值0是无缝不停止的滚动) direction => 0/1
        singleWidth: 0, // 单步运动停止的宽度(默认值0是无缝不停止的滚动) direction => 2/3
        waitTime: 1000, // 单步运动停止的时间(默认值1000ms)
        autoPlay: true,
      };
    },
  },
  watch: {},
  created() {},
  mounted() {},
  methods: {},
};
</script>
<style lang='scss' scoped>
.tableCarousel {
  margin-bottom: 30px;
  .orange {
    color: #eda44e;
  }
  .blue {
    color: #65b8f8;
  }
  .orderNum {
    font-weight: 600;
  }
  .rollTitle {
    background: #1f5384;
    font-weight: 600;
    position: relative;
    width: 100%;
    display: flex;
    text-align: center;
    height: 40px;
    line-height: 40px;
    span {
      flex: 2;
    }
    span:nth-of-type(1) {
       width: 40px;
    }
     span:nth-of-type(2) {
        flex: 6;
      }
  }
  .rollContent {
    height: 200px;
    overflow: hidden;
    .row {
      display: flex;
      text-align: center;
      height: 40px;
      line-height: 40px;
      span {
        flex: 2;
      }
      span:nth-of-type(1) {
        width: 40px;
      }
      span:nth-of-type(2) {
        flex: 6;
      }
    }
    .row:nth-child(odd) {
      background: #294358;
    }
  }
  .risk {
    display: flex;
    margin-top: 20px;
    .circleBox {
      text-align: center;
      flex: 1;
      .circle {
        width: 88px;
        height: 88px;
        border: 2px solid #65b8f8;
        border-radius: 50%;
        display: flex;
        flex-direction: column;
        align-items: center;
        justify-content: center;
        margin: 0 auto;
        margin-bottom: 20px;
        span:nth-of-type(1) {
          font-size: 28px;
        }
        span:nth-of-type(2) {
          color: #838d91;
        }
      }
    }
  }
}
</style>

动态数字

numscroll.gif

使用

index.vue

 <NumsRoll
                  :countEnterNum="totalCase"
                  unitVal="件"
                  :numberProp="{
                    width: '26px',
                    height: '30px',
                    'font-size': '22px',
                    'margin-right': '4px',
                  }"
                />

NumsRoll.vue

<template>
  <div class="centerContent">
    <!-- 数字滚动 -->
    <div class="chartNum">
      <div class="box-item">
        <li
          :class="{ 'number-item': !isNaN(item), 'mark-item': isNaN(item)}"
          :style="!isNaN(item)?numberProp:''"
          v-for="(item, index) in orderNum"
          :key="index"
        >
          <span v-if="formatNumber(item)">
            <i ref="numberItem">0123456789</i>
          </span>
          <span class="comma" v-else>{{ item }}</span>
        </li>
      </div>
      <span class="totalUnit">{{ unitVal }}</span>
    </div>
  </div>
</template>

<script>
export default {
  props: {
    countEnterNum: {
      type: [String, Number],
      default: "000000",
    },
    unitVal: {
      type: String,
      default: "1",
    },
    numberProp: {
      type: Object,
      default:()=>{
        return {}
      },
    },
  },
  data() {
    return {
      orderNum: ["0", "0", "0", ",", "0", "0", "0"], // 默认
    };
  },
  components: {},
  created() {},
  mounted() {
    this.getCountEnterNum();
  },
  watch: {
    /* eslint-disable */
    countEnterNum: {
      deep: true,
      handler: function (newV, oldV) {
        let list = [];
        const NumberList = this.formatMoney(newV).split("");
        for (let i = 0; i < NumberList.length; i++) {
          if (NumberList[i] == ",") {
            list.push(NumberList[i]);
          } else {
            list.push("0");
          }
        }
        this.orderNum = list;

        this.getCountEnterNum();
      },
    },
    /* eslint-enable */
  },
  methods: {
    formatMoney(num) {
      /* eslint-disable */
      var res = num.toString().replace(/\d+/, function (n) {
        // 先提取整数部分
        return n.replace(/(\d)(?=(\d{3})+$)/g, function ($1) {
          return $1 + ",";
        });
      });
      return res;
      /* eslint-enable */
    },
    // 判断是否是数值
    formatNumber(val) {
      /* eslint-disable */
      var numReg = /^[0-9]*$/;
      var numRe = new RegExp(numReg);
      if (!numRe.test(val)) {
        return false;
      } else {
        return true;
      }
      /* eslint-enable */
    },
    getCountEnterNum() {
      setTimeout(() => {
        this.$nextTick(() => {
          this.toOrderNum(this.countEnterNum); // 这里输入数字即可调用
          this.setNumberTransform();
        });
      }, 1000);
    },
    // 设置文字滚动
    setNumberTransform() {
      const numberItems = this.$refs.numberItem; // 拿到数字的ref,计算元素数量
      const numberArr = this.orderNum.filter((item) => {
        // console.log(this.formatNumber(item));
        return this.formatNumber(item);
      });
      // 结合CSS 对数字字符进行滚动,显示总数量
      /* eslint-disable */
      for (let index = 0; index < numberItems.length; index++) {
        const elem = numberItems[index];
        elem.style.transform = `translate(-50%, -${numberArr[index] * 10}%)`;
      }
      /* eslint-enable */
    },
    // 处理总数字
    toOrderNum(num) {
      num = num.toString();
      //总数中加入逗号
      /* eslint-disable */
      // num = num.slice(0, 2) + ',' + num.slice(2, 5) + ',' + num.slice(5, 8);
      num = this.formatMoney(num);
      /* eslint-enable */
      this.orderNum = num.split(""); // 将其便变成数据,渲染至滚动数组
      //   }
    },
  },
};
</script>

<style lang="scss" scoped>
.centerContent {
  // width: 100%;
  display: flex;
  flex-wrap: wrap;
  .gmv-title {
    width: 100%;
    text-align: center;
    margin-top: 5vh;
    font-weight: bolder;
    font-size: 32px;
    margin-bottom: 1.8vh;
  }
  .chartNum {
    display: flex;
    align-items: center;
  }
  .cont {
    margin: 0 0;
  }
}

.box-item {
  position: relative;
  height: 40px;
  font-size: 54px;
  line-height: 41px;
  text-align: center;
  list-style: none;

  writing-mode: vertical-lr;
  text-orientation: upright;
  -moz-user-select: none;
  -webkit-user-select: none;
  -ms-user-select: none;
  -khtml-user-select: none;
  user-select: none;
}

.mark-item {
  width: 10px;
  height: 50px;
  margin-right: 8px;
  line-height: 10px;
  font-size: 48px;
  position: relative;

  & > span {
    position: absolute;
    width: 100%;
    bottom: 10px;
    writing-mode: vertical-rl;
    text-orientation: upright;
  }
}

.number-item {
  width: 30px;
  height: 43px;
  font-size: 50px;
  list-style: none;
  margin-right: 9px;
  border-radius: 4px;
  color: #ffffff;
  font-size: 30px;
  background: #072847;
  font-weight: 700;
  border: 1px solid rgba(7, 91, 118, 0.96);
  color: #f2dc13;
  box-shadow: 1px 1px 12px 2px rgba(7, 91, 118, 0.96);
  -webkit-box-shadow: 1px 1px 12px 2px rgba(7, 91, 118, 0.96);
  -moz-box-shadow: 1px 1px 12px 2px rgba(7, 91, 118, 0.96);

  & > span {
    position: relative;
    display: inline-block;
    margin-right: 10px;
    width: 100%;
    height: 100%;
    writing-mode: vertical-rl;
    text-orientation: upright;
    overflow: hidden;
    left: -2px;

    & > i {
      font-style: normal;
      position: absolute;
      top: 0px;
      left: 50%;
      transform: translate(-50%, 0);
      transition: transform 1s ease-in-out;
      letter-spacing: 10px;
    }
  }
}

.number-item:last-child {
  margin-right: 0;
}

.comma {
  color: #ffffff;
  font-size: 50px;
  font-weight: 600;
}
.totalUnit {
  font-size: 16px;
  font-weight: normal;
  // color: #2390fe;
  margin-left: 10px;
  margin-top: 20px;
}
</style>

粒子动画

particle.gif

安装

npm install vue-particles --save-dev

main.js

import VueParticles from 'vue-particles'
Vue.use(VueParticles)

index.vue

<vue-particles
        color="#fff"
        :particle-opacity="0.7"
        :particles-number="100"
        shape-type="circle"
        :particle-size="4"
        lines-color="#fff"
        :lines-width="1"
        :line-linked="true"
        :line-opacity="0.5"
        :lines-distance="150"
        :move-speed="2"
        :hover-effect="true"
        hover-mode="grab"
        :click-effect="true"
        click-mode="push"
      >
      </vue-particles>

属性说明

  • color: String类型。默认’#dedede’。粒子颜色。
  • particleOpacity: Number类型。默认0.7。粒子透明度。
  • particlesNumber: Number类型。默认80。粒子数量。
  • shapeType: String类型。默认’circle’。可用的粒子外观类型有:“circle”,“edge”,“triangle”, “polygon”,“star”。
  • particleSize: Number类型。默认80。单个粒子大小。
  • linesColor: String类型。默认’#dedede’。线条颜色。
  • linesWidth: Number类型。默认1。线条宽度。
  • lineLinked: 布尔类型。默认true。连接线是否可用。
  • lineOpacity: Number类型。默认0.4。线条透明度。
  • linesDistance: Number类型。默认150。线条距离。
  • moveSpeed: Number类型。默认3。粒子运动速度。
  • hoverEffect: 布尔类型。默认true。是否有hover特效。
  • hoverMode: String类型。默认true。可用的hover模式有: “grab”, “repulse”, “bubble”。
  • clickEffect: 布尔类型。默认true。是否有click特效。
  • clickMode: String类型。默认true。可用的click模式有: “push”, “remove”, “repulse”, “bubble”