vue3 + ts + 大屏数字滚动播放

260 阅读1分钟

样式

image.png

父组件

<template>

<div class="card-jyxz">

  <div class="list">
    <NumberTo :value="GdmjNum" :time="1"/>
    <div class="text-span" >
      <span class="spanDis">
        <span class="name">耕地面积</span><span class="unit">(亩)</span>
      </span>
    </div>
  </div>

  <div class="list">
    <NumberTo :value="FgqxNum" :time="1"/>
    <div class="text-span" >
       <span class="spanDis">
        <span class="name">覆盖区县</span><span class="unit">(个)</span>
      </span>
    </div>
  </div>

</div>
</template>

<script setup lang="ts">
  // 引入子组件
  import NumberTo from "@mars/components/numberTo/index.vue"
</script>

子组件

<template>
  <div class="chartNum">
    <div class="box-item">
      <!-- 判断是否是数字  (逗号不需要框) -->
      <li
        :class="{ 'number-item': !isNaN(item), 'mark-item': isNaN(item) }"
        v-for="(item, index) in orderNum"
        :key="index"
      >
        <span v-if="!isNaN(item)">
          <!-- 每个数字对应的 0-9 的滚动列表,使数字竖直排列向上滚动 最终定位在对应的数字上 -->
          <i ref="numberItem">0123456789</i>
        </span>
        <span class="comma" v-else>{{ item }}</span>
      </li>
    </div>
  </div>
</template>

<script setup lang="ts">
import {defineProps, onMounted, ref, watchEffect} from "vue"
import {$message} from "@mars/components/mars-ui";

const props = defineProps({
  value: {
    type: Number, // 具体数值
    default() {
      return 0;
    },
  },
  time: {
    type: Number, // 滚动开始时间
    default() {
      return 1;
    },
  },
})
const soValue = ref(0)
const soTime = ref(0)

let orderNum = ref(["0", "0", ",", "0", "0", "0", ",", "0", "0", "0"])
let numberItem = ref(null)
let timer



watchEffect(() => {
  soValue.value = props.value
  soTime.value = props.time
  toOrderNum(soValue.value); // 这里输入数字即可调用
  increaseNumber(soTime.value);
},{
  flush:"post"
})

onMounted(() => {
  toOrderNum(soValue.value); // 这里输入数字即可调用
  increaseNumber(soTime.value);
})

// 定时增长数字
const increaseNumber = (time) => {
    timer = setInterval(() => {
      setNumberTransform();
    }, time * 1000);
  }

// 设置文字滚动
  const setNumberTransform = () => {
  const numberItems = numberItem.value; // 拿到数字的ref,计算元素数量
  let numberArr:any = orderNum.value.filter((item:any) => !isNaN(item));
  // 结合CSS 对数字字符进行滚动显示
  for (let index = 0; index < numberItems.length; index++) {
    const elem = numberItems[index];
    // 每位数字对应偏移量
    elem.style.transform = `translate(-50%, -${numberArr[index] * 10}%)`;
  }
}

// 处理传过来的具体值value
const toOrderNum= (num) => {
  num = num.toString();
  // 把具体值value变成字符串
  if (num.length < 8) {
    num = "0" + num; // 如未满八位数,添加"0"补位
    toOrderNum(num); // 递归添加"0"补位
  } else if (num.length === 8) {
    // 具体值value中加入逗号
    num = num.slice(0, 2) + "," + num.slice(2, 5) + "," + num.slice(5, 8);
    orderNum.value = num.split(""); // 将其便变成数据,渲染至滚动数组
  } else {
    // 具体值value数字超过显示异常
    $message("数量过大,显示异常,请联系后台管理员")
  }
}

</script>

<style scoped lang='less'>
.chartNum{
  display: flex;
  justify-content: center;
  align-items: center;
}
/*具体值value总量滚动数字设置*/
.box-item {
  padding: 10px 10px;
  position: relative;
  height: 80px;
  font-size: 54px;
  line-height: 41px;
  text-align: center;
  list-style: none;
  color: #258aff;
  writing-mode: vertical-lr;
  text-orientation: upright;
  /*文字禁止编辑*/
  -moz-user-select: none; /*火狐*/
  -webkit-user-select: none; /*webkit浏览器*/
  -ms-user-select: none; /*IE10*/
  -khtml-user-select: none; /*早期浏览器*/
  user-select: none;
}

/* 默认逗号设置 */
.mark-item {
  //width: 10px;
  width: 0px;
  height: 100px;
  margin-right: 5px;
  line-height: 10px;
  font-size: 48px;
  position: relative;

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

/*滚动数字设置*/
.number-item {
  width: 42px;
  height: 59px;
  background: rgba(1, 24, 24, 0.25);
  border: 1px solid rgba(4, 252, 255, 0.7);
  list-style: none;
  margin-right: 10px;
  margin-bottom: 0;
  //background: #fff;
  border-radius: 4px;
  //background: rgba(1, 23, 23, 0.55);


  & > span {
    position: relative;
    display: inline-block;
    margin-right: 10px;
    width: 100%;
    height: 100%;
    writing-mode: tb-rl; // writing-mode 改变文字排列方向
    text-orientation: upright; // 文字方向
    overflow: hidden;

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

      font-size: 37px;
      font-family: Arial;
      font-weight: bold;
      color: #1FE0FD;
    }
  }
}

.number-item:last-child {
  margin-right: 0;
}
</style>