欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Vue3+TS實(shí)現(xiàn)數(shù)字滾動(dòng)效果CountTo組件

 更新時(shí)間:2022年11月16日 16:53:46   作者:涼城a  
最近開(kāi)發(fā)有個(gè)需求需要酷炫的文字滾動(dòng)效果,發(fā)現(xiàn)vue2版本的CountTo組件不適用與Vue3,沒(méi)有輪子咋辦,那咱造一個(gè)唄,感興趣的小伙伴可以跟隨小編一起了解一下

前言

最近開(kāi)發(fā)有個(gè)需求需要酷炫的文字滾動(dòng)效果,發(fā)現(xiàn)vue2版本的CountTo組件不適用與Vue3,沒(méi)有輪子咋辦,那咱造一個(gè)唄。其實(shí)大多數(shù)版本更替導(dǎo)致公共組件不可用,最簡(jiǎn)單的做法就是在原版本的基礎(chǔ)上進(jìn)行修改調(diào)整,總體來(lái)講花費(fèi)的時(shí)間成本以及精力成本最低。

思考

先看下效果,明確需求,然后開(kāi)始搬磚。

明確基礎(chǔ)功能

  • 有開(kāi)始值、結(jié)束值以及動(dòng)畫持續(xù)時(shí)間
  • 默認(rèn)分隔符、自動(dòng)播放

擴(kuò)展功能

  • 自動(dòng)播放可配置
  • 分隔符可自定義
  • 前、后綴
  • 動(dòng)畫配置項(xiàng)

實(shí)踐

定義參數(shù)

const props = {
  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
    }
  }
}

定義一個(gè)開(kāi)始函數(shù)

    // 定義一個(gè)計(jì)算屬性,當(dāng)開(kāi)始數(shù)字大于結(jié)束數(shù)字時(shí)返回true
    const stopCount = computed(() => {
      return props.start > props.end
    })
    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掛在完成后執(zhí)行一些操作
    onMounted(() => {
      if (props.autoPlay) {
        startCount()
      }
      emit('onMountedcallback')
    })
     // 組件銷毀時(shí)取消動(dòng)畫
    onUnmounted(() => {
      cancelAnimationFrame(state.rAF)
    })

核心方法

    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 {
        emit('callback')
      }
    }

配置項(xiàng)

屬性描述類型默認(rèn)值
startVal開(kāi)始值Number0
endVal結(jié)束值Number0
duration持續(xù)時(shí)間Number0
autoplay自動(dòng)播放Booleantrue
decimals要顯示的小數(shù)位數(shù)Number0
decimal十進(jìn)制分割String,
separator分隔符String,
prefix前綴String''
suffix后綴String''
useEasing使用緩和功能Booleantrue
easingFn緩和回調(diào)Function-

注:當(dāng)autoplay:true時(shí),它將在startVal或endVal更改時(shí)自動(dòng)啟動(dòng)

功能

函數(shù)名描述
mountedCallback掛載以后返回回調(diào)
start開(kāi)始計(jì)數(shù)
pause暫停計(jì)數(shù)
reset重置countTo

組件

組件同步在git組件庫(kù)了https://github.com/kinoaa/kinoaa-components/tree/main/countTo

import {
  defineComponent, reactive, computed, onMounted, watch, onUnmounted
} from 'vue'
const props = {
  start: {
    type: Number,
    required: false,
    default: 0
  },
  end: {
    type: Number,
    required: false,
    default: 2022
  },
  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
    }
  }
}
export default defineComponent({
  name: 'CountTo',
  props: props,
  emits: ['onMountedcallback', 'callback'],
  setup(props, {emit}) {
    const isNumber = (val) => {
      return !isNaN(parseFloat(val))
    }
    // 格式化數(shù)據(jù),返回想要展示的數(shù)據(jù)格式
    const formatNumber = (val) => {
      val = val.toFixed(props.start)
      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
    }
    const state = reactive<{
      localStart: number
      displayValue: number|string
      printVal: any
      paused: boolean
      localDuration: any
      startTime: any
      timestamp: any
      remaining: any
      rAF: any
    }>({
      localStart: props.start,
      displayValue: formatNumber(props.start),
      printVal: null,
      paused: false,
      localDuration: props.duration,
      startTime: null,
      timestamp: null,
      remaining: null,
      rAF: null
    })
    // 定義一個(gè)計(jì)算屬性,當(dāng)開(kāi)始數(shù)字大于結(jié)束數(shù)字時(shí)返回true
    const stopCount = computed(() => {
      return props.start > props.end
    })
    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掛在完成后執(zhí)行一些操作
    onMounted(() => {
      if (props.autoPlay) {
        startCount()
      }
      emit('onMountedcallback')
    })
    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 {
        emit('callback')
      }
    }
    // 組件銷毀時(shí)取消動(dòng)畫
    onUnmounted(() => {
      cancelAnimationFrame(state.rAF)
    })
    return () => (
      state.displayValue
    )
  }
})

