QQ登录

只需要一步,快速开始

 注册地址  找回密码
查看: 2618|回复: 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 | 数据可视化实现数字滚动特效# x% j& ]3 ]* j. F6 V
    4 ]* F+ F  U' N
    前言' @3 \8 M5 p9 |$ _. Y: d
    vue3不支持vue-count-to插件,无法使用vue-count-to实现数字动效,数字自动分割,vue-count-to主要针对vue2使用,vue3按照会报错:. u+ p' ^/ d+ J  e1 B, x5 Z
    TypeError: Cannot read properties of undefined (reading '_c')2 v; I( c, H, H6 r- D9 ~- V: v' |
    的错误信息。这个时候我们只能自己封装一个CountTo组件实现数字动效。先来看效果图:
    # U! x! M8 b2 h; P* c3 h$ \0 A3 }. E" b, ]1 l3 @+ j: b

    9 a3 |% Z  Z9 N1 d5 s! p思路
    : _+ H2 ^; j' ^. R+ Q$ O% C: I使用Vue.component定义公共组件,使用window.requestAnimationFrame(首选,次选setTimeout)来循环数字动画,window.cancelAnimationFrame取消数字动画效果,封装一个requestAnimationFrame.js公共文件,CountTo.vue组件,入口导出文件index.js。
    " e: P* Q& d0 z3 |7 o4 O+ Q( r4 S( G7 b; Q6 N
    文件目录
    2 _, Q  |  i# y$ h
    ' o/ b) z# p  K' x- P  L$ d( K9 X2 q  G
    使用示例
    , W# l8 `) E2 H, x- f6 g4 |<CountTo
    ( v# K1 y9 O2 E6 k: [5 w: s :start="0" // 从数字多少开始
      k% g+ D/ L/ G  u8 L4 n :end="endCount" // 到数字多少结束( [3 J. N. K6 O" e; {% w" e
    :autoPlay="true" // 自动播放
    7 k( z2 m* ?* j3 _2 w :duration="3000" // 过渡时间7 x3 U. r" U. c+ V. O, W
    prefix="¥"   // 前缀符号& `& a$ c  L* ~9 a, o4 ]$ Q
    suffix="rmb" // 后缀符号! h# J+ k! i) X& q8 d' m
    />1 I8 B/ {+ P3 T7 m, P
    1
    ( [9 `: x+ v9 R; y; P3 @7 m2
    & h* m' {/ q$ ~) N3 d# k35 [5 c) h2 Z5 w8 \
    44 B5 O+ l4 a7 ~
    5
    . z: ?% [/ s' b& D8 B6! J8 X7 D$ N' S+ k/ H, h$ a% }
    7
    # @. x8 g; C8 t5 M. y84 P+ U7 r9 q% J( P+ k1 x0 `
    入口文件index.js
    0 E/ x* _* Z7 Y) B* z5 ]! e7 v! ^7 `2 j7 z7 V) {
    const UILib = {
    - g0 f9 S' u: N' D! B+ }  install(Vue) {% m) j* e0 G$ s1 ]6 p- A! j
        Vue.component('CountTo', CountTo)
    , I3 V, V# o; g3 `1 A+ k  t  }
    + U" i7 b# |/ F/ [" S7 ?+ L}4 o: d% T8 k% ?1 Y* o( i

    9 a4 @: D2 R/ W* x3 G) A1 s0 y; Y' \export default UILib. W5 Y: l/ O3 ~, o  t( m7 P
    9 l# V$ o( h1 T& f
    1
    ; k/ z9 n, @1 j- u( d2
    1 W9 h4 m& R, ^7 J1 R# ?3
    7 s2 c3 u! Y) U7 Y- A4 X9 y45 W- q, E% I% C( W& Q
    5+ C) V+ M; Y# z' f7 M$ J) c
    6
    & q3 T( V4 q; b, Q8 }7 \/ g7# l: H! ~6 E$ m1 B
    85 t0 ~" Q5 ~: \0 ~9 s2 n; {
    9% @- V$ Y8 h" I/ Y) E5 k
    main.js使用' ?& S! o3 I) E% h. e
    import CountTo from './components/count-to/index';( a7 `1 a. Y  ?' s  F" l
    app.use(CountTo)0 n2 N; n' [# A7 g) E4 e6 l% D
    10 Q  _# b) t9 e* U, m
    2
    & O3 }: k* _. e; WrequestAnimationFrame.js思路
    9 ^- g" H' p  k, y2 Y8 o先判断是不是浏览器还是其他环境
    , G2 {9 ?8 z$ ]5 ^如果是浏览器判断浏览器内核类型) `" I' Q* ]( C8 e/ w+ q6 A
    如果浏览器不支持requestAnimationFrame,cancelAnimationFrame方法,改写setTimeout定时器6 d, H3 Y) s8 u7 l9 N
    导出两个方法 requestAnimationFrame, cancelAnimationFrame
    1 ]. Z! X, K; ~& k: X3 V) Y各个浏览器前缀:let prefixes =  'webkit moz ms o';" ^$ T- @" w6 g! X! y1 ?
    判断是不是浏览器:let isServe = typeof window == 'undefined';
    7 _0 P3 o7 w+ M2 {) d: s9 q增加各个浏览器前缀:  
    % [7 A0 G" K* C+ X! X7 Ilet prefix;! r5 M1 Y) b) d; h6 h4 |1 R
    let requestAnimationFrame;+ C$ l9 `" d: @6 B% h6 B) D4 q- e0 g
    let cancelAnimationFrame;+ s% A& V% p+ ~! E; `
    // 通过遍历各浏览器前缀,来得到requestAnimationFrame和cancelAnimationFrame在当前浏览器的实现形式
    ' }+ j  s, i& ^& D0 u" g' W. R    for (let i = 0; i < prefixes.length; i++) {/ y' |1 r# p# D
            if (requestAnimationFrame && cancelAnimationFrame) { break }
    . P& h- d  i3 O/ D) U* ^: f        prefix = prefixes
    9 m2 \9 a) F0 R+ o        requestAnimationFrame = requestAnimationFrame || window[prefix + 'RequestAnimationFrame']* u+ b6 Z* ?! t) _* S
            cancelAnimationFrame = cancelAnimationFrame || window[prefix + 'CancelAnimationFrame'] || window[prefix + 'CancelRequestAnimationFrame']. @& C: F* u3 D; h7 c
        }
    ; X% S& P/ u$ k  [$ y" T7 A  g7 x: b
      //不支持使用setTimeout方式替换:模拟60帧的效果5 |4 r: A5 S$ `
      // 如果当前浏览器不支持requestAnimationFrame和cancelAnimationFrame,则会退到setTimeout2 Q" U! d% h+ x% }" `4 P. O' f
        if (!requestAnimationFrame || !cancelAnimationFrame) {
    2 |/ O/ W6 |) S- ~: V- e+ o/ A        requestAnimationFrame = function (callback) {, T2 C1 Z7 i  u5 x6 D/ h5 \3 I% ?$ p
                const currTime = new Date().getTime()
    * M' b, ]( N$ P3 I            // 为了使setTimteout的尽可能的接近每秒60帧的效果
    2 W. W) u  z$ m( r  h1 K9 @" `. Z            const timeToCall = Math.max(0, 16 - (currTime - lastTime))( L- E4 {- Y4 S5 z4 e5 [2 n
                const id = window.setTimeout(() => {
    & l4 K5 \  J- e4 |  D2 b) y" C8 \9 s1 c                callback(currTime + timeToCall)0 T3 W4 m/ c  c! C% e$ v+ f2 g
                }, timeToCall)
    7 P8 ]- I$ b3 u            lastTime = currTime + timeToCall
    : `- B+ ?4 k4 Q. W            return id  a9 u  z+ `* U- ?
            }
    3 O8 Y' M" f. M' \' N+ @8 V
    7 y. }& R' O) g5 B        cancelAnimationFrame = function (id) {
    0 \3 Z# R5 j" ]3 c1 R$ I) w            window.clearTimeout(id)
    + T( y7 h: c8 \9 p3 T3 \        }
    ; G3 }4 v, l* c- a* R    }) S. v: w: y4 i0 ^" b8 x

    , C( L# E/ ?, S16 K4 d/ @# c2 e- q
    20 \8 E5 ?8 c6 N
    3. z2 n! ?& w( o
    4- [* D7 k5 f; Q
    5; x5 f: a# r7 v6 D2 a
    6) `, U- p0 K0 x3 M% d: A- t% x
    7, Q) [' }3 U' O+ |7 D
    8* f3 U1 o5 V/ |2 E2 a7 V; u$ s2 ?
    9
    + y1 z7 O& S4 j4 E" p10% \5 {3 L' T$ _0 n$ M1 t6 F
    11- p& u$ m$ U( e# T# ^
    121 ?) d! N# i, d& F: Y
    13  H; K% X* z/ L0 n( g
    14
    5 u' ^; g2 f; c/ C) r$ e, K15
      X9 M& r8 p- [/ a; Z, i16
    , ?* b$ l! @1 e% @* {8 j6 B171 j0 u: }: h- B7 {; B
    18( O9 T- A3 H* v" m$ p
    19* B/ U1 g: |  |$ D6 Q2 `+ h9 x1 u
    20
    7 ]' w" Z" s9 d4 ^. h. G210 z6 ~! n4 `$ h# k
    22  z8 [2 B- K5 }/ D. w$ V$ @; C% \  F
    23
    / z) ]3 k. P9 _. S' d$ ^' \24) y$ c* b+ Z% z1 K
    25% h, r: L: K" L3 |- J4 C  U
    26
    ! F# w8 n: t+ A3 l2 M* M27& a6 q  r: R  p8 k8 X6 u
    28. O0 Y- L: ^9 V
    29
    / x, X! S% v- n30
    5 O% A- ]1 h2 \8 F+ K( ~31
    - J* \5 \3 j6 p0 M8 w32
    3 D0 j7 ^6 X: \2 R1 H4 l: Q, L& y完整代码:
    # C# [- s  o) I# Q) q3 FrequestAnimationFrame.js
    2 ]6 Q$ C7 j' ^% M
    6 a! t( U1 n0 R0 f2 Rlet lastTime = 0  z. l) l7 F3 y/ E" @( k. Y
    const prefixes = 'webkit moz ms o'.split(' ') // 各浏览器前缀( S0 a0 W* I: l4 ^3 h
    5 v2 i3 Y3 h2 i  ^0 C: y$ o& ?
    let requestAnimationFrame
    : A/ U+ w$ l" ]) Y- l( Mlet cancelAnimationFrame
    6 m( O  j6 a4 d8 R0 o$ f) z& h3 r; t
    // 判断是否是服务器环境! ?) f8 u7 l4 `  i8 ~3 q
    const isServer = typeof window === 'undefined'6 J2 `1 \! g/ W! q2 }2 m0 r( ^
    if (isServer) {
    % Z, J7 f6 E5 V/ G' C- N    requestAnimationFrame = function () {4 v! e% [2 d! V. f
            return
    " I. }, _$ l8 W- m: v    }! x8 I% ]4 U5 O2 \/ ]$ e$ ~' m% V* M
        cancelAnimationFrame = function () {  |# L; h8 W: F& `$ r
            return
    - _/ _2 R! k  U) s/ x/ r* k1 ~1 C5 [    }
    , }6 E$ @! o5 _} else {
    % I6 z8 t$ H0 W6 W    requestAnimationFrame = window.requestAnimationFrame
      o8 V8 n: m3 Q4 \    cancelAnimationFrame = window.cancelAnimationFrame8 C+ Q& ?: z. o) M$ \6 t4 z6 h- _4 T
        let prefix6 X& s7 R8 O2 _. x. }+ p, `8 F" z
        // 通过遍历各浏览器前缀,来得到requestAnimationFrame和cancelAnimationFrame在当前浏览器的实现形式
    2 g) H  c6 \) t8 c7 J, {    for (let i = 0; i < prefixes.length; i++) {
    " W. Q( f1 E: w+ m        if (requestAnimationFrame && cancelAnimationFrame) { break }
    + E' H1 ?3 S0 Z$ Y        prefix = prefixes. H8 a4 k" o/ O
            requestAnimationFrame = requestAnimationFrame || window[prefix + 'RequestAnimationFrame']
    7 w- b6 o) u6 Y5 B! u0 y        cancelAnimationFrame = cancelAnimationFrame || window[prefix + 'CancelAnimationFrame'] || window[prefix + 'CancelRequestAnimationFrame']+ s) U" M6 n0 L! y' G1 n2 J/ E
        }' P- e2 l# K: C) E1 [
    / H7 u+ Q% Q0 s+ x9 e; k9 m
        // 如果当前浏览器不支持requestAnimationFrame和cancelAnimationFrame,则会退到setTimeout
      D$ {. F4 i4 S/ P    if (!requestAnimationFrame || !cancelAnimationFrame) {% I3 R" Z1 L- y6 H- \
            requestAnimationFrame = function (callback) {
    $ m1 b+ T- N* R' Y# R            const currTime = new Date().getTime()5 c9 k3 @6 E: i! W" G
                // 为了使setTimteout的尽可能的接近每秒60帧的效果; K! m7 s4 n. L, m5 X
                const timeToCall = Math.max(0, 16 - (currTime - lastTime))
    ) J. ?! K9 }. C            const id = window.setTimeout(() => {
    ! t$ t& M! T8 H9 }$ t                callback(currTime + timeToCall)' b  ?- N' ?. R. R
                }, timeToCall)3 D2 N: G2 D9 R' O9 _8 e/ R3 ~% F
                lastTime = currTime + timeToCall/ @) `" \5 l8 e  b
                return id
    8 l0 q: e) W5 ~" \        }3 n+ v: f  \* P3 A" L
    % H! i0 }- T1 N7 z3 P
            cancelAnimationFrame = function (id) {5 w9 f8 t. j0 X8 |
                window.clearTimeout(id)
    * d5 B  i1 @; B/ q. K        }
    7 C' L: Y$ Z: D9 c4 {    }
    + Z$ p% B' y# h8 E}/ T# |6 _- h+ o: s

    ' s. V! E: Q# L" s% lexport { requestAnimationFrame, cancelAnimationFrame }
    + N/ U" V, Q$ i$ t. O! c% k% H- G! @+ y
    / o1 L) K: _; P, u1 R7 j
    14 d3 m+ h4 E/ K( A  X0 L1 m) z8 S
    2! m, T$ @* \5 E5 @" w& X; ]0 \. A
    3
    1 ]" ]; [8 i6 q5 A. q4/ E8 u7 y' s1 Q! u# `2 ~
    5
    8 T! z* @+ ~9 |/ j3 S6, w/ u" b+ Y7 {- ^/ H* s
    7
    , F& q. g* C6 i- x' O! K/ {85 @: d3 @  S2 r, d" i1 W( J
    9
    - E0 S1 b# ]. C/ G$ y* N5 ^2 ~10
    , b/ \" h$ h6 l8 A* \8 s7 z$ `11/ c# f, S2 E: Y$ j* j" |6 W
    12) J& S2 E! K$ z) B
    13" C; B# a: n  h- m, m" J$ k  [
    141 n& C9 W4 w2 u8 J& Y+ T/ E7 U
    15; n' H% f, ^, G: w  s+ {5 W
    16
    ! O0 R3 z2 ]+ D0 ]" u3 T17
    + y5 t5 c- A3 a* d/ V18
    0 _4 R3 ?7 L, \& b8 Q% _19, T, w4 M' c( `! r- B/ Y
    20  ~% W* X: t1 k. L/ T$ l
    21
    7 ^- s( X% v3 q22
    # e; `, Z) N- K23' E5 Z6 }& `" f( d3 ~& m) c
    24
    , n& g4 u6 k& F8 ^25
    . ~" z2 d# J+ k. ?) [) P4 A! G267 R! X. \9 H3 v
    27
    . A2 H6 s1 B5 [' b7 `* r1 r: t" K28
    : s+ k: p( g, O/ D, g% p) U$ {29/ U* V& _8 e4 K# O5 n. e- E7 F
    30
    7 v: I- W# H1 `% @2 k& I8 i% g31* n3 R0 J8 m: X0 K! E
    32% R  M7 Q6 I" H7 `
    33( O2 B; J$ o+ E6 L# n$ j8 [
    343 G+ M4 y! j5 ^, x
    35
    ( `! p4 j  N' i, N; ~4 ]36
    % D+ G  l' P$ X6 @4 p37
    ' ?6 b- p% i6 _% Q+ ^7 M" s38
    7 [" N! R$ {! R. ^* i! b+ v: O39
    6 H$ l4 O8 H  l# `" W% N406 V" K0 I7 T8 g' T
    41
    2 K: ?" y0 A! {  r' b' N+ a) W42
    ( V4 t' }# n7 Q1 a0 B3 Z43
    $ Y) S( f5 d: P) A8 A44# c# M1 X# `. A! S
    45, t+ h6 L5 w. O( L+ d, E- ]
    46' g" w+ D' J, Q3 B0 V1 w
    47& r) S4 V8 r6 _4 x  M  C
    48
    9 D$ |: N0 p/ {7 x( ?& gCountTo.vue组件思路! w0 d( \5 v$ a6 v  |$ w1 I
    首先引入requestAnimationFrame.js,使用requestAnimationFrame方法接受count函数,还需要格式化数字,进行正则表达式转换,返回我们想要的数据格式。: F% H. E- ~3 g7 C; ^
    0 ~( a2 ^4 a! H1 f/ X- s2 E
    引入 import { requestAnimationFrame, cancelAnimationFrame } from './requestAnimationFrame.js'
    % M3 R6 c0 E: `0 W+ A) r1) O: @# n' E- t8 ^
    需要接受的参数:. ]& F# I: B  h! U$ h
    ) E6 |' a8 W0 j4 g/ S7 y( s
    const props = defineProps({
    4 j- @: h  L7 Z, I+ r  start: {# j, x# |: v. Q+ C; }) h
        type: Number,5 C$ B  u! k* S- C& S
        required: false,
      d: p9 U! B8 y7 r5 t    default: 0
    5 E) w4 \; a) }. l  },
    & \( g  K) Z: a; z0 l  end: {& a4 w8 W1 ^* M9 L; c
        type: Number,. B( `4 O) V6 ~1 q
        required: false,8 }4 @  N* S5 E/ a* H  c
        default: 0* C- w2 z$ Q5 h. ^6 \  ]+ H1 s; D
      },
    ' ^& F, `! x, B$ A0 \* v  duration: {
    4 E7 y) M0 r  B) J1 ~    type: Number,& i' m6 ]: j- E/ \( z/ s3 p
        required: false,; a4 r- M) @4 d9 ^
        default: 50004 f) W! h) j. q- f9 y
      },) w2 G0 n& B0 E- p# d0 t
      autoPlay: {
      D7 v6 {- F( x% u+ N) H% J; p    type: Boolean,
    ' z& s- c; O, Y6 G8 W    required: false,8 l5 ]8 }  s3 S- I' }1 ?2 G4 I: }
        default: true
    $ }  j# d+ p; H# z) h2 t+ a; T, Y' J  },
    ' b9 b" F, P& j  L8 E8 t  decimals: {
    ; T7 o& ]; [/ G    type: Number,8 a) H% v. d7 T, p( W, ]
        required: false,' f. n; N/ O( K- m5 |) C
        default: 0,( G: Z3 ]5 X' K
        validator (value) {
    ( S) n; ~2 S9 P4 S+ |% ?      return value >= 0/ s0 _# Q+ R1 u8 W2 Z) V4 q
        }% ?; Q$ m/ i8 ~! X0 @% i
      },& _; \5 }/ E" o1 V- {$ _
      decimal: {6 b# i) s# [0 @2 [! T6 ?8 N; i
        type: String,
    * H2 J9 r; L5 L$ _' z1 \4 c0 N    required: false,' h3 {% l3 l0 K& ]! P, ^( d7 X2 E. ~
        default: '.'" Y3 \3 j; M$ e$ M4 w7 Y5 P9 C: K
      },6 O2 @1 y5 J) d% l7 f
      separator: {
    ! N0 `. Q8 T  J( U' T* G    type: String,
    / X5 ?: v: g7 @6 P, z7 E# y    required: false,
    , d6 {6 \6 b! ]- J6 c+ n    default: ','
    8 m4 I. U( ^1 x% h9 U4 g6 m( E: o( C0 g  },$ {1 }  C- T8 _$ d
      prefix: {  j" O) n/ v- x
        type: String,
    ; Z7 Y: C( s  K  I% b( |! J5 D    required: false,
    + ?1 b$ T# b, N) Z/ D  M    default: ''
    & z! G: I, O) C, S, [0 V  },% ^& k, w9 {1 N/ g! n0 z
      suffix: {+ r  x. O# W7 @( D8 c6 e% s# c
        type: String,
    6 i6 M9 H- N3 K+ Y    required: false,/ [% g" n: e5 @8 k* C
        default: ''% ^( x# n: x( d1 j0 t. B
      },6 d. Z! S% x8 }  X# S4 U
      useEasing: {. O. L4 E- Q+ r+ K7 T4 b
        type: Boolean,5 h* L' ^" y' m+ N9 J, N+ j0 p
        required: false,
    0 H2 `- P* P6 ?    default: true6 ^) z/ K1 r1 s/ ?/ P% p
      },4 ]- w: t3 B8 o4 X+ u: a& p
      easingFn: {' i( h& h3 o3 j! c* |0 {; b4 s- `
        type: Function,7 P% K6 J/ @) o5 v* c
        default(t, b, c, d) {
    5 r+ V0 O; H" h' N( c# X* l      return c * (-Math.pow(2, -10 * t / d) + 1) * 1024 / 1023 + b;
    ! y; ?/ |1 {5 f8 s  ?    }
    " [# q9 k2 I0 s7 ^  }
    / b8 S0 Q/ F1 k& U, x})
    % K. s3 z# K* y" Y# Q9 V  @- \% l
    5 x% L8 W! p& e! O0 Q0 }8 O2 i! \- T! M  T
    1
    / j/ ~& Q. o9 C0 o5 s2
    # `/ t- {$ l( w, N9 B) G- U3
      H0 p9 @+ \( `' f1 j42 s2 L% o% \: X, E9 c
    5
    $ q& Z1 u/ ]% d% F- @- x+ [6+ e) b6 P  L0 B- h/ \1 s& F- |
    7
    : ^) m. E4 N% o86 b" n$ C- P! E1 p5 w3 B4 Z8 F
    9
    ) w) ?0 U) d5 ^/ q4 u. D10
    7 G( X4 ^7 q3 B8 d11
    8 f' d$ b0 x9 K, d, g$ N9 e; f12, v# V, N  {* i: V% s. r
    13
    9 M! B1 j( d/ Y- i6 i7 a; c14
    # ^9 z6 ^; W6 p7 c, h: q% M- ?4 y# F15) B% A; q* B/ r1 R8 w7 T; r, L, p; c
    16
    ) L: I. S% B$ S* s# _2 t17
    " [# F% e2 Q  ~4 ?18
    6 n* K% k- X. T1 d) P% D6 ^19* V7 ~2 W& B0 J3 |
    20: j, K3 P. ^) r
    21. g) z! m" a, K# D3 C
    22
    $ H) {6 D! p* P5 ^  G; w, {23
    0 s+ D; \. I8 d. D9 j+ y! ~24( d; m6 F- y, C7 O1 L
    25
    , |( E1 G& W, E+ I26
    1 d0 u0 f: A/ e; |" K9 ~$ G0 V2 S27
    4 D8 N% Y2 \+ a4 u( I28# T! B" b3 k) J! P5 a( m
    29' p( A6 ?: L& e% N: C
    30" }9 ]: i  ^, b
    317 H" M. ^& I: z( B: b# w8 w
    32
    ) ~2 V" X* I5 L# m) i  g33
    : e6 X6 a$ ^8 i9 `" `! s34
    6 n3 w! b9 n8 i/ `7 x) M! ?. G35/ C  \, O- r5 W; ^# W+ y
    36" q9 Q# {! y, i. ^% y  i
    37
    - T4 I1 k" j% q! T38) s) Z( I# Q; I5 G+ H/ B: b
    39
    7 i& Q9 x; t# o409 Y9 {" P, S7 a+ t
    411 G9 B' u; n5 N0 O+ o4 e# D
    42
    2 J5 k2 C+ ]# y$ _43. r# q' h7 W0 M5 k' c1 s# Y3 _
    44( r  L! C2 \+ [0 g. x5 K! F
    45
    4 s' k; O/ J6 a6 b# ]2 G, v' h46
    # r6 T( O3 [$ f" V% O" e5 ~; }47
    / }2 p$ g! C* n6 _& b  V48* i4 _1 e* E( B& X! y! i
    49: y9 s$ |% W4 K$ \9 r5 f
    50
    * A' p# {7 x, V- E1 @  {/ ?4 m51
    % ~$ H8 a% W5 l; ~. w52
    ) G6 v5 m; V% V. r( t7 ^" T) c/ m2 s53' C& X( D5 \1 w" N! `* C& f
    54( o" z% K2 J1 Z
    55& t% z6 S: u# C; x
    56: r& `' _6 p6 E& n2 Q/ l8 {4 s  Y
    57, s$ P0 H5 S0 t) O0 k2 T
    587 F/ E8 w1 M% P/ z. `/ U( n
    59
    % L3 P' W  t6 [6 v0 N* h60; C" \3 r* _6 y* E5 `9 B" t2 b
    61
    5 |/ x2 i$ S& W# k62
      t6 p6 ?2 c. Y" a8 l* Q启动数字动效
    4 d0 R2 R9 ^5 J% Y5 l1 D# Z( d: M# g/ v, f  K% M
    const startCount = () => {. r* M$ c$ X! Q) k% W
      state.localStart = props.start
    + F! Z4 h' N' G8 n  state.startTime = null
    * w/ E5 I# ?( \- _3 J0 O+ @3 J  state.localDuration = props.duration% }* U7 F! `- o" v% ?  A
      state.paused = false
    ) K. l3 A3 i. p( e6 A/ z7 l! W  state.rAF = requestAnimationFrame(count)& o) [7 c# ?( z1 c, U% e
    }- q. Z, v0 t1 ?! q( D7 g6 R
    10 x- t& Q1 H9 W8 w4 P
    2
    $ [( f! U  A& s- d8 a$ g& E% ]3
    # n5 H0 @  [) |5 y1 K7 P4: R8 x% G9 A3 V% X* j. i
    52 B# k9 L/ {# v1 W) d( m
    6
    ' _) Y4 B8 ~1 U( Y  ]7% E+ K  s! j% T9 Q
    核心函数,对数字进行转动+ _2 d4 ~9 z. @! t; a% Q
    0 g9 G% m, P& a! X
      if (!state.startTime) state.startTime = timestamp
    ; y& I  }8 z8 \2 s  state.timestamp = timestamp
    8 a$ }2 e" U- J* A6 r6 ^* R  const progress = timestamp - state.startTime
    4 Z$ D4 @5 S* S: Q  state.remaining = state.localDuration - progress
    / N; i: @5 l7 H9 Y, `4 }  // 是否使用速度变化曲线0 @+ y- b8 M0 I6 r2 t: n7 ^6 t
      if (props.useEasing) {
    + H$ P- r# A# B2 U3 z+ N: K1 n    if (stopCount.value) {
    4 S4 k- L# f- ?2 e1 y; q8 j      state.printVal = state.localStart - props.easingFn(progress, 0, state.localStart - props.end, state.localDuration)
    6 P# R6 D* K. N    } else {
    : N7 O& {' u0 C! D+ Z; y; p4 o      state.printVal = props.easingFn(progress, state.localStart, props.end - state.localStart, state.localDuration)
    ( I1 n7 d2 W" x' e! j4 T    }8 E9 w3 {- O4 R- D
      } else {
    7 Q+ Y' V3 m( w1 V! A) O    if (stopCount.value) {
      U/ Q; {2 r  ]+ H( x, O* v      state.printVal = state.localStart - ((state.localStart - props.end) * (progress / state.localDuration))1 n& c* {! H6 j$ N/ C
        } else {
    : p2 w# y# b7 l2 M$ J8 o$ I2 }      state.printVal = state.localStart + (props.end - state.localStart) * (progress / state.localDuration)
    - Z" X& f/ S1 J* k+ f' L2 ~( i    }
    + g8 t3 h, h4 _" u& _  }3 _# r9 D0 {  K; v! O  n/ m
      if (stopCount.value) {/ c! U; c) Y# H
        state.printVal = state.printVal < props.end ? props.end : state.printVal) H- ~8 ~" |. g' C5 l+ D( t
      } else {$ T) c- _3 Y" l8 s, _* b% U
        state.printVal = state.printVal > props.end ? props.end : state.printVal9 F  `0 ?* u: H% U" D
      }
    / C  I/ |( |" q5 N' i: U+ S: \) y2 C, R/ N- H
      state.displayValue = formatNumber(state.printVal)+ P4 h: O, H0 b5 ]
      if (progress < state.localDuration) {0 X, X! v' r6 p/ T
        state.rAF = requestAnimationFrame(count)
    % S2 _. |& _, K! j% v  } else {
    2 ?; F! O# v, c    emits('callback')
    * z/ X4 e0 Y) k6 M3 o* g/ S6 B  }( V' h3 _: U1 X2 j
    }
    5 I7 H- W9 }! X$ A( T( ]. {' q- \) n! D/ C

    , x" e5 y- j# o: x// 格式化数据,返回想要展示的数据格式
    0 m% c6 ~6 x% l. |/ P- W7 |3 Hconst formatNumber = (val) => {* S3 G  z( _/ t# C4 N- ^  b) q
      val = val.toFixed(props.default)
    / D* K( n) h$ N: B) D1 C" N  val += ''2 W! V1 G5 f' A' K5 j
      const x = val.split('.')" B1 ~0 a; s9 p
      let x1 = x[0]! {7 `3 A* Q* j  _
      const x2 = x.length > 1 ? props.decimal + x[1] : ''6 a; ]- ^2 o9 a% n/ O( z; F8 X9 p" r
      const rgx = /(\d+)(\d{3})/- @7 l/ ]1 S. i
      if (props.separator && !isNumber(props.separator)) {
    ) Z5 e+ n% s, A2 M% ^4 c! U    while (rgx.test(x1)) {4 O) ~$ F- v* N8 y
          x1 = x1.replace(rgx, '$1' + props.separator + '$2')" w7 E8 H9 K+ b$ m& {' n6 p+ M4 E
        }  A% U' ]5 Z& H9 p' n5 M6 t
      }
    , l2 P, e: k3 `7 g; N  return props.prefix + x1 + x2 + props.suffix
    6 m$ [5 F8 r; ^1 N}+ A+ L* E# _5 J$ E

    ( n/ J; W3 s4 ]8 g1/ {! S0 k. F0 R3 ~
    2; Q' {9 ]5 T- W: ]9 O
    3
    # A( \6 w; z7 ]" O+ L4
    9 `' v4 I2 @0 i+ y2 B1 f5
    6 A( R6 C/ ?/ I1 |6# g: n" c# Z0 }; ~) M% ?+ q9 |# s
    7% r$ |" \2 @9 {, L
    89 c' B% ~4 _' A6 a9 A+ m1 v
    99 l% H7 }& ?# Y1 y6 H5 E- S! k, H
    10% x( A, a+ Q, ?2 C1 W# }' V
    116 }; t4 N7 r& Q% L
    12
    5 S- j1 ^+ D5 I/ f13
    & B+ Y4 i1 f/ K! Z8 c5 K  H14
    3 R) }+ N  d) H) ?: a15
    5 s  @7 F* }4 R) Y# }; a16
    $ |$ c+ }9 ?4 D2 h, [17- q. |9 u2 o) M( e
    187 n9 R6 |7 ~: p7 N( e
    19, e2 N4 p* w& g& B/ T
    20
    ! l8 C8 o! D! ^21: [% c5 G4 n. A
    22
    " ^# u+ H- {3 \4 L% K7 A' T23  D' i' C" [  C2 f6 C
    24
    8 L! C7 F9 v- B& N9 d25/ _- M# g4 I- Y- u. I" a
    26& L# n% x. |! m6 ^5 n5 z
    27
    9 Q1 K/ T( i$ ^; y2 c! K3 \28
      p+ [4 L# Q0 Z& I( e) s29: N% N, B# u4 u$ S$ e3 o8 e
    30
    ! @1 q- p  q' H31
    % G" i+ L, y* J0 B; l/ [8 n/ i. n326 T4 @. @& f  g% v5 n
    338 [& v/ C; l' O' {# T* g
    34
    1 \& L* {+ w# s. C9 `. s, `35  Y1 T% a2 B' k( u, R
    36% G/ v: O3 g" x. N2 g
    37' X( h: @1 K8 P  v! n1 b6 c  [' _! a
    38
    0 ?2 n4 U8 l9 p0 M: y/ D" {! S397 g$ t! a% B- s: z" w4 {
    40
    / Y- t/ H5 J7 ^: k9 ]7 N' ?- ?41
    * a" {3 a, c1 ^  Y425 r2 x6 x/ K' }4 Z' e
    43( F) S& t8 _% n7 s6 g3 O( F% o
    44
    / {  r7 t0 I8 m; T; g4 K3 T: P45
      R/ D4 @4 a+ L( ?% m+ M46
    + _4 q5 S* b( {2 u! F$ n47
    * V. `7 q; b- R483 d* {1 r$ {+ x
    取消动效6 q& w; {& V6 z" [2 J% ~

    ; }1 [8 U( \# E5 F: d7 @// 组件销毁时取消动画- b1 G0 q, g% ?6 `4 i
    onUnmounted(() => {( {4 |0 w- J8 N7 w" M
      cancelAnimationFrame(state.rAF)5 F' C  Z! X' R; F( V
    })
    9 f, D0 N3 u& k( ~. o- M$ j1
    " E1 ~4 t1 ]  m5 S" t3 y2
    # u0 p, ]3 @2 F. H- p* c0 u9 `& q3
    7 w* Z9 i) _6 i' S8 Y* ?4 {47 S, o) w: e2 k; U/ w' w
    完整代码* h% `& `- F/ g% h, e+ e- x" p
    ; F' `% ~% L6 T1 ?: O
    <template>0 t  K* H% m) @9 @' I' ~# u& w
      {{ state.displayValue }}: B. o* W( \( P  Y
    </template>
    , y2 [2 [: F5 k0 Y/ N: t: ~0 L: p( A3 T4 b9 A
    <script setup>  // vue3.2新的语法糖, 编写代码更加简洁高效
    9 |7 l1 r+ R! mimport { onMounted, onUnmounted, reactive } from "@vue/runtime-core";% b5 l  u7 a0 c; K+ ]
    import { watch, computed } from 'vue';/ g9 R% g: E- T1 G
    import { requestAnimationFrame, cancelAnimationFrame } from './requestAnimationFrame.js': S' g& s+ m% V8 z- d( `
    // 定义父组件传递的参数$ a! Y* Q' X! n9 q2 {' x/ V
    const props = defineProps({6 @3 G" s- w* X$ t+ U( A
      start: {
    $ {- _" q. p7 }) e: T    type: Number,
      A$ N0 y5 x% K' z( \! P4 v- t    required: false,. J8 t$ H3 O* f" j9 ]4 ^1 a# k
        default: 0
    5 P+ Z1 p+ h$ c  ~# H+ d  },, t6 {: M8 S" p5 H4 l7 s) L( N
      end: {. f, O; ?% J/ r9 M- O
        type: Number,: x. O4 _: v+ E
        required: false,, _6 k* j/ c8 r/ }
        default: 0  ?; G1 `4 _; W$ r- Y7 U
      },
    , ^" x( H1 T2 S2 E( E9 D% b3 C& w  duration: {
    # X/ j/ i3 M9 g6 g1 g    type: Number,# w; Q" M, I/ V. O) x6 a( @
        required: false,
    " f; w8 T6 F" d( _$ `+ F/ y    default: 5000
    ( g" ]1 d( ^% A/ m, u1 K) v. v  },
    $ |( C$ J  h% a/ w" r# X  autoPlay: {; y! k- `" d8 T
        type: Boolean,
    % f1 [! G$ N( q) f    required: false,- T7 t5 P/ [; T6 Q; F- F
        default: true1 ~* \' o" K' ?( ~0 P1 G1 R" U9 n, ]* c
      },6 K3 L" b8 I$ I  T- q1 W7 g2 c
      decimals: {
    ! M6 v1 }0 z7 e) M0 R9 ~  n) y1 P    type: Number,$ a6 g+ s3 O& e: z
        required: false,  D3 G1 T' u( l
        default: 0,
    & N- R5 J+ E3 k    validator (value) {1 M5 `4 P/ s/ ?  }1 S. B
          return value >= 0) V4 C, z/ n+ A8 B! v- w
        }
    + p( T. e  D- B/ f  D4 n$ j* \. a  },4 q( l3 ~9 m, C2 S5 ]
      decimal: {
    9 @1 p6 h3 Q7 }% C, Q5 E    type: String,  W* D  b3 S/ Z% q- a; C) \
        required: false,( P, a) @1 y, M3 }/ h- X4 D
        default: '.') R; Y, _0 V. o: q+ w. m# n" {& v
      },/ n# j+ B  R) [6 L* d; M8 @: i; m7 {
      separator: {
    " w3 v8 ^  ]$ j; k5 F5 r, j    type: String,
    . v  Q$ v. s9 W, {$ y/ `    required: false,( ^% k- _2 y. \& x( y- q/ L2 F
        default: ','
    5 i% X# l, B. @  }," L; i$ m2 Y. Z. N8 i5 p8 b
      prefix: {
    6 J. c. B6 G# V2 i8 N    type: String,6 j+ m  u( f7 f
        required: false,
    0 \3 _8 ?6 {# v6 c: W    default: ''
    & p; I: f7 ?) r$ _  },0 ?+ p2 O% V6 }5 F7 e$ u/ w
      suffix: {
    . N+ A! [* L- v2 e2 I* {: V    type: String,% C$ G1 q5 [% p2 C
        required: false,; U5 C1 I, k, I+ G) r- L* W+ ]
        default: ''( h* i4 ~2 b& L0 [) d4 }( M
      },: `2 s6 X+ x: x' J. C: d- W2 c) E
      useEasing: {
    - W" S6 A8 _- o4 d; j- _# c    type: Boolean,
    . C( x4 v- t) c) _0 l& q" e    required: false,
    ; e4 ^5 `2 }4 W. c, f2 l) D$ M% l    default: true
    1 {& ^& N" a  B7 Q$ H  },
    " W0 s. `' f& H5 [( y/ G, \: q9 H  easingFn: {
    8 _& R  R; D: V5 `6 q' [! I. V    type: Function,
    2 ?! G$ X5 T! w7 i    default(t, b, c, d) {
    - f/ C% E6 `( }0 D3 _      return c * (-Math.pow(2, -10 * t / d) + 1) * 1024 / 1023 + b;# \' K( \( r1 V3 L! }; z
        }3 B/ c0 z2 o) C
      }
    3 D. t  H' ]$ x3 d( W})' U8 V6 W8 a; E* }0 Z& `3 O

    . g& d, M3 M! ?: g6 ~( [; sconst isNumber = (val) => {
    1 F  O, L5 _8 X' [! h% ~% `1 t" ~9 o  return !isNaN(parseFloat(val))8 Y2 ]8 O* p2 K) Z# u
    }( \$ V  x: C5 w' z
    * l$ U% }# ?- r) T0 ^( Y" c
    // 格式化数据,返回想要展示的数据格式
    1 Y, v5 Z* |4 l& p' {3 Bconst formatNumber = (val) => {$ M2 M9 E+ h6 l2 r. j# R
      val = val.toFixed(props.default)
    1 G$ \9 r  U$ I) n  val += ''! M: d4 N8 q& ]5 n
      const x = val.split('.')
    * R3 j4 c" {3 h. h  let x1 = x[0]; L; y7 k9 f: r: j$ l& \% G
      const x2 = x.length > 1 ? props.decimal + x[1] : ''. H' [0 O4 t/ U8 t) E7 ]4 a
      const rgx = /(\d+)(\d{3})/3 b' a6 \- f/ Z  h- |: u2 F# E
      if (props.separator && !isNumber(props.separator)) {+ {0 h+ B: S) D: T; ]  r, F
        while (rgx.test(x1)) {
    - q! s  @* D/ Z: ]. r      x1 = x1.replace(rgx, '$1' + props.separator + '$2')
    7 w  {/ G* C- _. r( o    }5 K( B7 [3 P3 X9 R: a
      }
    . q, [0 ], p% w8 R  return props.prefix + x1 + x2 + props.suffix
    4 r* Z3 @5 R# r9 i( e2 m- w}
    * Q: p8 p. e8 i  a) j+ q. M* @  O3 @8 K$ Y3 h
    // 相当于vue2中的data中所定义的变量部分* N, L5 M9 Y( ?4 E  z$ V1 F! Q- p
    const state = reactive({% n  \$ g* G4 Y, v0 z1 `- D) H
      localStart: props.start,
    ; L) L) G: i- u' x( h  displayValue: formatNumber(props.start),
    * x+ q+ J8 [5 D& }; d" H, K5 H  printVal: null,
    7 \" S2 O9 o) t' e, I1 m  paused: false,' l8 \% O% k, m( e
      localDuration: props.duration,
    1 b9 L# a9 U9 r# v# s: f0 _, u; v  startTime: null,9 u' V% i$ v+ {& ^
      timestamp: null,+ o" o, R4 P+ S1 p9 v; [& d
      remaining: null,9 v. o2 X# ?( P2 ~- l+ w9 F% X+ I
      rAF: null8 M' J1 c, \8 c* a
    })* `. @+ Y( T" Q, l' i4 o
    / @5 ]" I, s# u0 g# g
    // 定义一个计算属性,当开始数字大于结束数字时返回true
    8 e8 F9 D$ k4 r3 n- U' A7 t' Fconst stopCount = computed(() => {# K9 U; \' m: s# p, ]' U0 o
      return props.start > props.end1 k% `( ~1 V7 V" A; e
    })
    & u7 T) V: g: l( B# p- t+ {// 定义父组件的自定义事件,子组件以触发父组件的自定义事件
    6 O2 ]3 {8 [) _# \& b2 N# S1 Aconst emits = defineEmits(['onMountedcallback', 'callback'])) m, C. M2 Q1 W
    $ r/ L* K# I! p: _, [4 p( \8 C
    const startCount = () => {
    3 W) c8 U$ P* L7 G  _  state.localStart = props.start9 @8 O4 l5 N! _1 I7 S" y
      state.startTime = null9 X4 i( U+ t; ~# |3 M
      state.localDuration = props.duration
    . a( W6 _1 Z9 O  state.paused = false$ ^- C, m- }* [) i
      state.rAF = requestAnimationFrame(count)
    + h8 I( F) h  B7 X. T- K$ v}
    % W& d% o0 s9 P# `; w0 W& F* ~. f9 P9 j9 F1 q4 G4 k
    watch(() => props.start, () => {
    5 r$ h0 c1 t: o6 L( V  if (props.autoPlay) {
    , X" M- m3 w1 q9 P- p    startCount()
    ; y7 g+ N! g. {8 N# B& t  }
      u* ]& `2 Q! a, _6 a}), j) u( `- S, P: u4 z$ }: I

    / R# a6 x9 G/ J3 T: i5 M) ^watch(() => props.end, () => {
    . k/ u3 a# N- s, W4 g8 \  if (props.autoPlay) {
    ; e" {: H, A2 A; s    startCount()
      N! j3 Y% s4 J# u  }- C  u4 i! y1 v& E& B# v. i* U
    })# T2 {4 C6 d7 z# W% W3 ]7 Q) J
    // dom挂在完成后执行一些操作7 S- K$ u$ E+ t. i0 Z& E: \
    onMounted(() => {; [. M6 A7 H1 }4 O  m  e
      if (props.autoPlay) {' z1 _6 \8 S0 a  X$ V% j- H. Y& Y1 q
        startCount()
    4 L0 m9 l3 z4 Z/ b+ }  }
    : m+ K. G/ h5 q  emits('onMountedcallback')3 [- q! j4 {  j1 f6 u# h
    })+ n1 `% P: z9 P  R' e# M
    // 暂停计数
    # {' C! }  C) B1 M- l2 sconst pause = () => {
    ( |- _% S9 A* z* S+ \  cancelAnimationFrame(state.rAF)# J9 N& F; }. V* b$ @7 n7 A
    }' @& ]9 e  t. b. j6 J; o% u4 p( O7 O$ C
    // 恢复计数, s9 ~5 @) y8 r/ t2 V
    const resume = () => {: Q, O* ?7 [+ `9 l
      state.startTime = null# w- K* v/ E9 U9 x; g
      state.localDuration = +state.remaining6 S  I- [: `0 q7 O) s- z" z" ?% B* U
      state.localStart = +state.printVal) y- O* E" w$ `
      requestAnimationFrame(count)2 L, q- u4 ]4 I; `0 E6 y. u1 V1 M
    }
    3 {! n& d2 l5 }) Q! r2 j+ ^5 T7 G3 b% u! T9 ^7 o6 Q
    const pauseResume = () => {( m6 v( T. Q4 f
      if (state.paused) {
    # I- d# N7 z! C3 d  u$ T+ p0 M    resume()) H5 U# ^1 P% R, q+ p  C
        state.paused = false; M3 |$ \0 f3 D, T4 w+ P
      } else {
    2 k) `$ U! ?: }: @4 a2 f    pause()
    8 u: N1 X! x  \8 n2 @% }    state.paused = true% Z3 Q% c& y! h4 L. o9 p+ Y
      }  V: c. _- |: X* {+ @! ~& D7 Q  [
    }% u! G/ A7 ?3 I. n

    1 V" e% O: ~* f7 C1 }const reset = () => {7 r9 B- x& u, d: S) m6 P
      state.startTime = null
    $ Q# ]$ l) J' v) i  cancelAnimationFrame(state.rAF)  n9 ?; Q, N7 O, E3 W
      state.displayValue = formatNumber(props.start)5 g5 _1 x( e  w' Y) |& l
    }
    2 b, d$ S, I; l+ E: d, e5 E" l& M: t
    $ `, U3 x% a+ Aconst count = (timestamp) => {
    7 M  P7 J1 |5 K- X* h" Z( L: i. b  if (!state.startTime) state.startTime = timestamp
    3 T" k$ F+ r$ b  state.timestamp = timestamp
    , M( R5 h3 a8 t7 o. R/ l  const progress = timestamp - state.startTime
    + g# g% z5 x3 N! e" }  state.remaining = state.localDuration - progress) G( b- U9 Z) g$ q( u
      // 是否使用速度变化曲线5 W& x& S/ b/ a2 E4 f  f  U
      if (props.useEasing) {1 K3 u8 O; J& j$ H
        if (stopCount.value) {2 ^1 r/ W1 z' ^, B, l
          state.printVal = state.localStart - props.easingFn(progress, 0, state.localStart - props.end, state.localDuration)
    # @7 C$ g/ d) t. q    } else {; r! n9 g1 |4 U) S; h$ g% Z9 E6 U8 P6 i
          state.printVal = props.easingFn(progress, state.localStart, props.end - state.localStart, state.localDuration)4 |5 r% r% B2 \( g" m, x. Y
        }8 Q; ^# P9 v5 P1 B  e6 m
      } else {9 E; l1 @. l% q& |  L7 {
        if (stopCount.value) {4 ^0 F( T, w, r' U! @
          state.printVal = state.localStart - ((state.localStart - props.end) * (progress / state.localDuration))
    9 X% J: f$ G+ c& u& J& G( W) @7 \    } else {
    5 B3 r# I% m8 T1 F6 i% \      state.printVal = state.localStart + (props.end - state.localStart) * (progress / state.localDuration)/ |: n0 o! A4 P! t& g
        }, C4 E4 T1 r$ ~: W; z
      }, o! }" X' \+ k" r
      if (stopCount.value) {
    7 h5 U/ M  O# s2 V% p    state.printVal = state.printVal < props.end ? props.end : state.printVal
    ) k- f. A& S8 a* O# C& m; r  } else {  ^4 k* }9 y( z5 v  }' @
        state.printVal = state.printVal > props.end ? props.end : state.printVal5 E1 s0 T, s5 c! W: f" q$ V6 g
      }
    + r$ u  O& {) b+ ]" G, j) w  N
    ) g! ]# o/ ?& [, s1 c" t  state.displayValue = formatNumber(state.printVal)6 Y# s, l3 v: n8 `8 V, p
      if (progress < state.localDuration) {
    $ m. H+ q3 b0 L& K    state.rAF = requestAnimationFrame(count): }3 o. q  t; S- L4 g
      } else {
    5 \* s6 m. Z. D1 ^* z    emits('callback')# K, ?( n+ b! j" k$ D0 W
      }
    * K: d6 N& n% W" O) Q6 _. x}0 u1 s: \# ?6 G
    // 组件销毁时取消动画
    9 C9 S  |- m# z+ @% honUnmounted(() => {* z6 O- l5 P, a( ?* D
      cancelAnimationFrame(state.rAF)
    / f% }( V, G1 |7 u' ~})
    " Y& R+ ?" g* l1 @+ V</script>4 c8 O9 t- m- b$ s# I: L5 c

    8 C" Q6 \! @, o" o7 I/ J1
    - ?" S0 `( [9 a0 l/ `% K# h# j7 r2! ?) u# e/ n( Q/ n6 Z0 a
    3. ?: l1 D" ?9 ~( w6 \3 U2 h. ~8 `
    4
    ) D& C) \0 @# E: C* Q% f/ x+ X7 m  E4 {5
    , E  Q% Q: N3 _* P" q% J66 t( a0 S- ^# z$ w7 r6 K4 O, r
    7
    ; x8 M, g0 H6 _0 F8
    . X' U7 l4 Y4 r$ n( r4 y# x. g8 d9" c6 v; P( u- ~( {9 [% [3 [% V) E3 d
    10
    0 E* b$ r9 v/ _$ q) h11
    * A4 v+ N* w1 R/ r$ a- v3 ~. r12
    9 B  ~- R4 S1 X2 }0 `( l5 z* a13
    , }. B9 o6 Q1 Y14
    % t6 N/ {$ G' J15
    5 r' L$ J) O6 l6 [. ?' c166 S6 P4 p+ i$ G: H4 P& u  ?+ S  G
    17
    - c7 J  ?- N8 P5 T5 X6 d18
    + J4 q+ g3 U) ^7 [+ Z6 }9 c( f19- K; U7 a# `- f  @6 m4 x
    20
      w: [0 p' H1 m) ~  l21
    4 q: P5 x- L4 A) l) [) k22! p) x& s& z4 P, v! ~$ i8 A1 W  |' k
    236 ]% W' P: w/ l% N4 Z
    247 E# S2 a' h4 K$ c
    25
    ' l% g# ^  G9 @+ L; A26
    & v) h+ S- J0 b" R, O9 d27" h0 w. O* V2 N2 V$ M4 Y! v" T* e
    284 q  U5 m& @4 Y7 s; v2 v
    29
    9 L( _- `# n, O30/ g8 v3 w/ A& ]% K/ v, T8 k; W
    31: {  r3 y# h" O& X; i
    32* H: ^) W& I9 T7 F
    33
    . C/ M* {4 Q9 F5 U& m% L9 \3 ]. }34
    4 R; b1 R& q) I6 `9 s  O& g35* A5 V& {1 b0 W0 I
    36
    : Z: i: U& }2 E( v, p37
    / E  K5 b- m* P" s) f/ ^5 m38
    0 r; o$ h0 M; W395 [- R7 m, D+ y1 k3 Z# U9 u! p0 h" C
    40
    , w: \; ?5 \7 M8 M5 J  Z411 x( e" Z; @0 A0 t. h
    42, s( l( r" m/ K+ h
    43& v# L1 j+ S1 V( I5 Q9 g2 t/ n
    44
    5 a( `" V: y, G$ u; V* i0 [8 _7 p45  X& @6 |- {3 J; X) q8 `5 d6 u# D7 D. ]
    46
    9 x. [! i0 s1 r& u" t+ O' h47
    ! }& |+ j6 v, ~1 [) f1 f* q48/ I5 X/ j" ^! ?' q" C
    49
    / G  j- H1 H/ B+ L50: ~2 H+ ?: a# |" F! I
    51
    3 Z/ R" z3 ]8 j, U  ?52/ f0 ?" G! K) \( \* _* f
    53* w. e+ }5 f! p
    54
    ; w" T/ V: X4 k% B: }3 k6 V55
    / z* E/ M9 ~+ y568 X( R- j5 n: e7 M2 K- _) h
    57
    ( W" w$ Z) y% L2 P58
    4 v8 K" m$ N) S: z% h59
    4 b5 l6 _4 P3 C+ u! @60
    7 J0 h2 s8 p: n2 ]" W# }. o61
    2 p$ K1 g% M) Q, d625 n* h+ N: j# \
    63
    3 i  i" g  D, q4 S8 P( h645 y1 R$ H+ T; g; W: a) Q. N
    658 z  ~' i5 ~- l% `+ ?
    66
    ) \) u3 m! `# o( O) u67% f2 c& J1 z2 Y' r  z
    68( S4 a. _0 x; k# N+ F
    69
    & u  }3 ?& l5 K2 u- `5 T) ?2 j& O70
    & y+ j: h' K6 K+ D. U" K71
    5 r! b$ y4 d# _4 y$ w8 y! h& o72
    " ?* p" t0 u+ Q0 E6 H3 i6 Q734 P4 e& ^7 x2 a# j% W' p2 s
    74
    8 b% o% p3 f2 \0 e6 q* A4 s1 r75
    ! v  ]& m- a) k4 {3 ]9 m) _9 r76
    + D4 T" J" S2 {77
    3 l; E- q" e7 y- T6 n78, {+ G& N: q0 b4 N- k" e
    79& m* C0 N/ w  r7 A+ V" N
    803 Z- Y; m" d6 |- ~0 V
    81
    0 p4 A- l& z. W7 `* }825 H2 z& |. V" ?; v
    838 l+ K6 L# r8 h0 f9 \/ ~# t
    84' D" n; }9 e9 d* W& V6 O
    856 h$ T9 H4 |8 W% l* L
    86
    ' p3 V7 Y7 _6 ^4 R87
    3 M, v, D  ~2 u3 `: l/ W# f88
    + ^7 v# ?4 T/ ~7 n. K! W  x89  |. i+ S  D% R6 T
    90# h2 U4 h# f8 i* ?& |  q
    91# [! _# a% F/ P  c+ S; _4 o+ K
    922 o( n. n5 h. ^! o, g, [
    934 J7 ~1 ]7 r- Y' H& `
    94/ r, R8 k0 \1 ?% D2 r  F6 U0 f
    952 N* e, ?' ]" V
    96' P) j% M% P& r  N; k
    97& T) ^0 y) c8 @8 i- x" d. y  E+ y- q
    98
    : S$ D+ f8 i2 {' z! a: w% d2 e6 C998 C! @# F( I  `/ Z3 s
    100. Q& Y: I# z5 |" X
    1019 ^8 c2 x3 s2 U  a" n- [
    102$ e; K4 x3 z# u) z2 R0 z& z0 I
    103
    7 U5 K* ?+ t8 X2 }/ Z104
    ; P! R6 e: ?9 R5 c1053 Y- V  Y4 v* N" H
    106
      R/ _4 A, A% X107
    1 Q) R2 y8 |+ J108
    # O+ S; G: u" Z$ }" K1 [" w* L109
    3 D8 _( Z7 }$ n/ |' J9 L110
    0 m* m, Y  q: B! V: Z111
    % d, A) p) z$ M/ e: W; n112- n8 ^% z+ x' ^2 ~0 ?
    113
    0 u( m' G) V) l1 {114
    2 C* G) B$ _0 U115
    6 i* o, C: L3 L2 Y6 I116( l( }0 j, ]  z& C9 `4 p
    117
    3 o, g5 u4 e" K( y  I) i118
    2 l' ^2 [+ Q) g$ h) f( c119
    ' q* r, c7 `& K! C6 `1208 h" A& e8 O" S  E+ U- E
    121/ y6 z- N/ t2 G4 Q0 U3 a- v
    122
    4 O0 X! y6 N: _  K123* H" b* U) R1 O+ ^! n9 E
    124
    0 R1 d; ?6 k& b# F% v5 x0 z125% \4 _3 y& ]/ i) T( P
    126
    ( l( `- f$ R- l127
    / n+ I4 o/ }  o6 z& T# F1 `1 c8 |128% m) `5 h* `/ O
    129
    / u; Z% g: W/ ?5 s130; ?9 E8 H2 y! L. N/ B& M6 N* x# U, y
    131
    8 Z  m: k; h% l132, d  \& M9 X  _) W
    133
    / n, F! o; g; }% M0 `1 @; `" J134
      n$ Y) R3 G- L$ x. X! _135. h% n0 `+ e/ I
    136
    & b. P, B  Z. {$ d2 \137  ^: C$ {; |7 A/ q0 w  y. ~( @% v
    138
    / s! `- N* ^4 q$ f; s6 h" G1 K139$ y  _2 t: e# A  P/ m! {; R+ Z! f
    140
    . H  r  k5 r9 _7 b1412 `8 |: Q; K+ \
    142) R: L3 {/ _3 W7 P% D9 W* e
    143# G9 E+ l7 J2 r
    144
    8 B1 \6 z% s- o8 a; m6 e- E) r145, }( Y7 f! U% @1 |: L  ~) L. o, C
    146
    3 y& J8 q" S. B* I! x147
    : R) w  T/ d" ~+ b* e148" I+ [0 e: G, L/ D) ^
    149
    ) A2 f1 l4 j& d/ }. E5 y" ]150
    * R/ a+ e( X' y0 r- P151- Q% w$ f* S5 r9 ^* X, C: u) {
    1529 S  s% E. N" g$ Z# s0 y6 x
    153
    $ d& u$ _0 e3 }  [/ u, u! f& y8 H154
    . H6 |, W; v' P. i1 S$ C4 T155
    " O1 b5 R% l/ D5 K$ p156) T1 t  Z( I; B" i7 I* S  D
    157' W) Q9 R! U  g
    1588 b4 ^! N  N' g
    159) M0 J( x; H+ J( A. w" Q
    160
    2 g6 h# R) V/ H$ k& O' @5 x161$ U2 ~- p3 Z7 q1 {2 ~) u% M$ @$ P# H
    1627 B" \9 ~6 w3 i
    163
    5 R, q4 _, Y. ~! n  v1647 G+ C, r+ l, S! A/ X+ w& e3 D+ F
    165
    4 u0 M0 x: v  P5 s+ m+ j" ]166$ n' b9 W3 T% ~2 V0 @1 ~
    167
    " h& O6 y: [5 I' t6 c9 F& U168$ k# q, T" {, s9 y2 ]2 V$ v
    1693 m( m9 Z8 [2 Y5 g3 v
    1708 N* J  \" n& F5 ~
    171
    2 v8 `8 f: b. N( f$ Q8 S2 r172' H  i5 c% U8 O- M
    173; P5 ]" l' G9 W* F: p& g
    174+ O6 w( L+ S* ~) {. Y9 F9 o
    175/ N7 ?3 z2 `& g2 ?' c! X- U
    176+ w1 ]2 o3 m/ u
    177
    : _: ~) k$ w0 @178$ ?: m- ~5 g( z3 P
    1799 m+ w, w, S: s0 @2 z
    180
    : e, I) N: z! _) s. J" j181
    $ r8 C0 m% f. z  M182
    9 ]5 e8 E6 e# m$ O3 }183) s4 j; }$ @  I
    184
    + f8 T4 I: R( E185# ]+ ]6 g) M! Q. M
    186( Y" o' a  T' Z3 h8 o+ Z
    1872 n# U4 R0 m  F( t6 `+ X
    1886 O; e- e$ K6 d2 L9 ]
    1896 c: E7 ]' D, h5 s) Z. C" o2 Y
    190
    6 q0 ~2 g# ~, w$ n4 v1 ]% i191
    # j0 Q" F1 }4 f1928 F  b" U  K1 h
    193
    ! s2 X9 q3 Z: T- Z' K' ?) v5 A% g, e194
    $ S7 h6 W3 L% R4 H7 @1 H  }; ?) ~8 |195
    ; F* N# p4 m7 j( o196
    ' m  [, s# p" h4 e5 ^197
    2 o- L. ~* }' V8 W; R  y, a# _9 E198: o' [0 t; _1 t! z! w1 X$ Y$ ?* d
    1992 V. s4 D$ h7 \4 P
    200
    9 U5 S  V1 C- G( \201
      S, X) W" `& r5 _# n202
    * I! n: W+ s) a, X+ B; Y% ?: I/ }总结* x" o; O: S" W
    自己封装数字动态效果需要注意各个浏览器直接的差异,手动pollyfill,暴露出去的props参数需要有默认值,数据的格式化可以才有正则表达式的方式,组件的驱动必须是数据变化,根据数据来驱动页面渲染,防止页面出现卡顿,不要强行操作dom,引入的组件可以全局配置,后续组件可以服用,码字不易,请各位看官大佬多多支持,一键三连了~❤️❤️❤️
    , E; `  m, t( {. l$ I
    ( B7 ]3 _% T: k% P' A* ]demo演示, i; z; D- _( J5 o- F+ M
    后续的线上demo演示会放在* C6 I3 Q3 t% D* i/ b3 @2 C
    demo演示
      [! T$ O1 m: f+ A完整代码会放在: E& U+ ?# ]* w2 L
    个人主页1 v& d# T/ m7 l, A* Z2 F+ Z  p

    & Q4 x) T, ^! L4 P1 l希望对vue开发者有所帮助~
    ! [- R4 p5 u; E: W0 d$ l
    / v+ c7 s! R9 d$ b& Y2 X个人简介:承吾4 w5 }6 _1 d& d& n
    工作年限:5年前端
    5 ^, M8 B% S, x1 l* |9 |地区:上海
    * j1 I6 n: l+ D( |个人宣言:立志出好文,传播我所会的,有好东西就及时与大家共享!
    . M) w. J! \3 b+ b, X. ^
    : d* \; c% j: `' N+ [) i: a2 s+ z9 Q7 o* q* D" s

    7 }+ }. F& o+ S$ P8 V0 r2 a$ `& ?2 k) E: t" Z1 E0 u6 g
    ————————————————
    2 m+ l) Q' I/ ^7 L2 g版权声明:本文为CSDN博主「KinHKin(五年前端)」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
    - ^5 ]' z, ]' Y: @原文链接:https://blog.csdn.net/weixin_42974827/article/details/126831847
    . Y- ~: }# u# \: c/ X: a- B9 ^( i8 I; ^
    ! U! ^/ ?+ L' x* L& ]
    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, 2025-6-2 18:15 , Processed in 0.507766 second(s), 50 queries .

    回顶部