QQ登录

只需要一步,快速开始

 注册地址  找回密码
查看: 3915|回复: 0
打印 上一主题 下一主题

[其他资源] vue3 | 数据可视化实现数字滚动特效

[复制链接]
字体大小: 正常 放大
杨利霞        

5273

主题

82

听众

17万

积分

  • TA的每日心情
    开心
    2021-8-11 17:59
  • 签到天数: 17 天

    [LV.4]偶尔看看III

    网络挑战赛参赛者

    网络挑战赛参赛者

    自我介绍
    本人女,毕业于内蒙古科技大学,担任文职专业,毕业专业英语。

    群组2018美赛大象算法课程

    群组2018美赛护航培训课程

    群组2019年 数学中国站长建

    群组2019年数据分析师课程

    群组2018年大象老师国赛优

    跳转到指定楼层
    1#
    发表于 2022-9-14 17:02 |只看该作者 |正序浏览
    |招呼Ta 关注Ta
    vue3 | 数据可视化实现数字滚动特效0 _* h. S( j: T- o6 k" h& m. ^) W
    " T4 T# f, L" ]$ l" m
    前言
    ' q7 b1 l% g) h, t$ z* @- Cvue3不支持vue-count-to插件,无法使用vue-count-to实现数字动效,数字自动分割,vue-count-to主要针对vue2使用,vue3按照会报错:
    8 N; m( D3 r( L( y  ?0 c: rTypeError: Cannot read properties of undefined (reading '_c')- k) D! W0 m! F' I
    的错误信息。这个时候我们只能自己封装一个CountTo组件实现数字动效。先来看效果图:3 ?" J9 R' h) h, ?, d
    ( |7 A5 W, S0 T9 G: c
      X2 F, W- A3 j5 l! p& d' V
    思路
    ) O. R" a! r1 }7 O& |使用Vue.component定义公共组件,使用window.requestAnimationFrame(首选,次选setTimeout)来循环数字动画,window.cancelAnimationFrame取消数字动画效果,封装一个requestAnimationFrame.js公共文件,CountTo.vue组件,入口导出文件index.js。
    $ G! o, e; Y  f2 A
    ) [* J  y3 u8 m; R4 o# s2 P; t文件目录
    5 n$ g/ p$ t; x0 |
    # m) n8 b& s$ C4 X6 F* y  X2 e' C6 F* H& K* l
    使用示例
    " N1 U8 U, Q+ m4 A; Z* b7 R* L<CountTo
    8 X- k$ Y1 f0 B* J9 y2 ]; e :start="0" // 从数字多少开始
    3 E" v! |0 _! t! J* q* _; O :end="endCount" // 到数字多少结束! G4 W0 Y5 X$ P- X
    :autoPlay="true" // 自动播放6 P2 G! n' W9 y6 w2 \6 Q* T* x
    :duration="3000" // 过渡时间- \& X/ F& d' F+ Y8 ?, u
    prefix="¥"   // 前缀符号
    0 I2 d" j" f) u- d  A/ } suffix="rmb" // 后缀符号+ W- J2 I5 }7 B
    />1 k# _$ K/ C# {8 n5 j* H
    1
    & a* m' t4 J, r. Z' b1 n' h7 u2 K2) V) t8 c  O8 G( l
    32 G8 ^# d( a& X
    4
    $ F6 f+ V* D7 p+ l6 E4 q5 y/ [5
    $ [) u. J9 w1 l6/ @! a" |+ o; @# v& n0 g2 p) `
    7
    * G9 b9 v, ~1 u% `4 M2 |8
    7 t& V. `! c% }6 W; G9 d; r7 A入口文件index.js6 C% V1 ^; V# B: R# A: Z! A

    ) j& s+ h. @" B& `( U6 Mconst UILib = {) u4 c4 Z' i. i5 f3 S6 C- o
      install(Vue) {/ J5 y) ^6 |+ T; Q/ n/ G, c
        Vue.component('CountTo', CountTo)2 E# e; E! M2 @0 p* G0 @4 H
      }! o5 s! h* u/ O; W7 t: G; k
    }1 z) u( i+ g+ p* ?' L0 O: O

      M/ |1 T' {) S7 x) k/ Aexport default UILib
    # a- P1 U9 G  h/ i' W
    8 {5 X9 e0 M9 {$ q0 e1
    8 |& E( w. x1 C29 ~% Z3 T0 E" h
    3
    $ u( \2 ]* o2 e" Z& W. Q1 A' }/ @4
    8 g0 n5 F* z% X) A2 R/ y58 D9 f1 j- ]7 {, }6 s' \
    6
      k: F5 v0 n  c; M, h( s/ }4 h0 p71 x& p+ ~$ {$ I2 r& g# r+ x
    8
    % n4 l( O/ l9 r$ u6 x: N5 v9; M4 T/ i% J) H' S; n# ?
    main.js使用
    5 D: ^9 H$ q) ~3 L7 F) \6 b$ Q6 f% \import CountTo from './components/count-to/index';
    6 @8 J7 l  O7 A5 d* @0 C! Oapp.use(CountTo)
    7 }" _" D% E" n0 `+ |2 ?0 p1
    . v! p6 e" ]" S2
    9 g8 u! `. e) m- @requestAnimationFrame.js思路
    ) \4 l+ A  v2 ~$ o8 S先判断是不是浏览器还是其他环境
    ! h3 u& s+ k& H) a5 K  j" Y% L# N如果是浏览器判断浏览器内核类型; G& C) J# X6 P7 N! C
    如果浏览器不支持requestAnimationFrame,cancelAnimationFrame方法,改写setTimeout定时器
    ' Y; `+ i- E3 m导出两个方法 requestAnimationFrame, cancelAnimationFrame" n6 W6 N4 E0 D$ c  f) D
    各个浏览器前缀:let prefixes =  'webkit moz ms o';2 [, g( u; [% Z& g5 C- S0 n. x
    判断是不是浏览器:let isServe = typeof window == 'undefined';4 ^8 `* _0 Y0 p! _3 c' O
    增加各个浏览器前缀:  
      @" m& Q0 u5 O, l& {" Vlet prefix;
    0 A* n* |5 `7 S  U& U/ G, Slet requestAnimationFrame;/ N* D3 i# `# S; y9 @+ k6 N8 s
    let cancelAnimationFrame;
    1 a# C. b" q; I; q* q( {  u// 通过遍历各浏览器前缀,来得到requestAnimationFrame和cancelAnimationFrame在当前浏览器的实现形式9 S# O; Y% w0 q4 P* ?- b7 I
        for (let i = 0; i < prefixes.length; i++) {
    0 o1 S4 x' x* s4 Y; x7 r) u        if (requestAnimationFrame && cancelAnimationFrame) { break }
      c( j* U) j6 M3 r1 t% U  p* I        prefix = prefixes2 z; u, I# C4 n& k# R, P
            requestAnimationFrame = requestAnimationFrame || window[prefix + 'RequestAnimationFrame']1 G3 @; L) n+ d; {# g
            cancelAnimationFrame = cancelAnimationFrame || window[prefix + 'CancelAnimationFrame'] || window[prefix + 'CancelRequestAnimationFrame']
    + t# B% Y4 O) Z    }1 q5 y6 D9 g0 K6 J# G- K+ k

    8 _0 f4 H7 y7 |' d+ L! E  //不支持使用setTimeout方式替换:模拟60帧的效果
    8 x1 S8 g1 X1 q. J+ y2 ?- P- R2 G  // 如果当前浏览器不支持requestAnimationFrame和cancelAnimationFrame,则会退到setTimeout
    ! W! `' o  L( X% m    if (!requestAnimationFrame || !cancelAnimationFrame) {
    2 n: ~) o7 W, C9 R! n: T3 z8 l- j  D        requestAnimationFrame = function (callback) {
    0 j& q% ?: T( C  i9 r            const currTime = new Date().getTime()  w* Y, k- o- N
                // 为了使setTimteout的尽可能的接近每秒60帧的效果
    ( k: |+ g! V2 y& c            const timeToCall = Math.max(0, 16 - (currTime - lastTime))) o5 p" R  C- b2 k( K
                const id = window.setTimeout(() => {
    - r' B$ ^( ]- [" j' G2 b9 ?                callback(currTime + timeToCall)
    " e& L6 ?9 k" O# r6 y1 ]' R0 f# u2 k. y            }, timeToCall)  F* d( L1 M( r
                lastTime = currTime + timeToCall
    ' H5 h* s$ u" q            return id8 \* N; v) [3 Y* a9 G
            }3 ~5 G6 n+ D/ ]( K+ j' i, k: I
    9 p, C/ s) a8 j7 S
            cancelAnimationFrame = function (id) {
    ! _+ V0 j7 A  {, ~4 l5 a8 Y/ `            window.clearTimeout(id)
    2 v. b  E9 Z: a        }+ S: g; i, o# h
        }
    / T8 j8 I6 w  c9 S( E5 @2 T1 p; j
    , D7 q. v, X8 f1! Q3 d5 D% Y% w" c- j
    2, p3 d- W9 m1 [/ [$ S; s: q
    3
    ' k6 i3 \# L1 O$ _' O: K* q) J4
    " G# ]/ ^9 x( O7 V5+ s4 v" ^; E+ o1 F6 o# c, C
    6
    ( N4 c$ q& [: b: Q  v3 F( _4 S# E72 _5 ]$ O. L# q1 Q
    8
    : \# C, O: z4 L3 b9# n4 B. `5 c! o% k
    10
    - G0 G7 ^0 O; l; l: D2 q4 Z/ f0 {11
    1 T9 e2 s5 f; O/ m7 D12
    2 s4 R( g7 i" c* z" i13
    2 T: X- Q9 I8 C2 _' L& M; J14
    7 s1 d* f' X" f3 C# D/ u15
    " O- I( u/ w$ U/ A+ g16  f2 Y! {( w) r+ F7 v( I
    17
    % T2 F+ t8 V9 z9 |$ a% v* ?/ R18
    ' I  A1 _- N; ^9 Y4 C19* F9 B7 f' y9 O3 U+ u' A
    203 |; @- _# x- `1 i4 ]" W8 f
    21
    ( J1 _7 N9 F# m222 ~9 W" \- k, `# ]1 C( z5 ^
    235 N' V* G$ X+ |( n- ~/ Z
    24
    5 U6 P/ M% Y- g; N25( m9 r' ]0 |4 v$ ?+ w) w& s, u
    26, e( E7 k* D2 w/ ^8 ~, ~# d, w3 k7 j
    27
    - H: X, q, I9 w285 z7 T' w9 e7 s2 \( p4 b4 F
    296 x/ `# t. B( b* g1 u6 A
    309 ~3 V; |, K; N5 }6 @0 v3 M2 d# l
    31, }% x& O) `% Z$ h. C+ l. [3 {
    32
    8 I! S) X2 [# U' h6 O8 a完整代码:  s9 N- l3 I+ F# T* f  B& X* Q& g
    requestAnimationFrame.js
    ! @" s1 P: m" D3 s, X: i5 N. W  \1 \8 P8 @* j
    let lastTime = 0; z0 ?" O# k& O# J" b9 h
    const prefixes = 'webkit moz ms o'.split(' ') // 各浏览器前缀( y4 O+ C8 h& l/ l3 D" H

    / {5 `3 U- l5 i: m/ p* D3 Xlet requestAnimationFrame4 ?1 {6 T- G+ p5 Z: x0 N; e! K0 y
    let cancelAnimationFrame% N/ J. C) V# x5 A3 E" |5 s
    8 i; Z5 q$ U0 W2 e  w- R: C
    // 判断是否是服务器环境
    " ?) c- q. w& w) \const isServer = typeof window === 'undefined'
    7 N* l- o* m: X: Y9 o8 q8 h/ Jif (isServer) {+ j) ~8 A( A% q7 S2 u! b4 ~
        requestAnimationFrame = function () {" n2 X* M+ r3 M" v; D( L
            return
    2 P6 `: \$ N9 P/ w    }" e# w, g% S. z. e- v
        cancelAnimationFrame = function () {
    ) e: }' G2 _; D4 p8 m7 W& D. K        return4 i1 M/ I& ]; c. G9 ?5 `
        }2 X8 Y. c/ v% X; k5 f5 r1 d
    } else {
    7 c' L7 l% e: @8 h/ f    requestAnimationFrame = window.requestAnimationFrame: D; _9 x; T7 a6 V9 ]0 V+ D# h
        cancelAnimationFrame = window.cancelAnimationFrame
    1 j& h% ~* K' G( }7 h2 U    let prefix2 s& ~" X$ G5 u, k
        // 通过遍历各浏览器前缀,来得到requestAnimationFrame和cancelAnimationFrame在当前浏览器的实现形式
    + l6 @8 u* |4 L* \: r" `    for (let i = 0; i < prefixes.length; i++) {+ `' \* X- `' m0 x, f! u' C' H  X
            if (requestAnimationFrame && cancelAnimationFrame) { break }# G: d( ~/ k* S0 a
            prefix = prefixes* b9 S" |) Q% s" c; L
            requestAnimationFrame = requestAnimationFrame || window[prefix + 'RequestAnimationFrame']# p7 P* _! H; S& t! B5 k
            cancelAnimationFrame = cancelAnimationFrame || window[prefix + 'CancelAnimationFrame'] || window[prefix + 'CancelRequestAnimationFrame']( p7 U$ g7 V5 H; k6 s. P3 k" Q# _
        }6 P/ O1 a$ w/ t
    * r. S7 Z4 c9 w! ~/ Q1 K' `
        // 如果当前浏览器不支持requestAnimationFrame和cancelAnimationFrame,则会退到setTimeout
    0 h* @% U4 e$ ~! ?9 R    if (!requestAnimationFrame || !cancelAnimationFrame) {
    ( O" P1 O2 F* I% F        requestAnimationFrame = function (callback) {
    2 J; n$ i7 U% R! s            const currTime = new Date().getTime()# K  {! `2 w. c( U3 q6 T
                // 为了使setTimteout的尽可能的接近每秒60帧的效果
    ! T4 f6 A* R* |3 ]: w$ Q; d: J            const timeToCall = Math.max(0, 16 - (currTime - lastTime))
    & @4 _( c2 t# D* d            const id = window.setTimeout(() => {+ @$ J5 K2 G/ u( n) i" N% p4 F+ u
                    callback(currTime + timeToCall)7 Y$ g& t7 y) w6 {" I
                }, timeToCall)
    , }' S4 {  @4 m7 n8 r$ n            lastTime = currTime + timeToCall
    ( q  \9 h+ R% E/ ?- k7 u- X            return id" G6 Q' ~3 K0 e5 s/ @7 @
            }
    8 f. f# E  M7 o3 C6 J) e2 g' ], p9 C, M) O& A# E% q4 L% W
            cancelAnimationFrame = function (id) {
    - N% V; f! h* ?            window.clearTimeout(id)5 ]7 F% g2 K$ C( L$ [4 L
            }
    ) ?! ]: K+ r. X; @# a, h    }
    * g% Q8 y  G7 x1 h}" _6 p1 v1 a6 `; n

    6 L+ Z/ I  H8 O! w$ |9 ~export { requestAnimationFrame, cancelAnimationFrame }
    . N) O6 p/ ?' m. E% G; B9 t$ N) b* w2 p
    0 F5 G- s( u* J' ^
    1; C! g' b% _/ j. a) M
    2
    ; @% D& m( {9 f. f+ v0 E7 w3- V0 n! e9 I" [; |: S
    4
    9 ~1 F+ Y7 F+ ^' N4 B% }52 g1 ^; ?3 u% C% ]& d$ t2 @3 u
    6
    # a) X4 Y) k" u. g. \; P77 G+ R1 c) ^  j) Z) c
    8$ |& `. f6 ?& }
    95 d/ V) }; k; V( n5 t
    10' T) l! O& O  U3 c) b1 U9 k9 h' O
    11! `2 M8 Z8 @3 D# `" \
    128 t. P6 n/ Y6 a2 z# |( y- m( n
    136 m. A% i7 B/ G* [/ M2 l
    14
    # G. g/ C3 y! d9 X5 m, }3 H) m) a15
    - ^! F1 M. I  S  {0 n16# ~, J- k4 x8 w$ w7 X% O) x7 M
    17' b! F& K' R" V* U
    18
    " J: _$ \" u& D/ Q& `) W19
    1 U3 R% O1 ~% z0 F/ \( _20
    % {0 G' i' S9 W0 e* ~. ^$ O21
    & @3 k8 M' V! Y0 q225 H# K1 ^3 a7 }3 ~% T
    232 q2 j& r7 S% j! P/ P8 Q6 m
    24
    0 Y; m1 ^* I* O7 @2 \6 ^252 j& D: Q: U) V( e
    260 C, z) M- N( @7 K& Q8 O8 o" l: f
    27. {0 U8 W7 T# }0 L& c- P) p: Z
    287 ^  ]) p, V2 U4 E. s4 C
    29. E0 X; ~+ q  I% {
    30% }( ^! _6 }$ @( A
    31
    & J' W4 \3 o6 R7 ?# r$ z32
    * e4 T, B+ L4 L# a8 d) V- h, j1 m& N33
    ; Y6 f' u! \. S346 j0 n* ]0 m  m4 U. }
    35
    & i" r8 X1 f4 a, V36" a! K7 F8 k0 ?
    37. p$ h4 z, L! q4 j9 T+ n
    386 D/ a& |0 B! F% ~" Y, R5 W
    39
    5 U- o0 F) g5 [( ~40! b/ W# z8 i. W
    412 Y! C; g$ X. U2 S
    426 L% E0 A( z3 ~
    43: q+ ?1 w6 D* J3 T/ _
    44
    , g8 ^0 S, L! V) R( Z45, M- i. V( C% X) ^2 S
    46' n  ^1 x8 w& g: W& B3 ?2 c; i
    47
    7 H! L: c9 ~) Z6 q8 Z1 H2 K2 n3 |482 m+ e% I5 o$ s% _) t% E
    CountTo.vue组件思路
    6 Y( u6 B# k0 B. `% p1 T首先引入requestAnimationFrame.js,使用requestAnimationFrame方法接受count函数,还需要格式化数字,进行正则表达式转换,返回我们想要的数据格式。$ ?5 H0 u6 |" N

    % ?2 Y* n+ X/ e2 J9 A% C引入 import { requestAnimationFrame, cancelAnimationFrame } from './requestAnimationFrame.js'" V4 q2 t' l+ m3 L- j* n
    1
    % _2 E' y9 }: v8 g- s# {. X需要接受的参数:
    1 I8 c# K; I( }; |
    ; d( |" F3 W$ }$ [const props = defineProps({
    * f/ d6 E6 h5 j% ~8 N  start: {
    + W0 |% F2 c8 L& Z    type: Number,) _. J* F1 ?: o
        required: false,
    $ k; C. c& W( S" Y    default: 0
    " r, \6 k7 T( L2 U  },; \7 G9 t3 ~% h/ g6 c$ E$ I
      end: {/ n/ W! I% Q. _+ Z; d1 v) a
        type: Number,
    2 S% ^8 Q% z( R    required: false,, g7 `: w9 X3 z8 W
        default: 0& D3 G# r9 S; U7 k; |: A
      },
    1 y/ ^6 z; B" @0 D2 e! ^1 Z  duration: {
    4 I+ R6 R% W9 k4 Q$ A8 d    type: Number,
    ; h6 b1 b; T2 y+ z2 {. Z3 ~& e8 A    required: false,9 _  _$ D# C: J
        default: 5000" m" ~3 S+ P9 R4 E- n
      },
    " x( D1 Q8 e3 ~  autoPlay: {) b# r* Y2 c! J* ~# w: \
        type: Boolean,
    $ o1 |/ Z# P  N% L9 B9 ?8 f; |% u    required: false,
    3 ^7 J" X2 c- j    default: true
    8 A5 U4 K2 W1 J; m  },: A0 k% m. M, A$ _
      decimals: {) r+ @6 }/ \; v
        type: Number,
    ) |9 d/ d/ |$ I8 E    required: false,( ?( b/ E) j5 r0 z- i- _, r
        default: 0,6 y+ P* x5 T3 Z9 ~: \# ^8 O: O
        validator (value) {! D0 d1 p& i; n6 Y/ H
          return value >= 0
    4 l& ~- W5 v8 ?( H    }
    / ^. M5 x& _! t  },
    / {& [" ]' d) ?9 Z2 N: G$ A& y  decimal: {( w3 }7 a! F& v9 c
        type: String,, z! _1 e% |3 M% |2 f2 s3 r% B
        required: false," u5 H6 {5 k+ T! s# o
        default: '.'! Q7 F# v0 s  B1 ]5 v
      },
      C, O2 Y& {8 y& D$ M; d  separator: {
    4 H) v  E% t( `, o    type: String,4 V2 _' {. x* o3 y4 @
        required: false,4 f& n- v( k$ w8 W5 F" V$ X3 y) D
        default: ','+ h6 f7 x; [4 W$ w$ q$ Q
      },
    + y( n5 @/ R8 Q/ t  prefix: {! T; {5 [0 R2 e9 L( o" z
        type: String,, R6 V3 f4 S+ d4 E7 v
        required: false,1 m% t- d/ H7 p+ {* A7 s% r
        default: ''  z! ?! f5 ^5 h# A2 T* U# E* Y* _
      },
    % b% N& Q/ {/ U! s4 C  suffix: {
    + b  `0 W& x( s7 L, o3 L7 _( w    type: String,
    % O( ]7 Q4 {0 C2 T7 L    required: false,
    - v' y" h  g/ e' Y) t$ s    default: ''" ?8 f* |1 W2 O. F) N- R9 z
      },
    $ Y% t0 Z* c, f2 Q5 B+ Z0 q1 f/ f  useEasing: {
    # f0 T1 a) L1 P1 p+ M    type: Boolean,
    : v' B" R# ]% }) p$ `    required: false,
    , z" e  n7 |* b: k! g  Y7 [    default: true8 [3 v. t; ~0 o5 H* C: ^0 d
      },6 R- ^( o3 ^- @
      easingFn: {; Z( {$ I) z2 t* O
        type: Function,
    8 q$ b7 [8 |4 {, M6 u* O+ K2 m    default(t, b, c, d) {% I8 Y. _7 N6 Y2 N; U; n, A! y
          return c * (-Math.pow(2, -10 * t / d) + 1) * 1024 / 1023 + b;9 A1 }2 M9 n5 A% w. c+ X
        }" j1 E, E* j, Q, m. L( P
      }
    4 R8 `4 W# P/ ], t; C" l})
    9 Q  i" U. _" k6 b4 n$ {! H* n4 A! }; W
    ! g& o( W, Z: R# I( F
    1
    ( Z; l/ \0 E1 n+ j# P4 x. W: P2
    ) i9 p' m2 _; d; V# Y7 T3( @' O6 @, O% f6 a0 j0 z
    49 }  N2 a% a; W+ [
    5
    : ~9 H" p! j: Y$ Z7 C, a8 U6; X1 g# b" X* E1 ~% d
    7
    , m0 q% l) ^2 Y9 C# v* A! ^89 O1 z* R& l2 x
    9
    ! I2 x7 ~' k: \0 U' c7 H# X/ ]3 u8 d$ c105 f3 [* f" z8 K( A  `8 p0 Q
    11
    1 h4 O; [, y/ L3 D. |% e121 I: b: D9 l* @4 t9 @6 \/ ~
    134 m* M2 T3 N7 m  e- o
    14
    5 z* J# ?: W0 F15
    8 ]5 p! Z8 {5 y7 b, F16, B# k+ c$ ~- Z1 J
    17
    7 |  {( A  E8 Q/ ~' i! M$ u' N185 g/ A$ `9 {7 j% M  D
    19- a2 ~% f. N& p: O
    20
    ! g, l* `4 s, Y& l5 V21
    4 e  t5 I3 ]5 R) n22
    4 W( K) f0 t/ A" W* w6 L5 a23" t2 l' l, z( |# e  ?& k7 {, N
    24
    ; Y! Q% }/ O2 J/ [25
    * X8 e& O! m2 ?267 z2 v- b7 S) Z
    274 R/ C7 b8 I& [. k) w
    28
    1 [) ~2 j4 T+ Q1 J29
    ( I' g  Z1 c0 Z& b30
    ! M0 _7 Y* Q; C31( u5 ^0 E" p) s$ |
    32
    7 u4 g7 A: s3 M) s  V8 G33: U. y3 W# B/ Z+ X4 h% H* V
    34
    8 y# M+ u, m  V: w6 f  `6 M7 R350 ~! Q6 f$ ?" A8 P# M
    36
    , T; R% Y3 j3 G1 x+ I373 i; L1 x6 z' F+ d, z* Q
    38" Z$ }/ B, [+ d  e4 g& h# r
    395 S- c+ N1 M" k' M
    40
    . ]5 K( d6 s- x+ a, C' r416 O7 x" _8 l. L0 e- B
    42
    ! I3 ~' A  \4 @: B- a; j$ J43
    : A0 }. O4 v1 D- {$ L+ f+ z. ]44, i0 k( j4 e& o. `5 x" B: w6 b
    45* d% p0 d' [3 ]# E
    46
    $ G: K: y) a. ^' J6 {474 `$ x9 s0 R$ f# q) `
    48
    ' l( \% ?- R! }8 W8 C0 R49
    % r$ ^' y5 A* q$ n) F50
    $ [' ~5 G6 z3 }- R& l6 x51
    # A9 S3 q+ }6 f8 m( D1 E: I52
    : p3 g, m/ @' V# g. f* B53  s- h8 F0 S* s4 f$ c- `. M9 \! C- h
    54
    - v( Y: I' [( `% I3 R' a: h4 N55
    # A1 c! F' L) ~% X7 J56
    5 x$ }" Q1 B4 j* `8 z  C57
    : U9 @  r% o5 h3 e58
    4 ?7 H" x1 y7 l/ g- V) \593 Y: X. Y$ K' f
    60( f$ j" U; ^( B: A; v
    61
    9 o! X$ m! X, ]- m- K4 o) ]628 t8 Y; K+ c) q! r' k5 A$ A; A
    启动数字动效3 n0 y. T; D( ]( q4 M2 s2 l

    4 Z: }' O# b6 P+ _$ Z8 dconst startCount = () => {
    9 {% y8 d$ N8 X; f1 V  state.localStart = props.start
    ) G1 z, O6 I+ p2 R. a- V  state.startTime = null
    0 W* N3 D* b# t7 I. L  state.localDuration = props.duration
    " I% P: {* P+ Q  v  q  state.paused = false
    , h" c& _' E, a4 x- U7 W8 r9 x  state.rAF = requestAnimationFrame(count)1 }6 l; {8 _, f! ?* I( i. E) Z
    }
    & W( _1 K( `9 r1
    % }0 K- P8 {  L25 v+ v8 q3 D3 B2 u
    3' W; H7 S0 D! `/ @, |  v% n
    49 q' m! D, @1 G3 l3 T/ z. }) J
    5
    1 j  M2 M- z. Y/ r1 x6* Y# z0 p1 }7 K+ p/ ]7 O/ O3 x
    7
    + C0 a3 }) Y" ]8 U; o核心函数,对数字进行转动9 ]( @: L' F1 a/ H3 x
    7 n- J4 X' C  N
      if (!state.startTime) state.startTime = timestamp
    9 l0 _6 N9 }9 a! D  state.timestamp = timestamp
    7 H4 J% a5 Q5 a0 F  R- q+ G  const progress = timestamp - state.startTime
    6 S$ v; W" |, U& \+ k( y( t  state.remaining = state.localDuration - progress
    2 q4 a* D+ m, i3 F% Y; K7 q: x( C% t  // 是否使用速度变化曲线8 f# z) d% c7 _1 K3 O' L  T, p" v+ i) ^
      if (props.useEasing) {- H$ F/ E0 k" r1 R) V
        if (stopCount.value) {
    ' N1 L: Q& S3 \) ^1 |) ?5 [      state.printVal = state.localStart - props.easingFn(progress, 0, state.localStart - props.end, state.localDuration)
    6 A" f; L6 a0 E$ ?3 j/ ?( F! ?    } else {
    $ x4 ~  _" v4 _      state.printVal = props.easingFn(progress, state.localStart, props.end - state.localStart, state.localDuration)/ i5 i) _, X, z) _
        }
    ( x2 t( H( f; h- T; T: P  } else {9 f+ H4 C8 e2 S5 e+ R
        if (stopCount.value) {
    & m  c; F8 i7 s, U' ?      state.printVal = state.localStart - ((state.localStart - props.end) * (progress / state.localDuration))# E' K; a) F# V9 s9 E. f# w% m
        } else {8 l+ c* p( V8 K* g) l5 p$ U
          state.printVal = state.localStart + (props.end - state.localStart) * (progress / state.localDuration)3 c/ q: ]/ ?+ |/ d4 X" R# p
        }, w- ?* _2 {1 k( D4 O+ g0 Y  _8 h
      }- s' K: }! S" ^* T* Z
      if (stopCount.value) {
    5 Q2 [! p8 Q, w5 f- a$ |    state.printVal = state.printVal < props.end ? props.end : state.printVal
    % w/ c8 A1 n2 b5 }. E) S1 U. ?  } else {! Q7 b- A5 ^( a0 g$ H
        state.printVal = state.printVal > props.end ? props.end : state.printVal5 m% ~( V# ~4 z2 I
      }
    0 j- j9 `9 ?8 g9 `. I# E( E& M" n2 N: O- \; D
      state.displayValue = formatNumber(state.printVal)
    3 _6 Y3 L# ]! j  if (progress < state.localDuration) {
    2 P0 N/ ~2 v4 c: c8 W3 y# d    state.rAF = requestAnimationFrame(count)( U* }( X# A- }
      } else {
    , g! m0 a1 E0 }2 q- C    emits('callback')* T& }& m# g! I. Z( p+ U
      }+ E) h. i& b" Y6 `, A& d
    }
    . a: Q( t8 h7 ?' G" @% H& {, ^( ^3 [* ]* c: U& H  o& n( R
    # Q' G' l/ }# s; t/ o% k
    // 格式化数据,返回想要展示的数据格式6 @' |. `; @' E
    const formatNumber = (val) => {, v2 {! t, _  `( i
      val = val.toFixed(props.default): V( D! `3 ^" v8 f" o: ~
      val += ''
    3 {; q* h$ b2 d  const x = val.split('.')
    ; c  a/ L6 {- p  @  let x1 = x[0]
    ! t$ x3 _/ d" \8 v  const x2 = x.length > 1 ? props.decimal + x[1] : ''/ b5 N$ X: B: e% I( \. J* B7 G$ P
      const rgx = /(\d+)(\d{3})/
    7 l( W/ g& F- E, I* a  if (props.separator && !isNumber(props.separator)) {* u  ?2 m0 I3 y
        while (rgx.test(x1)) {7 E& C; C+ V. Y  S+ y; U2 s; E
          x1 = x1.replace(rgx, '$1' + props.separator + '$2')
    1 Q7 V; c3 ?! r- g& |. K! {1 H    }
    % M3 [, }# M  G' l& \. o  }
    / a8 O$ L8 ^! h1 G, t2 D* D  return props.prefix + x1 + x2 + props.suffix
    4 N1 i% @1 s# X5 k) B8 Z  \% L}# H8 F  Z& I7 ~
    0 u5 ]& k% z, q- A; [
    1
    . t6 X" n1 e  D. u5 W2
    " z  E5 H4 Y. H& c& X34 _$ B  s' G+ F) @
    4
    4 P4 ~6 r3 _; |  H2 q, O) {+ N, D5! {% _. @" z6 A6 U
    6
    $ D) N- ^, C) k6 p* A7/ r5 F8 q2 I, G& x9 \
    8( C9 w! j' s* m4 E$ F2 y
    9" b- m# ~; F. m5 e! @
    106 q3 U& z0 ]/ G  p
    11
    % W' t/ ^6 H9 h  f$ a6 K# [: L12
    + v- m! g2 l- U" V8 T. K13! {, C$ N+ Y7 x6 G
    142 W- {- `1 e+ L
    15* k, d  w7 i1 M) J
    161 y, H+ M1 P3 r/ b+ k1 S0 I9 z4 P
    17
    8 r3 E- Y  M8 p: |' ~# O- s( W7 n2 y18
    7 x6 l7 t. A* h. S8 H  J. C192 Z8 W  H+ W1 a" t* g1 n
    20. c8 t% u" k3 I' s/ w) L7 q
    21
    ; W4 v; b, w, Q, E' F- a4 r22% ^% Q4 X5 u" Y
    23: m8 j+ w: J% L8 D3 X- {8 C$ X) _* T
    24, r  ~8 X1 E" j
    25; X' h4 ^2 |2 j# S: F
    26
    : w5 s6 @2 x8 {# ?) z* L5 y27! l0 L6 _+ K& H% X5 O; h* R
    28( d0 P* U* R/ Q4 t" e
    29# h1 ^+ k7 J+ G5 w3 _
    30
    # L: d4 D2 U$ g8 E% w+ r31
    9 D9 r. x* }4 a% d" S& K32
    + j/ |( z3 J" }33" {" u% ^% z" ~8 q
    34
    & m/ k  O) H! B# K0 l35& K/ g/ b! ~0 E7 E1 w$ g
    36. Q% Q4 T' T' _' u' T9 a( B! T
    37
    4 V; Z5 T0 I7 @$ G( n3 f9 ^! ~# r, t38. w  z# E+ k  W* c& M
    39* c/ L6 n) ~( `7 q& @# @+ i
    40
    8 C! v9 `+ P/ D: Z" `7 c% Z) L: T41: }8 a" y9 }" \+ O* {; j4 V9 |- Z
    42
    $ j4 v  `% n' k; x2 _2 }  z$ k; b' H43; K9 \' J: S( @  ^& X+ ~- r4 A: n
    44
    $ b( s, O2 l8 M8 @) i: f5 i" ~# ]! w9 R45
    7 ?; e  z2 [* \6 s8 I% |. ]9 W467 F6 B6 ^1 Z" s+ l
    47% P3 o6 W  n& I4 o7 {3 v
    48
    # q" K7 O6 \! X  s! p+ R取消动效
    " A! L/ c8 P7 A# Y( G
    ' s( ^, u( q/ Z# [2 H+ N. c// 组件销毁时取消动画
    , n/ x" p; }- x' q1 u2 jonUnmounted(() => {- t8 u- _! u  f, ?! X0 D1 |, E- z: ^
      cancelAnimationFrame(state.rAF)
    6 a- U8 r7 K# Y+ t6 d})) q  B) @1 j/ t  U, |  B( F
    1, c% _0 b. X) J; a/ i6 H5 A8 f
    2/ O. B0 o, p7 y1 C7 J# q0 f" w# R5 }
    3% K0 ]/ a! W- k$ v
    4
    5 s' x+ f; l4 S完整代码
    % J8 B0 x. S6 P" ]; r  e' H
    * q& o5 N' g" e0 A5 y$ l$ _9 j. R) E<template>; S1 a) M' x+ |+ C
      {{ state.displayValue }}) B4 [+ L3 Q2 S5 g  ]& C
    </template>& ^  n+ O+ V6 g) T- M. \
    " a, \# q6 O7 f% `$ V
    <script setup>  // vue3.2新的语法糖, 编写代码更加简洁高效2 d2 R" W# E7 a9 ]; q( A
    import { onMounted, onUnmounted, reactive } from "@vue/runtime-core";, C9 Q' [( U0 r& x( z
    import { watch, computed } from 'vue';1 u6 @! {  D5 D+ E) z" n; L
    import { requestAnimationFrame, cancelAnimationFrame } from './requestAnimationFrame.js'
    1 u' V9 _$ k4 Q( [// 定义父组件传递的参数
    / n5 b( ?% z1 B3 W8 U! e( |const props = defineProps({- y( S- Y. H$ ^+ ?! M) c
      start: {
    ! _4 Q; @  a9 K; i8 ?7 G% r5 r    type: Number,
    + \+ ?* S, F0 I- d5 e' E, H    required: false,
    1 \* s, A7 r7 u7 ~5 V7 E: P    default: 0" y' \8 N/ d: Z* w. `# c/ [* T
      },( K4 ~, k6 t3 F1 e9 ]3 }
      end: {. Z" j& P3 q% h+ p
        type: Number,
    ) R! J2 O% m; ?: \& \# d    required: false,
    " s7 f, ?& J0 ^; s. c    default: 01 n- o) {2 N* m  S) _
      },
    2 i( k% m0 O: Q) Y" Q  duration: {
    / q$ y5 c0 c* {8 X! d    type: Number,& f* M$ A8 J8 k. _# j
        required: false,0 r. n5 ~9 \$ p' t/ v. d
        default: 5000; v. g, w6 C1 ?, k( Q' a
      },
    + ?" ?" z' S! q9 r/ ^" G+ m  autoPlay: {
    ( n; t$ e  F0 l5 v/ L6 l    type: Boolean,
    - t$ y. x9 j4 q' D4 d! _    required: false,
    ' U8 y" ^  z5 `7 G    default: true
    , \' ^( }8 t7 b/ X6 D' {: |$ Z1 q  },
    4 s+ y$ H9 e' V1 [# `9 t  decimals: {; x/ J( K( K; B1 p
        type: Number,
    7 z: v& M# o" A" v# n' ]- o    required: false,
    1 {# F; \: a5 I4 P" P) k" c5 X    default: 0,
    3 @3 M' L# u2 w  A# w/ h% @* L* e2 p% y    validator (value) {
    4 t: B  h6 C1 Q7 u      return value >= 0
    # H+ m# p1 p0 d0 M& D$ {    }
    , P/ u- l' p: Z% L; U  },  ~2 N& ?  }% M7 m3 `- d* u
      decimal: {
    ) L: C0 X/ _  s( o: j, Q, \2 Y    type: String,4 G. Z. P4 l  P- v/ c- x8 D
        required: false,
    " n6 Z, b6 ^$ u7 W% B2 B7 j9 z3 Y    default: '.'0 Y8 c: ]" @. B
      },6 T$ X3 _" ?- d  g5 X2 U
      separator: {- e/ a; F- H2 K' @$ f- F3 Y
        type: String,
    $ h) b$ A1 G- Y# d0 c    required: false,
    ( X2 x' J/ H, v    default: ','
    $ ]& D- n8 S8 X  @. m2 d  },6 x5 v4 g4 e6 ]4 h" v) B; @
      prefix: {
    * }# M* C5 l* W* B6 x) B' W% f2 \/ _    type: String,! @/ @9 u+ Z0 a# s
        required: false,
    9 b1 [% @3 ]1 T( |( M3 K    default: ''' o2 g8 U! F- W" g* Q8 x; I7 G. S
      },% d! A5 n4 ~& y; c1 Q  \9 Q
      suffix: {1 L/ ]4 ~+ z  h- g1 w9 ^0 j0 [
        type: String,
    6 Y9 Q2 a  W1 v; m1 q    required: false,
    + h8 l. }4 H) ^& p: k    default: ''8 D9 Y+ V, u( [. ]; ?
      },
    : n. ?- S" r+ n  useEasing: {7 ?' q+ s7 N# p% F
        type: Boolean,7 S* z  c3 F2 d% V
        required: false,
    ; z2 k9 ?2 A; J) Q4 @    default: true
    % b+ x: H) G/ D- ?; {) S2 b1 ]  },
    + P9 f# q4 q6 f" d1 b  easingFn: {" p+ x- {" J; B* J; R
        type: Function,
    ( E6 V) ^2 t/ M% S2 y1 `. J    default(t, b, c, d) {
    # W3 ~  V# R6 }2 I      return c * (-Math.pow(2, -10 * t / d) + 1) * 1024 / 1023 + b;
    5 t! F  j7 C0 V/ q7 x    }
    5 n+ ~( R3 L1 i5 |6 \& K2 j  }- `: H5 R7 E' ?& v$ A2 B) Z
    })& L% E6 j' G2 K0 T/ P) v4 o
    * ?9 d' j# a5 v6 J" H" N' z" L
    const isNumber = (val) => {
    1 y! x/ v1 [( B: S, l  return !isNaN(parseFloat(val))  j6 W2 K6 i$ N% z
    }8 }; A/ n8 `8 g; `! H0 {( N

    7 |% z, X" O. P* s6 ?// 格式化数据,返回想要展示的数据格式- J7 ~4 l5 K# \& y: a4 K
    const formatNumber = (val) => {: w# n- T$ n' {; \6 g/ S1 O8 P0 V
      val = val.toFixed(props.default), F) J: O) o2 B! f& j. o3 v3 h
      val += ''% f# J' I# n$ r& ]' x- B0 C3 y
      const x = val.split('.')
    1 w" k9 P4 |& M- {9 r" m  let x1 = x[0]- \8 p/ e/ x# X% T& l, I- j5 W7 E
      const x2 = x.length > 1 ? props.decimal + x[1] : ''7 m' r8 {( M4 t8 d( p; u( ~0 ?- x. R7 y
      const rgx = /(\d+)(\d{3})// w- K3 @  N* u7 r5 I- C3 q8 E& o
      if (props.separator && !isNumber(props.separator)) {( F3 ]1 ?" K2 q$ A4 ^
        while (rgx.test(x1)) {
    ( W. z6 q+ ?, u# l8 v      x1 = x1.replace(rgx, '$1' + props.separator + '$2')
    2 a+ @4 _- k3 p! w0 n8 h6 j& S3 ~    }
    3 n. l+ M9 j8 X4 U  }
    5 j9 x0 @/ Z! u  return props.prefix + x1 + x2 + props.suffix
    ' N( N, U* t4 v6 ], P# B8 g}
    4 @( a+ F& R2 M- J% Q2 H" u5 q) b3 d5 s3 U
    // 相当于vue2中的data中所定义的变量部分. x; Q4 u' y) s; X
    const state = reactive({
    + c9 S7 `: `2 j) N% r5 |- ~  localStart: props.start,7 g3 `/ a5 P! T6 G
      displayValue: formatNumber(props.start),! A4 ?5 q) `& |0 T! w# E% \8 @, M" I
      printVal: null,0 _% s& E$ y3 `2 L) N
      paused: false,
    / d( ?. \3 S& m% O- ^  localDuration: props.duration,
    $ b) k. I* D' ?  startTime: null,
    8 O, _' b" R: a+ e  timestamp: null,
    + C4 T- q! b2 W, V" W6 \. J  remaining: null,
    : j" a: D% o: f8 m0 V9 j  rAF: null' H" E6 P* y/ c& x- v- D
    })
    6 G3 {6 [7 {: Z7 g6 b
    ( `  s4 L' R0 x. A+ d0 I// 定义一个计算属性,当开始数字大于结束数字时返回true
    3 x5 Z+ T6 P# `: Rconst stopCount = computed(() => {' v2 s7 J2 M' f! k* {
      return props.start > props.end
    * S5 U* R& V! F, C; `})
    4 V7 T/ E, d: L/ B- C+ a// 定义父组件的自定义事件,子组件以触发父组件的自定义事件
    & w  T) K( n8 v: Fconst emits = defineEmits(['onMountedcallback', 'callback'])+ ^0 ^+ ?" E. D* n0 u0 W9 t

    ! B; K$ P% C# Zconst startCount = () => {
    ' A. z' h  s( l2 a) q4 ]  state.localStart = props.start0 x4 O7 y( V2 C+ f5 }6 m' H9 t
      state.startTime = null
    # \  ]+ |1 A& s/ Z  state.localDuration = props.duration
    3 j8 q2 _8 Y" S  o$ K! V8 v  state.paused = false2 t# v7 a. A/ M1 O' z: d5 e+ u3 U
      state.rAF = requestAnimationFrame(count)
    : W3 E# U6 E: J" |1 m}
    ( `: e* X8 [+ j1 |; }) I7 k% X% k' ?" `" |9 h
    watch(() => props.start, () => {8 ]$ `  ]5 \+ x, z( Q
      if (props.autoPlay) {
    ! r7 G/ g9 v9 U7 e( D. \# U# c  \    startCount()1 Z4 _1 Q2 K' Q
      }
      N: M3 V$ w, L! U: w}): A) w; f$ }8 S* L: ]! J/ M
    , K! l( G3 l5 v
    watch(() => props.end, () => {, F+ F: R( K  N
      if (props.autoPlay) {3 Z) X2 |7 g$ q2 i* H
        startCount()4 D0 k6 V3 e( V
      }" V" J3 i3 d4 [: @+ R3 W
    }); }% f  @8 w0 n4 y# |2 q
    // dom挂在完成后执行一些操作4 c# h* s6 \+ G; H* R( R
    onMounted(() => {
    & M* B: o- Q% z$ _& a, f' J) `  if (props.autoPlay) {- L0 M" Z0 V+ k; b. Z( v
        startCount()* J' H3 X/ ]% V& ?" C! {3 v
      }
    % k: _; Q  _# |& m0 l( d  emits('onMountedcallback')
    1 P, ~* A* ~9 \  X. P})2 w5 h  |# T' s: G/ z3 A0 }$ J( b
    // 暂停计数
    3 H; `% E$ b1 e! h! Xconst pause = () => {
    - p. d0 k* K; E9 T2 c0 q  cancelAnimationFrame(state.rAF)' v$ Y. f5 p% y* L% J0 J; `
    }
    # v, v  G4 b; Z) f4 g$ n) [/ c// 恢复计数" D* O2 [8 g! g
    const resume = () => {3 b6 B1 d1 O; e' H& s% h
      state.startTime = null: \; D7 C7 r5 U+ F/ l
      state.localDuration = +state.remaining+ p. t- V9 ]! ?* d
      state.localStart = +state.printVal8 M& ~, V& A3 F1 [/ b
      requestAnimationFrame(count)
    ) l0 Z6 W6 `& f( z# b. s* F- f$ L}
    3 {" B" t( Z9 e% B' C* g/ s# ]1 I' K' q
    const pauseResume = () => {
    & A$ x! ]$ [- S6 e6 G9 }3 F. @. }  if (state.paused) {
    , J1 |$ d4 Z% m  F6 Q    resume()' O" W- N2 m3 Q' J3 P/ n4 C+ Y
        state.paused = false
    ) a$ L2 B4 f6 B2 h) w0 H  } else {; O* [8 e( L, J: |( M- w: x2 s
        pause()
    : N( D% `7 ~1 K  j    state.paused = true
    4 x- V& h& I' e; S0 ]: q  }( l5 x8 _# }+ ]$ o2 A2 G
    }
      V" u/ C; k- o) b1 |+ e6 `3 Y' ~% q/ {( }. a
    const reset = () => {
    / }! a2 [# P3 R* G& x: t& f& D  state.startTime = null& W! [+ o1 k1 @, z" R" O
      cancelAnimationFrame(state.rAF)% }+ d# E& q% J  o# C! v$ T' o" T
      state.displayValue = formatNumber(props.start)5 w* b3 ?$ s; @& o
    }
    1 F2 c' Y2 Z/ w2 [/ k5 E
    - a4 x9 |, c. G- p3 ^" V2 @const count = (timestamp) => {
    9 k3 w9 P& F, e" |! r8 P. F  if (!state.startTime) state.startTime = timestamp
    ) i1 o, l% [* }  state.timestamp = timestamp* A7 F6 H7 J7 c1 U7 w4 R) ~+ i4 b6 n
      const progress = timestamp - state.startTime
    + V; a1 b" V6 b  state.remaining = state.localDuration - progress! B0 J; F7 l& w! {
      // 是否使用速度变化曲线% W- I$ E4 B8 k
      if (props.useEasing) {
    & e1 ]* `& i# n+ S5 ?( i    if (stopCount.value) {! v& ^5 G* |0 ^9 b! t
          state.printVal = state.localStart - props.easingFn(progress, 0, state.localStart - props.end, state.localDuration)
      u& }' g! c( h6 P' ?4 k3 l7 O$ P    } else {( [7 X) y+ }5 G6 }3 w( F
          state.printVal = props.easingFn(progress, state.localStart, props.end - state.localStart, state.localDuration)0 t6 r# [+ g; A0 f& s7 K) G% X% M
        }
    / a( t  V1 C+ G: g7 @: l  } else {! P% X; D& K! c% u4 F" V7 M% h
        if (stopCount.value) {+ G) P/ S- W9 \- m0 W0 J: r- @
          state.printVal = state.localStart - ((state.localStart - props.end) * (progress / state.localDuration))& j  v' B, c6 p7 l1 W& q
        } else {
    : ~- j8 c2 J: L) p$ }      state.printVal = state.localStart + (props.end - state.localStart) * (progress / state.localDuration)2 g8 ]: M( h( @# u( I# l  b" p* O+ ?( P
        }
    ; N7 W( f  ^, @2 W  }
    3 N7 {3 j, h2 \0 j$ \) l  if (stopCount.value) {
    0 U, K5 c3 U& ^2 j3 {    state.printVal = state.printVal < props.end ? props.end : state.printVal7 A; q/ O7 n7 {4 n
      } else {
    ( v2 ?: k8 {' [    state.printVal = state.printVal > props.end ? props.end : state.printVal. s5 ?" V' g" }! l" Q) c1 {9 J' l
      }  c' R2 s, \& f) m
    & D2 i" T! K" @
      state.displayValue = formatNumber(state.printVal)' X8 P. Y' o2 B6 f" x
      if (progress < state.localDuration) {
    - f, ^; g  B. @. B, ~8 K( W    state.rAF = requestAnimationFrame(count)$ T2 a2 L# }) ~( g
      } else {
    2 z0 ~1 {6 ^8 Y# c3 i5 I  v6 i3 f* q( L    emits('callback')$ z7 r8 D/ c6 ~
      }
    % A$ d0 ?7 V9 g- n  F0 `0 k5 u. v}
    6 L* B2 M- O2 g5 o- m// 组件销毁时取消动画1 w; Y) F! p# e: F/ `
    onUnmounted(() => {4 ]- D, Q3 b* O, T
      cancelAnimationFrame(state.rAF)
    8 l0 \/ o3 y% V4 l% C$ i})& }  R8 `0 }! g3 Y
    </script>; z4 Z7 A9 c$ }9 @* _7 E( _2 I, a
    " w4 }6 l; i9 \- O8 p6 R2 W# j3 c
    1
    : c: R2 L- q7 P5 O, s2
    1 m+ D% X! f  }" }- T3( s- S1 K1 ^" e
    4/ f% F4 K/ n% N8 s) u+ C* F
    5
    1 d2 N! j0 U, D6 V68 ]' l9 A& F9 e
    7+ P5 M! E" U- F+ D  J5 `
    86 n4 B& ~" s3 O. g, m# B5 O
    9' ~2 ?# S7 L- n- s
    104 m" J+ Y5 ~# \# U
    11
    6 V1 N, F3 o* c12
    ) q8 F! t3 U) [1 ]13* c) d. l5 P" D
    14# b6 ]) G* F2 Q# Z, g. u7 h7 ?* X
    157 N4 e1 }: H' c# |# ^! t/ U* i" R
    16
    6 f% V% J; u! u! ]$ a3 D17
    5 N" {0 ]* ]0 q# K9 }18' r" d. v" Y  f" w
    19
    ' P* Q+ t3 A0 I9 A' o( F20
    7 n2 _5 _8 z0 S; b' [+ T6 [21  p3 K; E/ c: k% f
    22: |- f% }* `! i7 H% h; c
    23
    0 R& ]8 {! j, W" B249 `- O) X, H! _! z) T0 v' ?. V
    255 T# A" x- M+ f$ J5 L
    26$ P4 H9 J, U4 A. k, ~. F
    27
    9 K% D) L. n4 N9 T28
    3 q. a$ @6 O3 r( n29
    6 P) t9 @. g% m, W1 o/ j- V30
    7 z8 K9 X6 T/ ?3 r' Q# ]" l+ T. W* p316 u" v; Y6 D2 `: O5 S
    32
    : W0 I5 d) _9 B9 r33- Q& E" |5 f+ N- d/ A" K
    34: z+ `* m" y) M) @  @7 k
    35* p* \  ~+ o! a  V* f
    366 k0 f  f4 F) X! ?
    37
    ' [, A" C: |' @" E; c# M38  b& A* ~" s- L' Y" I
    39' p! E$ X% d! E
    40+ d+ o- X. |6 w1 P; L5 J3 e" D* h  G
    416 E" _1 s/ @$ \3 B, `( C
    42
    5 E& P- o4 p" e& X0 W43
    , J3 @/ E& B, ?4 H# h440 ?3 a2 g* c0 o' j$ i; T" w  H: @
    45
    ( J$ o1 m5 L  y. e6 P46$ o( w  _  ?( O
    47% r" a3 X: V$ Y
    48
    9 ~$ x* P3 Y1 j5 f" A7 ^49
    : R5 G" E8 Z, c, p4 n9 I& o; \50
    7 O, n6 M( J4 R& [: {+ [; H51
    0 s( r  Y4 U0 T& F52
    * @% D# O9 P+ i  U5 J53/ k5 l8 r1 a( U8 T/ V7 o
    548 C  g7 K  c( _
    55( `8 i$ B) ]3 J. [( l" L- u
    56
    6 t7 O3 {1 I6 K1 F: U% z# `4 Z  N57
    $ S8 C9 h$ m* Z, V( S586 F  d) I! C: _5 z6 ~
    59& c8 b! f. o; X3 _4 b" p4 f
    60
    - x. u0 ]  p) E# a% ?+ i. L& S4 _# k61
    # I$ W# {- a/ }' }5 l, Y8 g62
    , p, T/ b( i) d63
    ! ~- Z9 X/ o8 L+ ?64" a( t8 X& r, y$ H5 {
    65' l# s. ?2 v/ _& \6 ]
    662 i) o7 s: F5 H, B
    67) \# @5 N, W: q* V3 w/ Q
    68
    / f6 a+ }8 d9 M2 [3 ~4 ^3 }69& ^# y4 r5 f, K6 o
    70' ?7 [- ~0 k9 K! I* r+ V* v
    71
    ' Q) i! p5 W8 A$ F8 w% W8 @7 ~6 L72
    5 q+ D, R8 h5 l' h9 H: e3 I73
    2 o' ]9 V6 S; [( R. S74' S/ L, B3 n; l; y( l
    75+ {& X% P# b. L5 @4 s
    76$ T# [& B, {' p4 b: X7 A; s6 X
    77/ A: P3 ^1 V. [. {* T# h/ X* s
    78
    9 J$ c5 ~- A7 k* }) w/ h79
    4 f8 d: |9 W9 E8 e$ {* C80  C6 |0 l- {4 A2 X, s9 T
    81
    % I$ I0 M% @* F82
      @# @: p* M) i( ]0 F) i83
    ( B7 `9 z, N0 t/ F6 I. D5 s84* ~; e7 k, l. _, y- ]
    85
    ) P; S9 A7 w2 T! _, _86
    , i4 U, s; g$ C# b87
    # n- P" R) ]& Z' F4 @) L88
    ) G  d5 `! ^( o! c4 t7 z89
    + G: p0 J' ]% C  [* g6 i- N90
    1 D0 P' h% B& ~  ?" f91
    9 t1 J4 E7 Z+ R$ o. s92
    2 t$ d5 u/ o+ M93
    / [% k! i: X- E; l94
    : }$ S" U# O' G1 C95, p% a. Z8 x; v( |. V0 j4 Y$ @: L
    96
    # d4 {" o+ L9 D0 K1 f- h97; A/ w. y8 _* j! C( L1 G
    98& h# M% F! T, Y, S! L
    999 \" D8 U( M' L8 x$ B
    100
    * B8 F3 E6 `  Y9 }( r8 X8 S0 P1012 ^3 Y$ G7 h7 L+ `7 O8 P/ k; O
    102
    , D; S( Y3 W# Y' l- k103
    ' I- F. W' X0 v" p) ]$ s104
    4 X! H; Z9 U' o" q; `: j1053 g3 _0 }: Z; F; Q+ b  t3 _, _
    1066 L' a, i/ C% x
    107
    ( d" c) @, h3 g* I& ]! e/ s108
    % z, O" O  P; i5 {" ?: k/ I109
    ) r. j+ R4 \& M. f110
    : F8 O% T' `- R# ~111& Q$ H4 i4 i- l: V
    1126 V% _' c: g" h+ x# t$ G
    113- ]/ o5 M2 }- R
    114
    4 x. Q; s, E: ~% C8 s9 i115- K; z' l8 t1 x! u, G
    116
    1 s% R/ A- d1 z- I117# r3 v) ^4 W, \8 B5 ^/ W1 B
    1183 s) a0 Y. ]" C: y2 U2 p8 I6 X2 `
    119
    % K6 z" T4 R9 D120
    ; J- q4 y5 O, |0 A1219 N5 x5 p) L# o) `/ e% o6 P; ^: X
    1229 x7 C( O8 t$ ]' [0 e6 B2 x: k
    1238 X) }1 {, a9 x5 q5 \  I# n
    1244 g) t! \+ ~1 Y, X/ `# x" [" `
    125. X% Q  N! f' ?5 }% X' x4 s" i
    126* x2 o! T- J3 `3 p& M; q' d# p0 H
    127
    $ K2 R/ Y4 }+ o& ]1 e! b1282 @2 B- d3 L, l5 V4 P% {/ M+ i
    129
    ( G+ M# N* V0 K# r+ G3 b5 E130
    / T# L4 o( d! h# |2 `131
    6 P' c8 l. p7 ?3 r% W) v132
    . v0 ?2 c5 b% p$ m133
    7 ^$ k) ~' }' ]( F  x* o134
    , W  s* M9 |1 N, z* r) z& N  V135  D9 d7 L, b, L  q, V0 e1 ~0 _
    136: ]% K) l" n* u* W: f8 ~% e
    137* T# G- a+ M! ~! P' [
    1380 k3 N; L* ]# J/ S& o
    1391 C. Y8 Y0 V8 S1 Q  l
    140
    / _7 p: {# V+ e9 H141' ]8 m& q" o+ H! z9 \
    142
    & q" ~; ^) _- r' A$ E' {. D143
    . v! ^( Z* U0 `6 ~. _. ~144
    9 |6 C$ o# H$ ?$ p/ }1 ?145
    " n7 i5 W: o$ t* n7 T* W1463 K, ]( i0 h% I# J4 g+ \$ G) R
    147" M, @$ I' t& i
    148) n9 v, @5 T' `7 w  t/ ^) y
    149
    - Q! Q7 [" ~: ]* Q" o8 w+ c; D+ S2 r150
    9 ~9 d. u3 D7 b( S/ w5 z151
    / P8 M5 l2 k! T152
    & ?# H6 E- }1 X7 ~( j$ c2 @1531 j  H9 u; {+ O3 W1 \
    154
    ' l- l4 E! n: m1 E$ i7 A155
    % _  R8 B0 S9 a* O( D! ~# Q+ q156
    . Z- @  w7 x0 d' m8 p& N0 R* i4 [! [157
    7 J( {* u0 D, X" j158: ^3 Y8 d- h# r2 I0 P2 o: c# v4 |
    1599 |$ S# b( ^4 E. k
    1606 N$ {2 L0 o: L1 ~
    1617 Z% S1 K! H  E; ~/ |
    162
    + }0 m: l$ P4 n& O163' k+ Z) {3 ^- S% b+ N
    1648 S' ^3 w  G; K2 a( z. X* Q0 E+ f
    165
    4 A) e" ]9 P2 C+ E5 S( r166
    + P6 g: e! p1 S  E4 ]167
    , b; W1 F% g8 ^5 p6 {3 B168
    ' p8 p0 D0 l! ?- z1699 a- n/ }. {5 Q2 f
    1700 r0 d& J2 a( u8 U0 `& t
    171
    8 ~" T; P% }! ^172
    $ ]. {1 ]" r- s; D% [# r/ V! H173
    * C+ o1 x* t1 k1 d3 Q4 l7 t" `3 I5 J174+ q: I; @: \. E
    175
    6 c$ O! F4 _% r0 r( q176; L$ ?( T3 h7 |6 ]
    177! ]- v6 n$ I( D; _* d
    178
    0 K1 z  A* t: e6 u! o' b% Z9 y  Q% y3 d! J179; y4 W% M7 ~1 [6 R: I
    180
    $ h% P! I' L# z; a3 b181
    3 p8 `, y& d! b% P$ E: c3 W182
    $ H* |0 Y! }- F183
    + w" i, `. n4 r184: f, e! G" c( k0 p
    185
    ( t* L& H: s3 ]- M4 j9 s- l& N( N186
    9 E& b0 S; I- L: K0 |  v187
    ) q4 D7 Q/ Q/ m$ M188- m' o9 J( I) o* B9 r
    1893 S& ~) m+ N# u: t0 H6 o. O
    1906 o( K; Q1 P5 Z$ o' U$ N& j5 y
    191" e0 G; k* F+ U: H# Y( T# |$ c
    192
    8 }3 f: c4 B& u4 ]- s0 a# e  x5 a193# A1 m+ Y3 `1 c7 u: x' N
    194+ ]! @, p; r1 s2 R0 z9 U- o3 J5 {$ N& O4 \
    195
    " p, }' z% p: a7 n7 x196
    0 `0 l2 A) r; s# K. x197
    4 V. w! r7 I+ _! g+ d2 v198& Y4 f4 y! H' l2 `
    199
      B& W* I+ Y% J7 O+ M) B$ w2000 V  _* `* ~" ^. D% }" `
    201+ T1 D& C4 J9 m" T7 o+ I
    202
    / |; h  M) p% b, `# M3 F总结
    7 M+ f6 T! T. K7 M4 U9 A" B9 z: Q自己封装数字动态效果需要注意各个浏览器直接的差异,手动pollyfill,暴露出去的props参数需要有默认值,数据的格式化可以才有正则表达式的方式,组件的驱动必须是数据变化,根据数据来驱动页面渲染,防止页面出现卡顿,不要强行操作dom,引入的组件可以全局配置,后续组件可以服用,码字不易,请各位看官大佬多多支持,一键三连了~❤️❤️❤️
    " T" k' s6 e3 R4 I- C( t) X; D$ M& f+ ^
    demo演示
    . @5 m. o& P* j5 Y+ v, o后续的线上demo演示会放在
    . B, @7 G' W! V. k5 I" x* g0 Udemo演示& x( L- w6 B' J" N
    完整代码会放在
    & n0 u- l( J+ Q" k个人主页
    # U& d6 {/ n# l4 ^
    * T9 p: B; f% C, w( H希望对vue开发者有所帮助~& L& a6 F: q3 h% n' I3 {: ~

    ) W! m/ h  C5 z; P) z个人简介:承吾
    5 x  ?- N: m: o9 N! S: l* y9 n工作年限:5年前端' h' D7 [, h' E- a  W+ b! j, o  X
    地区:上海' }4 b7 E  `# E2 x
    个人宣言:立志出好文,传播我所会的,有好东西就及时与大家共享!; [9 J+ U! V0 n  z/ X
    $ U- D0 N+ j; S( w" v; e
    " N: U+ r+ f# Y& o- r7 D

    ' B6 \+ K0 G7 F
    ! O& e  U  a% n7 F5 [————————————————
    , C" S" q1 A" m" ~# o! W: x版权声明:本文为CSDN博主「KinHKin(五年前端)」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
    * @8 `- o! e. f" m: [$ K7 z- a原文链接:https://blog.csdn.net/weixin_42974827/article/details/1268318479 [" n- X. d$ x1 E
    0 u$ c$ p. c0 r/ d0 g  z" F( C
    , w$ |4 M7 @0 _; T
    zan
    转播转播0 分享淘帖0 分享分享0 收藏收藏0 支持支持0 反对反对0 微信微信
    您需要登录后才可以回帖 登录 | 注册地址

    qq
    收缩
    • 电话咨询

    • 04714969085
    fastpost

    关于我们| 联系我们| 诚征英才| 对外合作| 产品服务| QQ

    手机版|Archiver| |繁體中文 手机客户端  

    蒙公网安备 15010502000194号

    Powered by Discuz! X2.5   © 2001-2013 数学建模网-数学中国 ( 蒙ICP备14002410号-3 蒙BBS备-0002号 )     论坛法律顾问:王兆丰

    GMT+8, 2026-8-24 04:04 , Processed in 0.485150 second(s), 51 queries .

    回顶部