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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/514161.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

最新408试卷分析+备考经验分享

408出题再糟糕&#xff0c;你是不是还是要考&#xff1f; 别管出题人出多刁钻的题&#xff0c;大家拿到的卷子都是一样的&#xff0c;要难就都难&#xff0c;要刁钻就一起g... 所以再潜心钻研出题规律或出题套路&#xff0c;不如多花些时间去多复习巩固几遍知识点&#xff01…

JAVAEE之IoCDI

Spring 是⼀个 IoC&#xff08;控制反转&#xff09;容器&#xff0c;作为容器, 那么它就具备两个最基础的功能&#xff1a; • 存 • 取 Spring 容器管理的主要是对象, 这些对象, 我们称之为"Bean". 我们把这些对象交由Spring管理, 由 Spring来负责对象的创建…

redis集合Set

set是一种无序集合。它和列表的区别在于列表中的元素都是可以重复的&#xff0c;而set中的元素是不能重复的。而且set中的元素&#xff0c;并不像列表那样是具有顺序的。 SADD是添加一个元素。course是集合。 SMEMBERS SISMEMBER判断Redis在不在集合course里 SREM是用来删除Re…

Celery的任务流

Celery的任务流 在之前调用任务的时候只是使用delay()和apply_async()方法。但是有时我们并不想简单的执行单个异步任务&#xff0c;比如说需要将某个异步任务的结果作为另一个异步任务的参数或者需要将多个异步任务并行执行&#xff0c;返回一组返回值&#xff0c;为了实现此…

Flutter中setState函数的使用注意事项

文章目录 Flutter中setState函数的使用注意事项只能在具有State对象的类中使用不要在build方法中使用将状态更新逻辑放在setState方法内部避免频繁调用使用回调函数更新状态 Flutter中setState函数的使用注意事项 setState()函数是Flutter中非常重要的一个函数&#xff0c;它用…

【教程】宝塔default.db占用空间几十g解决方法|宝塔占用磁盘空间特别大解决方法|宝塔磁盘被占满怎么清理

目录 一、前言二、排查问题三、解决方法 一、前言 用过宝塔创建网站&#xff0c;大家应该都非常熟悉&#xff0c;但是用随着用的时间越来越多&#xff0c;宝塔所占用的空间也越来越多&#xff0c;不停的加大数据盘都没有用&#xff0c;我原先买了30G够用了&#xff0c;随着时间…

基于单片机的盆栽自动浇花系统

**单片机设计介绍&#xff0c;基于单片机的盆栽自动浇花系统 文章目录 一 概要二、功能设计设计思路 三、 软件设计原理图 五、 程序六、 文章目录 一 概要 基于单片机的盆栽自动浇花系统设计概要主要涵盖了通过单片机技术实现盆栽植物的自动化、智能化浇水管理。下面将从系统…

四川古力未来科技抖音小店:安全便捷,购物新体验

在数字化浪潮席卷全球的今天&#xff0c;电商平台的安全性与便捷性成为了消费者最为关心的问题。四川古力未来科技有限公司&#xff0c;凭借其强大的技术实力和深厚的行业经验&#xff0c;为广大消费者带来了一个安全可靠的购物新选择——古力未来科技抖音小店。 古力未来科技抖…

【论文速读】| MASTERKEY:大语言模型聊天机器人的自动化越狱

本次分享论文为&#xff1a;MASTERKEY: Automated Jailbreaking of Large Language Model Chatbots 基本信息 原文作者&#xff1a;Gelei Deng, Yi Liu, Yuekang Li, Kailong Wang, Ying Zhang, Zefeng Li, Haoyu Wang, Tianwei Zhang, Yang Liu 作者单位&#xff1a;南洋理工…

三维VR虚拟展馆打破传统展览的时间与空间限制

探索绿色未来&#xff0c;见证生态转型——这是长江经济带在国家发展蓝图中的承诺。如今&#xff0c;通过线上长江经济带发展阶段性成效展厅&#xff0c;这一承诺正以创新的互动体验呈现给公众&#xff0c;彰显了环境保护与经济增长的和谐统一。 深圳VR公司华锐视点精心策划的长…

