vue3+elementPlus:实现数字滚动效果(用于大屏可视化)

自行封装注册一个公共组件

案例一:

//成功案例:
//NumberScroll.vue
/*
数字滚动特效组件 NumberScroll
*/

<template>
  <span class="number-scroll-grow">
    <span
      ref="numberScroll"
      :data-time="time"
      class="number-scroll"
      :data-value="value">
      0
      </span>
  </span>
</template>

<script>
import { defineComponent } from "vue";
export default defineComponent({
  name: "numberScroll",
  props: {
    time: {
      type: Number,
      default: 2,
    },
    value: {
      type: Number,
      default: 0,
    },
    thousandSign: {
      type: Boolean,
      default: () => false,
    },
  },
  data() {
    return {
      oldValue: 0,
    };
  },
  watch: {
    value: function (value, oldValue) {
      this.numberScroll(this.$refs.numberScroll);
    },
  },
  methods: {
    numberScroll(ele) {
      let _this = this;
      let value = _this.value - _this.oldValue;
      let step = (value * 10) / (_this.time * 100);
      let current = 0;
      let start = _this.oldValue;
      let t = setInterval(function () {
        start += step;
        if (start > _this.value) {
          clearInterval(t);
          start = _this.value;
          t = null;
        }
        if (current === start) {
          return;
        }
        current = parseInt(start);
        _this.oldValue = current;
        if (_this.thousandSign) {
          ele.innerHTML = current
            .toString()
            .replace(/(\d)(?=(?:\d{3}[+]?)+$)/g, "$1,");
        } else {
          ele.innerHTML = current.toString();
        }
      }, 10);
    },
  },
  mounted() {
    this.$nextTick(() => {
      this.numberScroll(this.$refs.numberScroll);
    });
  },
});
</script>

<style lang="scss" scoped>
.number-scroll-grow {
  transform: translateZ(0);
}
</style>

//单页面
//html
<div class="count">
  <!-- 组件 -->
  <numberScroll :value="datalist.equip.realTimeDeviceCount" :time="30"></numberScroll>
</div>

案例二

这个是拉取vue-count-to插件源码,因为这个插件在vue3里不能用

//先在common文件夹建立requestAnimationFrame.js
let lastTime = 0
const prefixes = 'webkit moz ms o'.split(' ') // 各浏览器前缀

let requestAnimationFrame
let cancelAnimationFrame

const isServer = typeof window === 'undefined'
if (isServer) {
 requestAnimationFrame = function () {
 }
 cancelAnimationFrame = function () {
 }
} else {
 requestAnimationFrame = window.requestAnimationFrame
 cancelAnimationFrame = window.cancelAnimationFrame
 let prefix
 // 通过遍历各浏览器前缀,来得到requestAnimationFrame和cancelAnimationFrame在当前浏览器的实现形式
 for (let i = 0; i < prefixes.length; i++) {
 if (requestAnimationFrame && cancelAnimationFrame) { break }
 prefix = prefixes[i]
 requestAnimationFrame = requestAnimationFrame || window[prefix + 'RequestAnimationFrame']
 cancelAnimationFrame = cancelAnimationFrame || window[prefix + 'CancelAnimationFrame'] || window[prefix + 'CancelRequestAnimationFrame']
 }

 // 如果当前浏览器不支持requestAnimationFrame和cancelAnimationFrame,则会退到setTimeout
 if (!requestAnimationFrame || !cancelAnimationFrame) {
 requestAnimationFrame = function (callback) {
 const currTime = new Date().getTime()
 // 为了使setTimteout的尽可能的接近每秒60帧的效果
 const timeToCall = Math.max(0, 16 - (currTime - lastTime))
 const id = window.setTimeout(() => {
 const time = currTime + timeToCall
 callback(time)
 }, timeToCall)
 lastTime = currTime + timeToCall
 return id
 }

 cancelAnimationFrame = function (id) {
 window.clearTimeout(id)
 }
 }
}

export { requestAnimationFrame, cancelAnimationFrame }

