位置: IT常识 - 正文

vue3 | 数据可视化实现数字滚动特效(vue数据可视化大屏布局)

编辑:rootadmin
vue3 | 数据可视化实现数字滚动特效 前言

推荐整理分享vue3 | 数据可视化实现数字滚动特效(vue数据可视化大屏布局),希望有所帮助,仅作参考,欢迎阅读内容。

文章相关热门搜索词:vue可视化创建项目,vue cli可视化,vue cli可视化,vue实现数据可视化,vue可视化创建项目,vue数据可视化大屏布局,vue数据可视化大屏布局,vue实现数据可视化,内容如对您有帮助,希望把文章链接给更多的朋友!

vue3不支持vue-count-to插件,无法使用vue-count-to实现数字动效,数字自动分割,vue-count-to主要针对vue2使用,vue3按照会报错: TypeError: Cannot read properties of undefined (reading '_c') 的错误信息。这个时候我们只能自己封装一个CountTo组件实现数字动效。先来看效果图:

思路

使用Vue.component定义公共组件,使用window.requestAnimationFrame(首选,次选setTimeout)来循环数字动画,window.cancelAnimationFrame取消数字动画效果,封装一个requestAnimationFrame.js公共文件,CountTo.vue组件,入口导出文件index.js。

文件目录

使用示例<CountTo :start="0" // 从数字多少开始 :end="endCount" // 到数字多少结束 :autoPlay="true" // 自动播放 :duration="3000" // 过渡时间 prefix="¥" // 前缀符号 suffix="rmb" // 后缀符号 />入口文件index.jsconst UILib = { install(Vue) { Vue.component('CountTo', CountTo) }}export default UILibmain.js使用import CountTo from './components/count-to/index';app.use(CountTo)requestAnimationFrame.js思路先判断是不是浏览器还是其他环境如果是浏览器判断浏览器内核类型如果浏览器不支持requestAnimationFrame,cancelAnimationFrame方法,改写setTimeout定时器导出两个方法 requestAnimationFrame, cancelAnimationFrame各个浏览器前缀:let prefixes = 'webkit moz ms o';判断是不是浏览器:let isServe = typeof window == 'undefined';增加各个浏览器前缀: let prefix;let requestAnimationFrame;let cancelAnimationFrame;// 通过遍历各浏览器前缀,来得到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'] } //不支持使用setTimeout方式替换:模拟60帧的效果 // 如果当前浏览器不支持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(() => { callback(currTime + timeToCall) }, timeToCall) lastTime = currTime + timeToCall return id } cancelAnimationFrame = function (id) { window.clearTimeout(id) } }完整代码:

requestAnimationFrame.js

let lastTime = 0const prefixes = 'webkit moz ms o'.split(' ') // 各浏览器前缀let requestAnimationFramelet cancelAnimationFrame// 判断是否是服务器环境const isServer = typeof window === 'undefined'if (isServer) { requestAnimationFrame = function () { return } cancelAnimationFrame = function () { return }} 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(() => { callback(currTime + timeToCall) }, timeToCall) lastTime = currTime + timeToCall return id } cancelAnimationFrame = function (id) { window.clearTimeout(id) } }}export { requestAnimationFrame, cancelAnimationFrame }CountTo.vue组件思路vue3 | 数据可视化实现数字滚动特效(vue数据可视化大屏布局)

首先引入requestAnimationFrame.js,使用requestAnimationFrame方法接受count函数,还需要格式化数字,进行正则表达式转换,返回我们想要的数据格式。

引入 import { requestAnimationFrame, cancelAnimationFrame } from './requestAnimationFrame.js'

需要接受的参数:

const props = defineProps({ start: { type: Number, required: false, default: 0 }, end: { type: Number, required: false, default: 0 }, duration: { type: Number, required: false, default: 5000 }, 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; } }})

启动数字动效

const startCount = () => { state.localStart = props.start state.startTime = null state.localDuration = props.duration state.paused = false state.rAF = requestAnimationFrame(count)}

核心函数,对数字进行转动