到此這篇關(guān)于Vue3+TS實(shí)現(xiàn)數(shù)字滾動(dòng)效果CountTo組件的文章就介紹到這了,更多相關(guān)Vue3數(shù)字滾動(dòng)效果內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • vue 項(xiàng)目打包時(shí)樣式及背景圖片路徑找不到的解決方式

    vue 項(xiàng)目打包時(shí)樣式及背景圖片路徑找不到的解決方式

    今天小編就為大家分享一篇vue 項(xiàng)目打包時(shí)樣式及背景圖片路徑找不到的解決方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2019-11-11
  • 基于Vue.js+Nuxt開(kāi)發(fā)自定義彈出層組件

    基于Vue.js+Nuxt開(kāi)發(fā)自定義彈出層組件

    這篇文章主要介紹了基于Vue.js+Nuxt開(kāi)發(fā)自定義彈出層組件,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-10-10
  • 淺談Vue3.0新版API之composition-api入坑指南

    淺談Vue3.0新版API之composition-api入坑指南

    這篇文章主要介紹了Vue3.0新版API之composition-api入坑指南,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-04-04
  • 基于Vuex無(wú)法觀察到值變化的解決方法

    基于Vuex無(wú)法觀察到值變化的解決方法

    下面小編就為大家分享一篇基于Vuex無(wú)法觀察到值變化的解決方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2018-03-03
  • iView-admin 動(dòng)態(tài)路由問(wèn)題的解決方法

    iView-admin 動(dòng)態(tài)路由問(wèn)題的解決方法

    這篇文章主要介紹了iView-admin 動(dòng)態(tài)路由問(wèn)題的解決方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2018-10-10
  • vue2和elementUI?實(shí)現(xiàn)落日余暉登錄頁(yè)和滑塊校驗(yàn)功能

    vue2和elementUI?實(shí)現(xiàn)落日余暉登錄頁(yè)和滑塊校驗(yàn)功能

    這篇文章主要介紹了vue2和elementUI打造落日余暉登錄頁(yè)和滑塊校驗(yàn),本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),需要的朋友可以參考下
    2023-06-06
  • Vue3框架使用報(bào)錯(cuò)以及解決方案

    Vue3框架使用報(bào)錯(cuò)以及解決方案

    這篇文章主要介紹了Vue3框架使用報(bào)錯(cuò)以及解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-10-10
  • vue結(jié)合echarts繪制一個(gè)支持切換的折線圖實(shí)例

    vue結(jié)合echarts繪制一個(gè)支持切換的折線圖實(shí)例

    這篇文章主要介紹了vue結(jié)合echarts繪制一個(gè)支持切換的折線圖實(shí)例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-10-10
  • vue移動(dòng)端使用canvas簽名的實(shí)現(xiàn)

    vue移動(dòng)端使用canvas簽名的實(shí)現(xiàn)

    這篇文章主要介紹了vue移動(dòng)端使用canvas簽名的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-01-01
  • Vue?數(shù)據(jù)綁定事件綁定樣式綁定語(yǔ)法示例

    Vue?數(shù)據(jù)綁定事件綁定樣式綁定語(yǔ)法示例

    這篇文章主要為大家介紹了Vue?數(shù)據(jù)綁定事件綁定樣式綁定語(yǔ)法示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-07-07

最新評(píng)論