网络攻防中json序列化漏洞案例,fastjson远程命令执行漏洞原理

网络攻防中json序列化漏洞案例,fastjson远程命令执行漏洞原理。 网络攻防中的JSON序列化漏洞是指当应用程序使用JSON(JavaScript Object Notation)格式来序列化和反序列化对象时,由于不当处理或不安全的编程实践,导致攻击者能够执行恶意操作的安全漏洞。这些操作可能包括远…

说说对排序算法的一些理解

对排序 - 冒泡排序的理解 冒泡排序是一种简单的排序算法&#xff0c;其基本思想是通过多次遍历数组&#xff0c;每次比较相邻的两个元素。如果前一个元素大于后一个元素&#xff0c;则交换它们的位置。这样&#xff0c;每一次遍历都会将当前未排序部分的最大元素“冒泡”到数组…

【Flutter】windows环境配置

windows 11 环境 官方教程 配置了flutter 环境变量在系统的path里 bin 路径。 死活没反应 关闭了git关闭了dart.exe关闭了vs还是不行卸载重新来 新版git flutter doctor 还需要android 环境

Redis性能管理及集群三种模式(一)

一、前期准备 至少准备三台服务器为主从复制、哨兵的实验做准备 一台主redis、两台从redis 二、Redis性能管理 2.1 查看Redis内存使用 查看Redis内存使用——info memory 2.2 内存使用率 1<内存碎片<1.5表示合理的内存碎片大于>1.5&#xff0c;需要输入shutdown save…

ES学习日记(十)-------Java操作ES之连接客户端

Elasticsearch有两种连接方式: transport、rest。transport 通过TCP方式访问ES(只支持iava)&#xff0c;rest 方式通过http API 访问ES(没有语言限制)。 ES官方建议使用Iest 方式&#xff0c;transport 在7.8 版本中不建议使用&#xff0c;在8.x的版本中废弃。你可以用Java客户…

小白水平理解面试经典题目1431. Kids With the Greatest Number of Candies【Array类】

1431. 拥有最多糖果的孩子 小白渣翻译 一群孩子手里拿 着不同数目的糖果。你打算额外给每个孩子一些糖果&#xff0c;然后再确定哪些孩子拥有最多的糖果。 给你一个数组 candies &#xff0c;其中 candies[i] 代表第 i 个孩子拥有的糖果数目。另给你一个整数 extraCandies &…

MVCC详细总结

简介 MVCC&#xff08;Multi-Version Concurrency Control&#xff09;是一种多版本并发控制机制&#xff0c;主要用于数据库管理系统中&#xff0c;实现对数据库的并发访问。在编程语言中&#xff0c;MVCC可以实现事务内存。 MVCC的特点是读不加锁&#xff0c;读写不冲突。MVC…

基于Unet的BraTS 3d 脑肿瘤医学图像分割,从nii.gz文件中切分出2D图片数据

1、前言 3D图像分割一直是医疗领域的难题&#xff0c;在这方面nnunet已经成为了标杆&#xff0c;不过nnunet教程较少&#xff0c;本人之前跑了好久&#xff0c;一直目录报错、格式报错&#xff0c;反正哪里都是报错等等。并且&#xff0c;nnunet对于硬件的要求很高&#xff0c…

mac、windows 电脑安装使用多个版本的node

我们为啥要安装多个不同版本的node&#xff1f; 开发旧项目时&#xff0c;使用低版本Nodejs。开发新项目时&#xff0c;需使用高版本Node.js。可使用n同时安装多个版本Node.js&#xff0c;并切换到指定版本Node.js。 mac电脑安装 一、全局安装 npm install -g n 二、mac电脑…

内存和网卡压力测试

1.内存压力测试 1.1测试目的 内存压力测试的目的是评估开发板中的内存子系统性能和稳定性&#xff0c;以确保它能够满足特定的应用需求。开发板通常用于嵌入式系统、物联网设备、嵌入式智能家居等场景&#xff0c;这些场景对内存的要求通常比较高。 其内存压力测试的主要目的…