if (!state.startTime) state.startTime = timestamp state.timestamp = timestamp const progress = timestamp - state.startTime state.remaining = state.localDuration - progress // 是否使用速度变化曲线 if (props.useEasing) { if (stopCount.value) { state.printVal = state.localStart - props.easingFn(progress, 0, state.localStart - props.end, state.localDuration) } else { state.printVal = props.easingFn(progress, state.localStart, props.end - state.localStart, state.localDuration) } } else { if (stopCount.value) { state.printVal = state.localStart - ((state.localStart - props.end) * (progress / state.localDuration)) } else { state.printVal = state.localStart + (props.end - state.localStart) * (progress / state.localDuration) } } if (stopCount.value) { state.printVal = state.printVal < props.end ? props.end : state.printVal } else { state.printVal = state.printVal > props.end ? props.end : state.printVal } state.displayValue = formatNumber(state.printVal) if (progress < state.localDuration) { state.rAF = requestAnimationFrame(count) } else { emits('callback') }}// 格式化数据,返回想要展示的数据格式const formatNumber = (val) => { val = val.toFixed(props.default) val += '' const x = val.split('.') let x1 = x[0] const x2 = x.length > 1 ? props.decimal + x[1] : '' const rgx = /(\d+)(\d{3})/ if (props.separator && !isNumber(props.separator)) { while (rgx.test(x1)) { x1 = x1.replace(rgx, '$1' + props.separator + '$2') } } return props.prefix + x1 + x2 + props.suffix}

取消动效

// 组件销毁时取消动画onUnmounted(() => { cancelAnimationFrame(state.rAF)})

完整代码

<template> {{ state.displayValue }}</template><script setup> // vue3.2新的语法糖, 编写代码更加简洁高效import { onMounted, onUnmounted, reactive } from "@vue/runtime-core";import { watch, computed } from 'vue';import { requestAnimationFrame, cancelAnimationFrame } from './requestAnimationFrame.js'// 定义父组件传递的参数const props = defineProps({ start: { type: Number, required: false, default: 0 }, end: { type: Number, required: false, default: 0 }, duration: { type: Number, required: false, default: 5000 }, 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; } }})const isNumber = (val) => { return !isNaN(parseFloat(val))}// 格式化数据,返回想要展示的数据格式const formatNumber = (val) => { val = val.toFixed(props.default) val += '' const x = val.split('.') let x1 = x[0] const x2 = x.length > 1 ? props.decimal + x[1] : '' const rgx = /(\d+)(\d{3})/ if (props.separator && !isNumber(props.separator)) { while (rgx.test(x1)) { x1 = x1.replace(rgx, '$1' + props.separator + '$2') } } return props.prefix + x1 + x2 + props.suffix}// 相当于vue2中的data中所定义的变量部分const state = reactive({ localStart: props.start, displayValue: formatNumber(props.start), printVal: null, paused: false, localDuration: props.duration, startTime: null, timestamp: null, remaining: null, rAF: null})// 定义一个计算属性,当开始数字大于结束数字时返回trueconst stopCount = computed(() => { return props.start > props.end})// 定义父组件的自定义事件,子组件以触发父组件的自定义事件const emits = defineEmits(['onMountedcallback', 'callback'])const startCount = () => { state.localStart = props.start state.startTime = null state.localDuration = props.duration state.paused = false state.rAF = requestAnimationFrame(count)}watch(() => props.start, () => { if (props.autoPlay) { startCount() }})watch(() => props.end, () => { if (props.autoPlay) { startCount() }})// dom挂在完成后执行一些操作onMounted(() => { if (props.autoPlay) { startCount() } emits('onMountedcallback')})// 暂停计数const pause = () => { cancelAnimationFrame(state.rAF)}// 恢复计数const resume = () => { state.startTime = null state.localDuration = +state.remaining state.localStart = +state.printVal requestAnimationFrame(count)}const pauseResume = () => { if (state.paused) { resume() state.paused = false } else { pause() state.paused = true }}const reset = () => { state.startTime = null cancelAnimationFrame(state.rAF) state.displayValue = formatNumber(props.start)}const count = (timestamp) => { if (!state.startTime) state.startTime = timestamp state.timestamp = timestamp const progress = timestamp - state.startTime state.remaining = state.localDuration - progress // 是否使用速度变化曲线 if (props.useEasing) { if (stopCount.value) { state.printVal = state.localStart - props.easingFn(progress, 0, state.localStart - props.end, state.localDuration) } else { state.printVal = props.easingFn(progress, state.localStart, props.end - state.localStart, state.localDuration) } } else { if (stopCount.value) { state.printVal = state.localStart - ((state.localStart - props.end) * (progress / state.localDuration)) } else { state.printVal = state.localStart + (props.end - state.localStart) * (progress / state.localDuration) } } if (stopCount.value) { state.printVal = state.printVal < props.end ? props.end : state.printVal } else { state.printVal = state.printVal > props.end ? props.end : state.printVal } state.displayValue = formatNumber(state.printVal) if (progress < state.localDuration) { state.rAF = requestAnimationFrame(count) } else { emits('callback') }}// 组件销毁时取消动画onUnmounted(() => { cancelAnimationFrame(state.rAF)})</script>总结

