数据可视化大屏开发的过程中,需要实现一种滚动数字的效果。
实现代码示例如下:
<template>
<span>
{{ value }}
</span>
</template>
<script>
export default {
props: {
startVal: {
type: Number,
default: 0,
},
endVal: {
type: Number,
default: 9999,
},
duration: {
type: Number,
default: 1000,
},
autoplay: {
type: Boolean,
default: true,
},
decimals: {
type: Number,
default: 0,
},
},
data() {
return {
localStartVal: 0,
startTime: null,
timestamp: null,
ret: null,
printVal: 0,
value: 0,
};
},
mounted() {
this.start();
},
methods: {
count(timestamp) {
if (!this.startTime) this.startTime = timestamp;
this.timestamp = timestamp;
const progress = timestamp - this.startTime;
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.value = this.printVal.toFixed(this.decimals);
if (progress < this.localDuration) {
this.ret = requestAnimationFrame(this.count);
} else {
// this.$emit('callback');
return;
}
},
start() {
this.localStartVal = this.startVal;
this.startTime = null;
this.localDuration = this.duration;
this.paused = false;
this.ret = requestAnimationFrame(this.count);
},
},
computed: {
countDown() {
return this.startVal > this.endVal;
},
},
watch: {
startVal() {
if (this.autoplay) {
this.start();
}
},
endVal() {
if (this.autoplay) {
this.start();
}
},
},
};
</script>
属性 | 描述 | 类型 | 默认值 |
---|---|---|---|
startVal | 开始值 | Number | 0 |
endVal | 结束值 | Number | 9999 |
duration | 动画时长 | Number | 1000 |
autoplay | 是否自动开启动画 | Boolean | true |
decimals | 展示小数点后的个数 | Number | 0 |
requestAnimationFrame
是浏览器用于定时循环操作的一个接口,类似于setTimeout,主要用途是按帧对网页进行重绘。 requestAnimationFrame的优势,在于充分利用显示器的刷新机制,比较节省系统资源。显示器有固定的刷新频率(60Hz或75Hz),也就是说,每秒最多只能重绘60次或75次,requestAnimationFrame的基本思想就是与这个刷新频率保持同步,利用这个刷新频率进行页面重绘。此外,使用这个API,一旦页面不处于浏览器的当前标签,就会自动停止刷新。这就节省了CPU、GPU和电力。
requestAnimationFrame使用一个回调函数作为参数。这个回调函数会在浏览器重绘之前调用。
各个支持requestAnimationFrame的浏览器有些还是自己的私有实现,以及不支持requestAnimationFrame的浏览器需要做兼容
解决兼容性问题
let lastTime = 0
const prefixes = 'webkit moz ms o'.split(' ') // 各浏览器前缀
let requestAnimationFrame
let 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 }
vue-count-to
vue-count-to是一个没有依赖的轻量级vue组件,可以自行覆盖EasingFn。 可以设置 startVal 和 endVal,它会自动判断计数进行数字渲染。
附上地址www.npmjs.com/package/vue…