最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

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

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

前言

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

思考

先看下效果,明確需求,然后開始搬磚。

明確基礎(chǔ)功能

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

擴(kuò)展功能

  • 自動播放可配置
  • 分隔符可自定義
  • 前、后綴
  • 動畫配置項(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è)開始函數(shù)

    // 定義一個(gè)計(jì)算屬性,當(dāng)開始數(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í)取消動畫
    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開始值Number0
endVal結(jié)束值Number0
duration持續(xù)時(shí)間Number0
autoplay自動播放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í)自動啟動

功能

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

組件

組件同步在git組件庫了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)開始數(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í)取消動畫
    onUnmounted(() => {
      cancelAnimationFrame(state.rAF)
    })
    return () => (
      state.displayValue
    )
  }
})

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

相關(guān)文章

  • Vue下載不同文件的幾種方式總結(jié)

    Vue下載不同文件的幾種方式總結(jié)

    在Vue項(xiàng)目中實(shí)現(xiàn)文件下載有多種方式,包括使用window.open、<a>標(biāo)簽、axios、FetchAPI、自定義$download方法以及創(chuàng)建a標(biāo)簽等,每種方法都有其適用場景,開發(fā)者可以根據(jù)項(xiàng)目需求選擇最合適的方式
    2025-01-01
  • Vue+vant實(shí)現(xiàn)圖片上傳添加水印

    Vue+vant實(shí)現(xiàn)圖片上傳添加水印

    這篇文章主要為大家詳細(xì)介紹了Vue+vant實(shí)現(xiàn)圖片上傳添加水印功能,文中的示例代碼簡潔易懂,具有一定的借鑒價(jià)值,感興趣的小伙伴可以了解下
    2025-02-02
  • Vue自定義部分頁面顯示導(dǎo)航欄功能

    Vue自定義部分頁面顯示導(dǎo)航欄功能

    這篇文章主要介紹了Vue自定義部分頁面顯示導(dǎo)航欄,在設(shè)計(jì)導(dǎo)航欄的時(shí)候,考慮到登錄之前不能瀏覽該網(wǎng)站,所以需要在登錄頁和注冊頁不能出現(xiàn)導(dǎo)航欄,登錄后的頁面才能出現(xiàn)導(dǎo)航欄,本文給大家解決這個(gè)問題,感興趣的朋友跟隨小編一起看看吧
    2022-10-10
  • vue實(shí)現(xiàn)自定義顏色選擇器

    vue實(shí)現(xiàn)自定義顏色選擇器

    這篇文章主要為大家詳細(xì)介紹了如何使用vue實(shí)現(xiàn)一個(gè)自定義顏色選擇器,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下
    2025-04-04
  • vue.js中實(shí)現(xiàn)登錄控制的方法示例

    vue.js中實(shí)現(xiàn)登錄控制的方法示例

    這篇文章主要介紹了vue.js中實(shí)現(xiàn)登錄控制的方法,結(jié)合實(shí)例形式分析 vue.js操作登陸頁面流程控制相關(guān)實(shí)現(xiàn)技巧,需要的朋友可以參考下
    2018-04-04
  • Vue?中駝峰命名與短橫線分割命名的用法及區(qū)別

    Vue?中駝峰命名與短橫線分割命名的用法及區(qū)別

    在?Vue?中,命名規(guī)范是一個(gè)非常重要的話題,駝峰命名和短橫線分割命名都有其各自的優(yōu)缺點(diǎn)和適用場景,開發(fā)者需要根據(jù)實(shí)際情況進(jìn)行選擇,這篇文章主要介紹了Vue?中駝峰命名與短橫線分割命名作用及區(qū)別介紹,需要的朋友可以參考下
    2023-05-05
  • vue改變循環(huán)遍歷后的數(shù)據(jù)實(shí)例

    vue改變循環(huán)遍歷后的數(shù)據(jù)實(shí)例

    今天小編就為大家分享一篇vue改變循環(huán)遍歷后的數(shù)據(jù)實(shí)例,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2019-11-11
  • vue3 可拖動的左右面板分割組件實(shí)現(xiàn)

    vue3 可拖動的左右面板分割組件實(shí)現(xiàn)

    最近在使用vue的時(shí)候,遇到一個(gè)需求,實(shí)現(xiàn)左右div可通過中間部分拖拽調(diào)整寬度,本文就整理一下,分享給大家,有興趣的可以學(xué)習(xí)
    2021-06-06
  • vue中axios解決跨域問題和攔截器的使用方法

    vue中axios解決跨域問題和攔截器的使用方法

    下面小編就為大家分享一篇vue中axios解決跨域問題和攔截器的使用方法,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2018-03-03
  • Vue表單之v-model綁定下拉列表功能

    Vue表單之v-model綁定下拉列表功能

    這篇文章主要介紹了Vue表單之v-model綁定下拉列表功能,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2019-05-05

最新評論

永登县| 木里| 无极县| 师宗县| 滨州市| 嵊州市| 张家界市| 永寿县| 乐山市| 南开区| 双辽市| 延川县| 桐柏县| 华容县| 汕头市| 毕节市| 岱山县| 台中市| 鱼台县| 竹北市| 调兵山市| 博客| 鹤峰县| 芮城县| 桦南县| 富顺县| 峨边| 油尖旺区| 远安县| 蓬溪县| 渭源县| 墨玉县| 二连浩特市| 云阳县| 盐津县| 郧西县| 孝义市| 香河县| 永寿县| 辉县市| 沂南县|