使用
html
<Incremental :startVal="0" :endVal="1000" :duration="500" />js:
import Incremental from '@/utils/num/numView'```
js
let lastTime = 0
const prefixes = 'webkit moz ms o'.split(' ') // 各浏览器前缀let requestAnimationFrame
let cancelAnimationFrameconst isServer = typeof window === 'undefined'
if (isServer) {requestAnimationFrame = function () {}cancelAnimationFrame = function () {}
} else {requestAnimationFrame = window.requestAnimationFramecancelAnimationFrame = window.cancelAnimationFramelet 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,则会退到setTimeoutif (!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 + timeToCallcallback(time)}, timeToCall)lastTime = currTime + timeToCallreturn id}cancelAnimationFrame = function (id) {window.clearTimeout(id)}}
}export { requestAnimationFrame, cancelAnimationFrame }
封装vue模块 (需要时倒入)
<template><span>{{ displayValue }}</span>
</template>
<script>
import { requestAnimationFrame, cancelAnimationFrame } from './num.js'
export default {props: {startVal: {type: Number,required: false,default: 0},endVal: {type: Number,required: false,default: 2017},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.startValthis.startTime = nullthis.localDuration = this.durationthis.paused = falsethis.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 = nullthis.localDuration = +this.remainingthis.localStartVal = +this.printValrequestAnimationFrame(this.count)},reset() {this.startTime = nullcancelAnimationFrame(this.rAF)this.displayValue = this.formatNumber(this.startVal)},count(timestamp) {if (!this.startTime) this.startTime = timestampthis.timestamp = timestampconst progress = timestamp - this.startTimethis.remaining = this.localDuration - progressif (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>