//再在components文件夹建立CountTo.vue
<template>
  <span>
  {{displayValue}}
  </span>
 </template>
 <script>
 import { requestAnimationFrame, cancelAnimationFrame } from '../common/js/requestAnimationFrame.js'
 export default {
  props: {
  startVal: {
  type: Number,
  required: false,
  default: 0
  },
  endVal: {
  type: Number,
  required: false,
  default: null
  },
  duration: {
  type: Number,
  required: false,
  default: 3000
  },
  autoplay: {
  type: Boolean,
  required: false,
  default: true
  },
  //小数点位数
  decimals: {
  type: Number,
  required: false,
  default: 0,
  validator (value) {
  return value >= 0
  }
  },
  decimal: {
  type: String,
  required: false,
  default: '.'
  },
  separator: {
  type: String,
  required: false,
  default: ','
  },
  prefix: {
  type: String,
  required: false,
  default: ''
  },
  suffix: {
  type: String,
  required: false,
  default: ''
  },
  useEasing: {
  type: Boolean,
  required: false,
  default: true
  },
  easingFn: {
  type: Function,
  default (t, b, c, d) {
  return c * (-Math.pow(2, -10 * t / d) + 1) * 1024 / 1023 + b
  }
  }
  },
  data () {
  return {
  localStartVal: this.startVal,
  displayValue: this.formatNumber(this.startVal),
  printVal: null,
  paused: false,
  localDuration: this.duration,
  startTime: null,
  timestamp: null,
  remaining: null,
  rAF: null
  }
  },
  computed: {
  countDown () {
  return this.startVal > this.endVal
  }
  },
  watch: {
  startVal () {
  if (this.autoplay) {
  this.start()
  }
  },
  endVal () {
  if (this.autoplay) {
  this.start()
  }
  }
  },
  mounted () {
  if (this.autoplay) {
  this.start()
  }
  this.$emit('mountedCallback')
  },
  methods: {
  start () {
  this.localStartVal = this.startVal
  this.startTime = null
  this.localDuration = this.duration
  this.paused = false
  this.rAF = requestAnimationFrame(this.count)
  },
  pauseResume () {
  if (this.paused) {
  this.resume()
  this.paused = false
  } else {
  this.pause()
  this.paused = true
  }
  },
  pause () {
  cancelAnimationFrame(this.rAF)
  },
  resume () {
  this.startTime = null
  this.localDuration = +this.remaining
  this.localStartVal = +this.printVal
  requestAnimationFrame(this.count)
  },
  reset () {
  this.startTime = null
  cancelAnimationFrame(this.rAF)
  this.displayValue = this.formatNumber(this.startVal)
  },
  count (timestamp) {
  if (!this.startTime) this.startTime = timestamp
  this.timestamp = timestamp
  const progress = timestamp - this.startTime
  this.remaining = this.localDuration - progress
 
  if (this.useEasing) {
  if (this.countDown) {
  this.printVal = this.localStartVal - this.easingFn(progress, 0, this.localStartVal - this.endVal, this.localDuration)
  } else {
  this.printVal = this.easingFn(progress, this.localStartVal, this.endVal - this.localStartVal, this.localDuration)
  }
  } else {
  if (this.countDown) {
  this.printVal = this.localStartVal - ((this.localStartVal - this.endVal) * (progress / this.localDuration))
  } else {
  this.printVal = this.localStartVal + (this.endVal - this.localStartVal) * (progress / this.localDuration)
  }
  }
  if (this.countDown) {
  this.printVal = this.printVal < this.endVal ? this.endVal : this.printVal
  } else {
  this.printVal = this.printVal > this.endVal ? this.endVal : this.printVal
  }
 
  this.displayValue = this.formatNumber(this.printVal)
  if (progress < this.localDuration) {
  this.rAF = requestAnimationFrame(this.count)
  } else {
  this.$emit('callback')
  }
  },
  isNumber (val) {
  return !isNaN(parseFloat(val))
  },
  formatNumber (num) {
  num = num.toFixed(this.decimals)
  num += ''
  const x = num.split('.')
  let x1 = x[0]
  const x2 = x.length > 1 ? this.decimal + x[1] : ''
  const rgx = /(\d+)(\d{3})/
  if (this.separator && !this.isNumber(this.separator)) {
  while (rgx.test(x1)) {
  x1 = x1.replace(rgx, '$1' + this.separator + '$2')
  }
  }
  return this.prefix + x1 + x2 + this.suffix
  }
  },
  unmounted () {
  cancelAnimationFrame(this.rAF)
  }
 }
 </script>
 
 //最后在单文件的html里直接使用
<count-to :
startVal="0" 
:endVal="datalist.equip.realTimeDeviceCount" 
:duration="4000">
</count-to>

上一篇文章,

uniapp踩坑之项目:uni.previewImage简易版预览单图片-CSDN博客文章浏览阅读547次。uniapp踩坑之项目:uni.previewImage简易版预览单图片,主要使用uni.previewImage_uni.previewimagehttps://blog.csdn.net/weixin_43928112/article/details/136565397?spm=1001.2014.3001.5501

  • 11
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值