自己封装数字动态效果需要注意各个浏览器直接的差异,手动pollyfill,暴露出去的props参数需要有默认值,数据的格式化可以才有正则表达式的方式,组件的驱动必须是数据变化,根据数据来驱动页面渲染,防止页面出现卡顿,不要强行操作dom,引入的组件可以全局配置,后续组件可以服用,码字不易,请各位看官大佬多多支持,一键三连了~❤️❤️❤️

demo演示

后续的线上demo演示会放在 demo演示 完整代码会放在 个人主页

希望对vue开发者有所帮助~

个人简介:承吾工作年限:5年前端地区:上海个人宣言:立志出好文,传播我所会的,有好东西就及时与大家共享!
本文链接地址:https://www.jiuchutong.com/zhishi/299054.html 转载请保留说明!

上一篇:2023年前端开发趋势未来可期(2023年前端开发找工作好找吗)

下一篇:如何通过nodejs快速搭建一个服务器(nodejs如何使用)

  • 小米蓝牙耳机air冲不进去电(小米蓝牙耳机air2声音小怎么办)

    小米蓝牙耳机air冲不进去电(小米蓝牙耳机air2声音小怎么办)

  • 如何调整单元格内文字行间距(如何调整单元格顺序)

    如何调整单元格内文字行间距(如何调整单元格顺序)

  • 隔空投送点不动蓝色的(隔空投送不动了)

    隔空投送点不动蓝色的(隔空投送不动了)

  • 淘宝在双11期间,红包可以退吗(淘宝在双11期间有优惠吗)

    淘宝在双11期间,红包可以退吗(淘宝在双11期间有优惠吗)

  • 投影仪怎么连接音响(投影仪怎么连接手机)

    投影仪怎么连接音响(投影仪怎么连接手机)

  • 手机知乎为什么不能复制了(手机知乎为什么要下载)

    手机知乎为什么不能复制了(手机知乎为什么要下载)

  • 米notelte是什么型号(小米mi note lte参数)

    米notelte是什么型号(小米mi note lte参数)

  • 抖音举报后有什么反应(抖音举报后什么时候封号)

    抖音举报后有什么反应(抖音举报后什么时候封号)

  • 魅族17有防水功能吗(魅族17pro防尘防水等级)

    魅族17有防水功能吗(魅族17pro防尘防水等级)

  • pad屏幕无法旋转(pad屏幕旋转不了)

    pad屏幕无法旋转(pad屏幕旋转不了)

  • 苹果11怎么微信分身(苹果11怎么微信设置密码)

    苹果11怎么微信分身(苹果11怎么微信设置密码)

  • 微信解绑qq有什么影响(微信解绑qq号后微信还能用吗)

    微信解绑qq有什么影响(微信解绑qq号后微信还能用吗)

  • 交了网费多久可以上网(交上网费后多久可以恢复上网)

    交了网费多久可以上网(交上网费后多久可以恢复上网)

  • word文档切换快捷键(Word文档切换快捷键)

    word文档切换快捷键(Word文档切换快捷键)

  • 京东调货商品是什么意思(京东调货商品是什么意思能退吗)

    京东调货商品是什么意思(京东调货商品是什么意思能退吗)

  • 魅族16s有nfc功能吗(魅族16xs nfc功能)

    魅族16s有nfc功能吗(魅族16xs nfc功能)

  • vivo打电话视频通话怎么弄(vivo打电话视频彩铃怎么取消)

    vivo打电话视频通话怎么弄(vivo打电话视频彩铃怎么取消)

  • 宽带错误651是什么意思(考试时心态崩了怎么办)

    宽带错误651是什么意思(考试时心态崩了怎么办)

  • IT和OT是什么(IT和OT是什么意思)

    IT和OT是什么(IT和OT是什么意思)

  • excel受保护的视图怎么解除(excel受保护的视图怎么解除不掉怎么办)

    excel受保护的视图怎么解除(excel受保护的视图怎么解除不掉怎么办)

  • card reader接在哪里(card.reader)

    card reader接在哪里(card.reader)

  • windows10截屏在哪里(windows10截屏在哪看)

    windows10截屏在哪里(windows10截屏在哪看)

  • 淘宝直播如何发红包(淘宝直播如何发图片给主播)

    淘宝直播如何发红包(淘宝直播如何发图片给主播)

  • 苹果xr是苹果几代(xr是苹果几代)

    苹果xr是苹果几代(xr是苹果几代)

  • 西瓜视频怎么提现(西瓜视频怎么提现到微信)

    西瓜视频怎么提现(西瓜视频怎么提现到微信)

  • Linux怎么查找影子文件并进入?(linux如何查找命令)

    Linux怎么查找影子文件并进入?(linux如何查找命令)

  • 清华同方笔记本电脑开机进入BIOS的几种方法(F2)附bios设置图文方法(清华同方笔记本怎么进入u盘启动)

    清华同方笔记本电脑开机进入BIOS的几种方法(F2)附bios设置图文方法(清华同方笔记本怎么进入u盘启动)

  • 大沙丘国家公园和保护区,美国科罗拉多州 (© Y Paudel/Getty Images)(大沙丘国家公园在哪里)

    大沙丘国家公园和保护区,美国科罗拉多州 (© Y Paudel/Getty Images)(大沙丘国家公园在哪里)

  • 微软 Win11 Build 22468预览版更新推送:修复 Wi-Fi、显示等多项 Bug(微软surface售后电话人工)

    微软 Win11 Build 22468预览版更新推送:修复 Wi-Fi、显示等多项 Bug(微软surface售后电话人工)

  • Python 基础(十二):字典(python基础100例)

    Python 基础(十二):字典(python基础100例)

  • 公司出售房产缴纳税金如何凭证
  • 手机上税票怎么开
  • 公司闲置资金理财做了三年定期存款
  • 增值税加计抵减最新政策2022
  • 出口退税业务提醒信息包括哪些
  • 卖自用轿车要缴什么税
  • 固定资产的折旧方法一经选定,不得随意变更
  • 应预缴的增值税
  • 退休回聘政策与程序
  • 固定资产税前一次性扣除政策中的扣除十点
  • 通讯费企业所得税计算
  • 个体工商户每月不超过10万免税
  • 小规模转为一般纳税人最新规定
  • 对公业务指什么
  • 所得税季报固定资产加速折旧表资产原值
  • etc发票一直不出来
  • 序列号不可用怎么办
  • 个体工商户生产经营所得税税率表2021
  • 追补确认年度是哪一年
  • 分公司给总公司管理费的会计分录
  • 河道管理费入什么科目
  • 个体户酒店服务业个税税率
  • 哪里查询发票是否抵扣
  • 样品送出,不收款怎么做账?
  • 公司账户替别人过账
  • 外账进销存单据是怎么弄的?
  • 暂估成本比实际高分录
  • 财政专项补助资金企业所得税申报
  • kali渗透工具安装
  • 外籍人员个人所得税政策2023规定
  • 增值税最高开票限额审批时限
  • 慕尼黑基姆湖
  • 分页limit
  • 基于51单片机的电子秤设计
  • 餐饮业采购管理
  • 停车费计税
  • 企业所得税季初和季末怎么算
  • 房地产预缴增值税计税依据
  • phpcms官网打不开
  • 长期借款的会计分录怎么写
  • sql2005安装步骤
  • 什么叫一般
  • 一般纳税人之外还有什么
  • 所得税费用是指
  • 增值税期末留抵退税原因采集确认单
  • 委外加工物资管理制度
  • 收到政府补助的会计分录
  • 转账支票记到哪个科目
  • 红冲暂估原材料如何做会计分录
  • 怎么理解核销
  • 退回的个税手续费如何账务处理
  • 工程款发票怎么做分录
  • 环保局检查锅炉房都查什么
  • 分支机构是否需要设立账簿
  • 企业财务建账应由谁负责
  • mysql存储引擎实现原理
  • 淘宝pc端打不开
  • macfic
  • ubuntul
  • docker1.12.6
  • 虚拟机怎么安装VMware Tools
  • xmp文件是干嘛用的
  • win7还原系统怎么还原
  • 高危KB3045645!Win7/8.1别安装这个补丁
  • linux自动化装机
  • mingw 编译
  • 使用jquery实现的项目
  • html中dt
  • 基于vue的购物系统
  • jquery mobile demo
  • javascript操作csv
  • [置顶]游戏名 TentacleLocker
  • Android IntentFilter 匹配原则浅析
  • amd模拟intel
  • 上海烟草集团董事长是谁
  • 运满满订单取消技术服务费退还吗
  • 江苏省社科院院士名单
  • 珠海市香洲区有火车站吗
  • 赞美税务局的话
  • 免责声明:网站部分图片文字素材来源于网络,如有侵权,请及时告知,我们会第一时间删除,谢谢! 邮箱:opceo@qq.com

    鄂ICP备2023003026号

    网站地图: 企业信息 工商信息 财税知识 网络常识 编程技术

    友情链接: 武汉网站建设