1. 程式人生 > 程式設計 >vue3使用vue-count-to元件的實現

vue3使用vue-count-to元件的實現

專案場景:

資料視覺化大屏開發的過程中,需要實現一種滾動數字的效果,在使用vue2時,使用vue-count-to完全沒有問題,功能也比較完善(滾動時長,開始值,結束值,字首,字尾,千分隔符,小數分隔符等等),但是在vue3中使用會出現問題。

<template>
 <div id="nav">
 <router-link to="/">Home</router-link> |
 <router-link to="/about">About</router-link>
 </div>
 <count-to :startVal="0" :endVal="2045" :duration="4000"></count-to>
 <router-view/>
</template>

展示的效果

在這裡插入圖片描述

問題描述:

出現的錯誤時 == Cannot read property ‘_c' of undefined== 這是一個_c的屬性沒有找到,具體的情況也不是很清楚。在vue-count-to打包後的原始碼中可以大致看出來,這是在render函式中出現的錯誤。但是還是沒法下手。

在這裡插入圖片描述

解決方案:

採用的方法是直接複製node_modules下vue-count-to的原始檔(src下),到自己專案的components下。如圖

在這裡插入圖片描述

然後根據eslint的檢查,修改程式碼,直到不報錯,且記刪除package.json下剛剛引入的vue-count-to的依賴。如圖

在這裡插入圖片描述

最後重啟專案。

vue-count-to原始碼

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 }
<template>
 <span>
 {{displayValue}}
 </span>
</template>
<script>
import { requestAnimationFrame,cancelAnimationFrame } from './requestAnimationFrame.js'
export default {
 props: {
 startVal: {
 type: Number,required: false,default: 0
 },endVal: {
 type: Number,default: 2017
 },duration: {
 type: Number,default: 3000
 },autoplay: {
 type: Boolean,default: true
 },decimals: {
 type: Number,default: 0,validator (value) {
 return value >= 0
 }
 },decimal: {
 type: String,default: '.'
 },separator: {
 type: String,default: ','
 },prefix: {
 type: String,default: ''
 },suffix: {
 type: String,useEasing: {
 type: Boolean,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,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>

到此這篇關於vue3使用vue-count-to元件的文章就介紹到這了,更多相關vue3 vue-count-to元件內容請搜尋我們以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援我們!