QQ登录

只需要一步,快速开始

 注册地址  找回密码
查看: 3842|回复: 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 | 数据可视化实现数字滚动特效
    4 C( H2 j% I0 [" z; k. n3 a& r  B4 p9 E
    前言
    , c/ R% q9 i; Y' V/ n2 k/ lvue3不支持vue-count-to插件,无法使用vue-count-to实现数字动效,数字自动分割,vue-count-to主要针对vue2使用,vue3按照会报错:; m9 d+ D5 v+ N
    TypeError: Cannot read properties of undefined (reading '_c')
    8 q. \1 s( G) O  R  Y的错误信息。这个时候我们只能自己封装一个CountTo组件实现数字动效。先来看效果图:$ B' w/ M3 h, F, i" b; n
    * l- }! E/ K6 B, b( q' |% Q

    : v7 h. Z$ M1 f: J$ m  p思路" g. K: _( ~, ^$ P6 c1 `% }+ [
    使用Vue.component定义公共组件,使用window.requestAnimationFrame(首选,次选setTimeout)来循环数字动画,window.cancelAnimationFrame取消数字动画效果,封装一个requestAnimationFrame.js公共文件,CountTo.vue组件,入口导出文件index.js。3 S4 ~1 ~4 Z' t
    & ]6 M  k% E+ W1 G$ D5 U% q
    文件目录) L6 L% E6 w( p6 t" d) q
    ; w$ ]5 f2 U) G' x/ r

    5 C# v6 Y" u' Q, _+ n使用示例
    4 R0 T+ s/ F, Y6 s2 Q/ H6 a5 F, e<CountTo
    + z6 u( B5 Z3 A5 i :start="0" // 从数字多少开始! E  C# B( Q% Y. N- }0 U
    :end="endCount" // 到数字多少结束6 j- m& i, H3 v! c  G' v7 ]) i
    :autoPlay="true" // 自动播放; m( g* R+ Q2 X
    :duration="3000" // 过渡时间$ a  F2 y6 L: g! g6 G# D5 Q2 ?
    prefix="¥"   // 前缀符号. U( H) n. N3 K9 |, J6 |
    suffix="rmb" // 后缀符号, W6 Q" e  p/ P( |4 _
    />
    $ [3 t5 H+ ^" I2 C6 w- o' @1
    . }+ {  G; `( J$ h4 W( Y2
    - C9 Z7 _6 [2 d' E1 n$ k3" g% H" M8 P+ ?! |; `
    4& l/ Z$ A4 Z& g5 K# J, t
    5
      m- ?4 L7 a% b* n! ~# D- v6
    & R6 E) z* R9 S7 o, S7
    . E+ U" J% X7 D6 Z: V8
    8 w0 Z- T; C) R% y- c, ?5 N- q' y入口文件index.js
    6 ^, I& a: t  {% b4 y
    ! t* f5 ~# s5 O# Q: ?const UILib = {4 b& k$ f. L+ O' E/ S5 C- C: w1 \
      install(Vue) {
    # \6 {, r6 V6 H) o( [& P9 J( J    Vue.component('CountTo', CountTo)
    # @' B$ {, k/ |9 w  }& w1 [$ D% i# R" p7 J" b: H( \& [
    }
    " O. j) _% z% J# K, X6 E! P: z5 V  u7 ^8 u$ Q5 `+ N6 }
    export default UILib
    7 P7 C5 w' S* l+ v( x* ^
    $ z( {* F% q. y: `! ]0 u! l1
    3 p1 Z2 P/ @4 j. @- S9 P) h5 \2
    $ y9 K3 k6 P, j$ Z31 W0 L2 z& A+ \/ }1 _# v
    4
    * h' w3 G: [7 }5! b: X! Q% U3 S! A" o% U
    6
    * U5 }7 s( S# }. z$ `2 W6 U7
    5 y" Q" e5 ?4 W% L8" a) i7 z; f0 E
    9
    1 t) r0 t3 l4 u; H9 Zmain.js使用
    / \& X  j0 v( S# d! v) iimport CountTo from './components/count-to/index';1 I. j/ x; @2 b* S. O
    app.use(CountTo)8 u$ V7 C; W% P
    1/ y$ o2 y! y& J# w
    23 k+ u. l: T* p
    requestAnimationFrame.js思路
    % r- G2 S: \7 A6 A" f先判断是不是浏览器还是其他环境9 N+ G  H( o1 ~& R& N
    如果是浏览器判断浏览器内核类型
    $ p) k( {. x4 d0 C& z& `" h如果浏览器不支持requestAnimationFrame,cancelAnimationFrame方法,改写setTimeout定时器
    + u, T' U% {, ^5 n导出两个方法 requestAnimationFrame, cancelAnimationFrame
    6 ^# g" {. t: J, h, a: g: e各个浏览器前缀:let prefixes =  'webkit moz ms o';
    4 G. J& a" ]! T$ y' o判断是不是浏览器:let isServe = typeof window == 'undefined';
    1 T: q2 J+ x/ A9 Q: W8 g2 l: e增加各个浏览器前缀:  $ F3 @7 ?0 m0 A6 P( K- l
    let prefix;$ K/ f4 q7 o6 S# K: L  m1 {
    let requestAnimationFrame;
    4 y  b8 `! y* }let cancelAnimationFrame;7 k4 m3 ]( q$ Y
    // 通过遍历各浏览器前缀,来得到requestAnimationFrame和cancelAnimationFrame在当前浏览器的实现形式
    # e; n9 S) Y9 q1 x3 r2 Q8 `" G+ V# ~    for (let i = 0; i < prefixes.length; i++) {
    7 O& u6 F' m" {' V        if (requestAnimationFrame && cancelAnimationFrame) { break }
    , L- o: r5 t' H/ e3 G" ~2 G        prefix = prefixes& c; _3 F; {& Q: E& a) W# y+ ]
            requestAnimationFrame = requestAnimationFrame || window[prefix + 'RequestAnimationFrame']2 |: x, H6 ~- _
            cancelAnimationFrame = cancelAnimationFrame || window[prefix + 'CancelAnimationFrame'] || window[prefix + 'CancelRequestAnimationFrame']
    & d2 @5 c" n+ O. S    }( h; v6 x8 l5 m; {

    1 p% N- I8 G% b- e  //不支持使用setTimeout方式替换:模拟60帧的效果# m5 P4 S% \$ v3 h+ n
      // 如果当前浏览器不支持requestAnimationFrame和cancelAnimationFrame,则会退到setTimeout0 A& P7 q6 n9 R: |8 \1 g$ k' i- I& W+ W
        if (!requestAnimationFrame || !cancelAnimationFrame) {% k, u3 w( w3 z3 r1 ]& O
            requestAnimationFrame = function (callback) {4 o1 l5 |) S- P7 U- C
                const currTime = new Date().getTime()
    / M; y9 W% F) A/ G. B- Z& F            // 为了使setTimteout的尽可能的接近每秒60帧的效果( S* p' n; z) j2 r# O( P
                const timeToCall = Math.max(0, 16 - (currTime - lastTime))
    " w/ f$ l% ^$ t$ j. [* m; z            const id = window.setTimeout(() => {1 u1 V! w' ^( q0 [
                    callback(currTime + timeToCall)  I* ^- n, J& |* [# b3 H
                }, timeToCall)
    . H* a9 t* |# E5 _/ a* O            lastTime = currTime + timeToCall
    $ B3 O: ?! F' x            return id
      t: f+ r3 Z  l% q; }0 O        }- m& i% n6 V% T" f- N3 y2 L( t
    4 |' v8 c4 m* l5 s+ Q
            cancelAnimationFrame = function (id) {0 Y" M& c( x) b! b7 {, ~; v4 I  U
                window.clearTimeout(id)
    8 Y) z. c8 I5 U8 k! O$ {" ^: S        }
      W  \# B9 J+ P8 L0 d    }* Z, B5 q% f* m2 ^( G1 a

    , N: h/ B  a1 X7 g* k4 T; L$ r* j1
    2 G+ u" p7 @" n6 W! R: S29 J# a' ^: h( v! ~9 w* w
    3" P- o' S3 q; k" ~! k9 i
    4
    ( C% D7 o) T; H( b5
      G8 s: ]  N; s3 o2 \: E6
    5 ?- C* W1 q2 g6 v" R7
    + m5 a9 h1 {9 h5 {82 ]! u4 W- b& K* `: ?) l
    98 }+ Z3 m* d6 b& v6 b% T' ~
    108 Z6 ?4 v" o9 w: e- X0 x
    11* I# D5 A5 m, X  r4 U% L0 k8 H
    128 ^/ [. B2 _- t6 b; ?; [+ }
    13
    % P6 u0 N3 j& q' @2 V14
    " v: N& {8 O% O( ]# g  I$ z15
    . F4 ^; @- d* B160 z: j( [# s# h
    17
    7 a, @+ c/ U5 ]  S18$ s9 E+ v. q# g, Q* k. z+ I
    19, M, ]- Y  l/ d, q. y! p
    20
    : [+ \/ F; H3 ^21
    ! `8 ]7 u% N% e( S$ r" c22
    : _+ N" z( W' E+ b7 T23+ \/ C6 _/ X$ S7 T) a
    24# D" v' E% H: p% f  X: ]
    25
    ; j- l0 S1 k  ?4 R& G26
    2 W( k" K" m0 Q! P27" Z7 k6 L7 S7 G0 g' P: q3 U2 M
    28
      z; b- ~) N- m* j29
    8 ?) I- U9 P' r, g, Z30
    8 V! r3 Z3 \+ a! [! U31
    0 [/ n6 A1 Y. V5 I( d320 J& {" i' K% ^. s, r- W8 D, {
    完整代码:
    ; n! P) D7 v* D' q; K" S  ~# PrequestAnimationFrame.js0 J  A: B* f: s# i# k
    ) `8 a$ z1 o4 m9 R( h$ m
    let lastTime = 09 z$ v' s' i" V" N7 V0 W3 @
    const prefixes = 'webkit moz ms o'.split(' ') // 各浏览器前缀
      m; x  U/ X/ J1 x6 Z8 S
    . L$ ~( S: S2 W, U$ G6 P( y: Blet requestAnimationFrame9 x5 T9 l5 Y! o$ F6 G% h3 b4 A
    let cancelAnimationFrame- [1 c8 G4 B+ t7 V- F% M1 T% Z
    ; @* d* A/ z7 m# U/ }3 m7 b0 c
    // 判断是否是服务器环境
    * o. R( T) R$ K+ Y" b" u# tconst isServer = typeof window === 'undefined'
    ' s6 W7 ?) K6 y1 p  \6 nif (isServer) {
    # S5 Q* X( b! X( O+ E$ K# ?    requestAnimationFrame = function () {
    " D$ r' H: N0 b% \        return
    9 \, P4 r( i! ]3 w7 \    }  w, h* I9 N* H5 h: r
        cancelAnimationFrame = function () {
    9 h8 X& U+ G! t" e0 P        return
    " i9 x* K" ]- w9 X3 |" B    }* j- T) D& x5 l: O
    } else {
    ) g. E% w0 N) g4 |- j% A2 L  }* D    requestAnimationFrame = window.requestAnimationFrame7 a+ E, [/ J# R& y! d3 `0 X. b
        cancelAnimationFrame = window.cancelAnimationFrame
    8 G7 i/ I; j6 [% C, X/ e    let prefix
    ! U; j( S0 Y. i- {& [; i    // 通过遍历各浏览器前缀,来得到requestAnimationFrame和cancelAnimationFrame在当前浏览器的实现形式0 t+ v7 \% t4 F
        for (let i = 0; i < prefixes.length; i++) {
    + W/ x' V, A: @8 M) W$ H        if (requestAnimationFrame && cancelAnimationFrame) { break }) c% m1 D+ @# x3 Z. ]/ T1 m
            prefix = prefixes7 V* {% \7 e/ A3 c7 p3 |8 ]* K" c
            requestAnimationFrame = requestAnimationFrame || window[prefix + 'RequestAnimationFrame']; T+ a4 W  K9 X; K
            cancelAnimationFrame = cancelAnimationFrame || window[prefix + 'CancelAnimationFrame'] || window[prefix + 'CancelRequestAnimationFrame']
    % R, _7 c$ z- [    }
    : T3 {2 N3 H+ q6 Y: H0 }
    2 S7 O$ B% y- e, S) }' {7 H5 u    // 如果当前浏览器不支持requestAnimationFrame和cancelAnimationFrame,则会退到setTimeout
    2 v# {9 D8 z, P4 S1 |) L    if (!requestAnimationFrame || !cancelAnimationFrame) {
    % {6 [4 E8 S9 ?6 L5 E7 W5 f" ]        requestAnimationFrame = function (callback) {
    4 b9 {+ R! A) u            const currTime = new Date().getTime()9 x0 o7 q  w" e( Z
                // 为了使setTimteout的尽可能的接近每秒60帧的效果, G; l; A& q( t% x# Y" o
                const timeToCall = Math.max(0, 16 - (currTime - lastTime))
    & B( t' B+ s$ `1 t            const id = window.setTimeout(() => {
    ! u& i1 K) B  B6 d# K                callback(currTime + timeToCall)
    8 \, v: e- R2 G0 K            }, timeToCall)
    1 E* G8 O, n) X; [$ ~) }            lastTime = currTime + timeToCall0 Q2 P) E$ m) {& F7 |
                return id
    ) x8 R$ o5 N; }  |        }" I" n! b/ C+ s  |
    ! R. A% w0 h! z8 Q7 i
            cancelAnimationFrame = function (id) {
    $ ?  T4 {6 e; H8 v) b            window.clearTimeout(id)' p. d/ F0 s1 b
            }
    ; a7 ]0 H( H5 o# C4 X+ A$ y; L) z    }
    ' _3 X0 q$ T/ s3 z}
    3 p: v5 g7 d1 O2 ^$ S% M: D9 v& }! O1 f1 j* ~; q4 o
    export { requestAnimationFrame, cancelAnimationFrame }/ o8 q3 g5 l) Y, X# J( a1 M! v8 ~
    ( B' m- c4 r$ P3 T( Q

    , R  `' |/ S+ J6 _( r" f- N' U15 ~8 Q* M1 L, B. r5 j
    2: A6 U: p; f" S4 m3 E8 {) O+ X
    3! _7 n: _; @  E1 e3 K
    4
    ' ?5 u$ l5 g0 K# W4 }5
    6 Q7 [+ d. F; J, _6
    # S# N4 g) q) V1 c7# g: t& n$ X2 i- W" j  Y
    8
    . Y. W) b! e% u/ ~9 B( I( i9/ E* O3 X# K/ S8 g
    10
    4 j" O/ u  ^4 [11/ ]5 ^8 {$ t1 h8 x/ E
    12
    ; M- q, r* H4 n3 A$ k7 [13
    - i) {# K8 F8 d3 n  T+ X( g$ F$ D9 ]4 f14! ^  D: j9 c1 q2 F8 D" v+ \( t
    15
    - J# }% Q' k' c" Z; X16
    : r# Z$ n! T2 z17
    4 W& T" n, |  K* H189 Y- l( e: U$ P# ]
    19" h$ J; a2 I3 g1 |* N9 T
    20
    ) A4 N9 C" E( g2 B: a; E! h21
    % m) _) M+ X: l. q5 N- Q22  k# H3 o+ ^2 ?7 E& k* O
    23
    1 |. p2 @8 D' _0 W24, t8 e" ^0 M4 {0 O7 s% e+ B8 i9 K. T
    25
    9 x, Z" c% w! x6 g' P26
    $ `; X) x6 S, a6 ^! Z* `. b27
    5 I; f- B- Y& l: P28
    7 e8 r7 @3 x7 D1 k1 U" J" {29( h2 a1 {2 \0 v
    305 N# J" C8 W9 I# v
    31: X3 e( @6 t: \
    32; W7 h) s) \' f, U- u+ @( N6 a
    335 w" j0 H6 q; n5 [. L: l+ o$ B- k8 }
    34
    3 i. ~; P; ], C35* D+ W5 i9 |8 w8 v4 C, J9 c
    36) \  L" D& h6 E, _
    37
    1 R% `5 A6 @9 n. G  d, ]" k% H38
    ! \' [5 c2 `1 t& H( V+ ~" G5 ^; u39* V$ ~; Y5 Q, M0 e5 _: z3 X
    40
    9 J- ]% O# x; E3 v+ S) G6 N41
    8 a* d) s# [5 m. e2 `422 X- X+ _, b5 s5 m
    43
    ) |' {+ N6 J, ^6 m. G. Y3 C6 p444 b" Q- |- c3 K
    45
    5 K) b6 f+ t8 L* |( M46
    , X  p  i' J+ S6 C: {47
    $ [1 G0 Q# R/ @/ d+ Z( H: {( n48; i5 d# h6 o, `  ]3 @
    CountTo.vue组件思路
    1 |0 h9 v+ ?# K7 N/ Y首先引入requestAnimationFrame.js,使用requestAnimationFrame方法接受count函数,还需要格式化数字,进行正则表达式转换,返回我们想要的数据格式。
    . `& M1 E# w5 W$ u+ _) b' ~9 Z# `' l/ |
    引入 import { requestAnimationFrame, cancelAnimationFrame } from './requestAnimationFrame.js'
    % C2 g8 @* R* ~( ^3 {1
    9 u% X9 `/ V" H. @( @. [需要接受的参数:, L( {3 v& D2 w- b8 q

    , k1 J3 o/ j/ ^const props = defineProps({- g- `* A  r8 F, _
      start: {4 s+ g9 d. _6 N8 @% d. K
        type: Number,
    . W2 Q! H+ O% E7 _    required: false,
    7 [0 {+ J# t; A7 g9 X: x- V- v$ q6 ?    default: 02 G! [8 k8 F& b9 g3 {
      },
    / ~# q" ~7 o# W2 E+ [$ d  end: {8 S+ P6 [- L  J6 ^1 j3 s! n3 `8 P
        type: Number,
    + M7 n2 e6 g. L9 O4 Z7 v9 O; C" T    required: false,
    8 I( [1 T/ r; |* I) I    default: 03 }7 A3 _8 m4 t2 H" l3 f
      },
    3 I2 |8 D. ?) e' E  duration: {# t, n; A& I$ w; V  b
        type: Number,+ b# @8 g2 `) K! t) Y/ m: ]0 \
        required: false,
    8 t5 p+ h# [8 z, F) s! h0 `4 n8 |    default: 5000* z* y/ w0 Z, O3 Q
      },
    - C. R( E! a' N/ n* m4 Z# I  autoPlay: {
    9 |/ _- P6 S' J# ~1 r0 W4 j    type: Boolean,0 H$ k4 _) r! w" |
        required: false,% h; p* _% |0 S" K5 e
        default: true
    % A" g7 }2 d3 r" \8 m2 ^  }," ^! [1 I) x% E) `2 i1 C, a8 j" g# Q3 B
      decimals: {
    $ \$ K# i) v" Y  z    type: Number,4 ^4 j* [2 x% Z& `, L3 @" L8 v
        required: false,, n/ {. U9 x$ R) o; G/ h1 g
        default: 0,
    3 {2 [* S0 ]$ h6 a) `    validator (value) {. e, H! [7 P, D! A( r* E! N0 Y
          return value >= 0: T) J: ?# U% K: |* v& i
        }% f7 c  w+ V* V7 p) ^' w3 B2 @
      },/ Q. G' t" H4 o. d. I0 r
      decimal: {
    # H, x9 Q* }, ~" I    type: String,
    ; |% n0 _1 K' a    required: false,$ b( B* O* M/ r
        default: '.'. U4 k( P0 v3 J( @, V% Q* Z; W
      },# N' w% l0 L, p% E/ r4 ]2 I
      separator: {$ ^  h; _/ v7 l" |0 D; O
        type: String,! D! r9 r+ m6 v, O9 z. R& U
        required: false,6 U$ Q" g2 |# |
        default: ','
    - |5 G" C6 }- d; y) \, e  },
    * B8 P3 A8 a4 D/ J  prefix: {
    ' y' i# H  N* X9 N9 |    type: String,
    5 w& r! ^) F, t+ A# b. v+ {/ ]% l    required: false,
    & p  s, ~; G& m* c; Z    default: ''+ M9 s6 ?) ~- r
      },
    ; Z. q. ]8 O* x) ?6 P& S$ Y  suffix: {
    ) C# n; k+ Q" j' |# C1 d/ {3 f) J    type: String,
    # G( g6 X0 o, I( y5 f0 f  G    required: false,) W: l9 O  t# y
        default: ''
    . e/ k. ]2 h1 W% Y% ~  _1 g  },
    % r7 O& _& c3 m! ^% q0 s  useEasing: {: Q1 f5 {& `& Q* a7 J8 @1 C0 m8 m1 P
        type: Boolean,
    1 T5 h. ?! X# T& O! Y9 v    required: false,6 |, m5 i( S5 E) K) N
        default: true  N5 `. ]& `4 C, _* ?" b$ }+ @& h9 S
      },
    ' h' f2 V; v5 N8 G6 D/ {9 L  easingFn: {8 w9 N4 V% A; @/ ?: z, q
        type: Function,
    8 x7 d0 a1 K( C4 w# v    default(t, b, c, d) {
    & v' y4 s/ F* n) g* [9 g$ m. y      return c * (-Math.pow(2, -10 * t / d) + 1) * 1024 / 1023 + b;
    + j8 h8 O$ C; K2 s9 e3 h    }
      g5 }8 Q4 W. `6 ]/ `! n1 |  }
    % A# A+ _; b2 k( e})* ?7 s( v- t" |; F+ q  e* `# W/ s6 m
    # A  ~8 U" q9 f0 i! J- d
    : `- [. _7 g. {% I: @; C  \! j/ K( Y, k
    1
    1 M+ |1 n! n. h1 {3 _2
    / {1 N" S2 p6 _2 T36 K0 ?- u; t8 ~" c5 d7 I
    4
    - g7 `; R9 O8 y" ]* g; n% [5
    ( T+ P: J3 N& n5 s1 s2 a2 R7 t3 V2 N63 S; R' M% Q+ z  B# L
    7) \$ e' _# B" }5 N8 F( p
    8" x6 w% N$ F5 K0 a+ i* `; a) z5 f
    96 a% Z5 k9 |/ @- o5 U+ ]3 ^" y
    10
    9 J8 y4 D6 n  ]/ p1 {11( V$ x4 s1 H: }7 f, u
    12
    ' a4 O, {# x+ w* O13
    ! X6 w' a  A* [% F14* e" R# k0 U  b* g
    15
    2 q9 ]9 [( f- x9 i16$ r1 m2 Y; D* Q% v5 k; E7 V
    171 |3 Z; R* w! E) X6 p& ~. x
    182 ?5 J8 D( |0 C5 Z
    19/ O. t3 V) M2 k" i
    20' Q- d% [$ S8 f! d' f, u$ G/ U
    21/ l) e- `- f0 w+ q$ U+ w7 t
    223 e1 ^. R( `* P8 \0 {7 o1 T+ B
    23: g" _2 f- H0 B" `
    24
    8 C! R5 [# c" M' r) ~/ |  o4 K1 C25$ c* m2 o# g" Z- V1 ^2 Z* ~, O6 S
    26, D9 ~$ s9 i+ p( l" q9 q
    270 N, o# |& T3 j9 P8 m
    28
    ' E2 n6 t5 J- [: B$ q29/ l. ?. u8 Z8 d+ k. c
    30
    , w6 z0 R' U" o; ^! r- c31
    - j" H4 |/ x* q32# }/ y- w* d: z; s9 a7 }  Y
    33
    3 u/ e2 h1 d+ }9 I, Z; D34) M" o2 l, N# ~5 t9 D
    355 k# o& \! U5 p" W; `. A
    36/ F& |8 w5 V5 ?% g2 ]; U; f
    373 F* \" |& V! J( c" ?& I$ w; M
    38
    4 {9 [! H, b) e% V4 x' c39
    ! ]1 D2 M4 `% L3 x  Z1 Z40
    ( F2 ^5 {: R# K* C9 \41
    7 w# O% E6 u- }" O# g: [! c, y: ], Y42+ n" z  S: W$ N
    43
    * R/ i& \. U( Y8 F& L7 i! h9 A44
    ( C4 ~3 j& C) r' g45; Y/ [$ q2 z* @& r/ u/ q8 k
    46
    9 D" ^% S) K( A! \# C47
    ( d8 W8 `: d. n485 g: p9 g$ A3 n9 |( W
    49- `+ w' l* _6 o8 m, l% H
    50; [# ^1 m' R6 U5 I2 q6 t
    51
    $ s! O- d% N4 v1 r: M52
    8 ?  M4 W, E/ N6 U4 M53
    % N& L" h0 G. [+ z54' b( F+ Z3 j  U8 U. }9 P. y+ p
    55
    - t9 U4 L: E  j! ~) h. ^. C" k56) W0 D% ?2 l- @% t# y' z" c
    57
    ( m8 L* R! \0 m) K/ A. P) _58
    ( J8 Y. q8 _# F+ ~59
    ; |5 J2 D2 d$ ^' f# N/ k( _60
    , I! B+ J; p; @8 Y61% [5 c6 F2 }6 b# N7 s
    62
    8 @8 D* C& {* F8 y' ]" ~4 H启动数字动效
    / ]6 q% T( h" N8 F9 R
    ; i" ]3 r; c. Y( R. L$ Iconst startCount = () => {/ w! L4 p$ g; [( u) D1 w# C6 z
      state.localStart = props.start
    2 f( a4 d* Q! c5 i  state.startTime = null  S9 r% s: c5 W7 t2 C
      state.localDuration = props.duration
    " m" w$ Q% ]& g1 h0 c. |! i  state.paused = false* h1 S# g6 o% Z3 ]" y2 u
      state.rAF = requestAnimationFrame(count)% {& {, l9 x$ M! w1 l
    }2 S2 S- m- m+ l7 G) p9 e
    19 Q& Z! [8 _( n+ _9 L7 d( [# e
    2: _  E% h+ Y5 p& f( R
    37 g* b6 j% \4 G( X/ Z2 L. y% A
    4
    , n3 p6 \2 y) ?$ F6 [5
    / I+ Z$ l6 @- l! {! S# P( ]6 m+ K6
    - w' m  ?8 y+ g( _4 E  I1 Q5 e7
    & b8 q% O! K4 M2 H! L! G" ]核心函数,对数字进行转动
    # S, F1 s8 C9 M) @' {4 [: k
    8 k+ q; h- O/ w" o" [  if (!state.startTime) state.startTime = timestamp
    6 V0 Z6 J* j: ?3 U3 N  state.timestamp = timestamp
    - v+ [9 b: W% f. }- B7 D  const progress = timestamp - state.startTime4 r3 U4 b  ~2 W0 e7 t
      state.remaining = state.localDuration - progress; P: g2 Q7 U, Q" p. }( D
      // 是否使用速度变化曲线
    : L2 l9 x* i6 `  if (props.useEasing) {8 I9 n8 K# R+ j$ ^
        if (stopCount.value) {. E- t" N* d6 A0 Y
          state.printVal = state.localStart - props.easingFn(progress, 0, state.localStart - props.end, state.localDuration)
    " X- y: H2 _& R    } else {
    3 W# G, R" X  ?0 R7 t      state.printVal = props.easingFn(progress, state.localStart, props.end - state.localStart, state.localDuration)9 g* k8 K! }+ \2 Z2 e2 R3 X7 |$ x
        }
    ) Q+ q* w: Z- c! p/ ~  } else {# E% ]6 s, k5 o* T  z6 T- J
        if (stopCount.value) {
      r8 B, \; u6 x7 q& n      state.printVal = state.localStart - ((state.localStart - props.end) * (progress / state.localDuration))
    - Z  s$ K4 r$ A3 p$ t& t5 C' q    } else {
    ( y) o% t" R; X/ ?* W' f' F      state.printVal = state.localStart + (props.end - state.localStart) * (progress / state.localDuration)& m  W/ b0 c2 Y5 N$ j+ e5 _& S$ O
        }
    6 x! C* X% u& n( [# M9 @  }9 g  g" t$ i* C1 |1 X: b* z
      if (stopCount.value) {
    6 m, l" P0 p7 M$ k$ Q    state.printVal = state.printVal < props.end ? props.end : state.printVal
    0 i  `  J, D3 u+ q  ^9 C3 L  } else {/ X2 a7 y/ q9 x$ I5 P# {
        state.printVal = state.printVal > props.end ? props.end : state.printVal% t  B8 @6 b" q6 m2 c' p
      }/ e9 j  p# S, r$ R0 {4 t9 {

    * _! f& d7 {7 r5 ?  state.displayValue = formatNumber(state.printVal)
    1 t; H. e4 H" z% x2 Y" M2 V, h) d  if (progress < state.localDuration) {. I6 c% w( K+ T2 E: i
        state.rAF = requestAnimationFrame(count)
    7 G% L/ c2 s: {# W& t  } else {* J' @: m+ C( I0 o; d% B, F" d. I/ C4 o
        emits('callback')5 d1 S$ t$ J2 t! s
      }# o* T4 \3 e, l3 @- s
    }
    $ d* K: `8 J* w/ `$ Y! t8 r0 @, C/ }# T9 w$ D& U9 p

    8 i3 c( T* P7 I; W- ?// 格式化数据,返回想要展示的数据格式/ Y# `/ J1 N" I1 X! u* b  o
    const formatNumber = (val) => {) Q  `; [& A& `# I
      val = val.toFixed(props.default)+ y* c" o$ O6 y/ J( j
      val += ''
    ! C9 |+ q( y* X( Y8 T) }1 n  const x = val.split('.')4 R( `: G3 u1 c# k7 Y
      let x1 = x[0]
    4 v( n# x% `' Y5 w6 V0 ]; G# q  Q( b  const x2 = x.length > 1 ? props.decimal + x[1] : ''& Z1 x0 Z3 F" X! q  `$ D
      const rgx = /(\d+)(\d{3})/
    1 m6 F5 b. I% S! M' H9 u: _0 J9 d  if (props.separator && !isNumber(props.separator)) {
    # F- h) K2 _/ |$ D& t    while (rgx.test(x1)) {
    & T8 P% D- Y4 e      x1 = x1.replace(rgx, '$1' + props.separator + '$2')
    8 C8 [1 {5 r6 i& n    }
    * H5 c& M0 B3 A/ }  }
    5 ^9 h) A6 M. E& t) x  return props.prefix + x1 + x2 + props.suffix
    1 Q8 K; R7 i  q4 U  Q+ q}
    " w$ F% X; X" i2 g% V+ d( q5 Z  ]$ Q3 d; f. [* h( I# _# e  I
    1  t1 [5 L' ?- R: R+ ?" ~8 R5 c  y
    2
    1 ~, K# F3 `* p# m- \  r$ x33 _9 ^0 N! ~( |3 ^/ R
    4
    & [5 G: H; W5 _! v; V, X4 Y5; e# `) y0 K- p% F
    6
    + O4 _( W9 X5 p7$ m' D* t" l! p- U8 o, H1 E
    8
    2 t  E# T! t0 S/ B+ O8 y9
    : u* `* c+ R3 c+ N) p/ j10
    . z+ R' d% M  }& Q* O8 V114 g7 A; n6 F) ]- p  Z5 l" h) `
    129 e6 C. Q- D& h" N5 M1 S& W+ o
    13
    + \$ a3 B4 ~3 v* M3 c14
    9 ^' K# ^" t- x8 R15
    ' I) y4 K8 w4 C- O" P( A7 s166 j: u& Z+ x2 b$ r! n6 s
    176 B' @3 D3 ^. A* `6 T5 N" V
    18
    . O& b2 m/ x5 B( h$ H19' d& j# P# }# k2 _# x; H
    204 H0 M/ c3 H% L0 p6 q
    21* o1 H. U" C& |( k9 J- \. p
    22
    : N. a2 |# k$ V* e8 T23
    2 p: L, e2 Q3 M; b+ A; W: y24+ A9 }% e, i, i" J% e
    25
    6 a  Y; z+ L5 w% y/ }260 @. G. m" m; W9 {$ z
    27% b  D7 g1 q+ f  W
    287 O9 L. Q6 g8 r, C% j" F
    294 e4 _) V  ^& g/ ]7 p
    301 ^( U% }$ Q, Y" i1 k+ R- Q! Q
    317 s/ K5 t5 \; D9 Z2 }/ y: n9 e) f& U
    321 v7 a% ]0 X: A0 I% J! ^7 V
    33+ \/ \/ l, h9 y! P+ t5 i
    34
    7 }: z; }) g# K5 |1 {0 b+ G/ p35
    " Q& e& R4 u: g2 S( e6 C1 J36
    & E; ?7 c3 z4 b6 q9 g0 W& {37
    , W6 E; ~) K& C38# `# Z: ], N, x; _, l( L1 l0 p
    396 O" s6 H5 H9 |$ z* ^4 R
    40" A! W, ]0 d$ e' \8 Y% n' }/ @: T2 k
    419 i; n% k4 s( L2 `: S) ^
    42
    , y5 T" A& g$ C& i+ w43  ^( F# V5 {$ h  o, |; e
    44- n, ?5 F/ z0 i4 `% x2 d  k9 S
    45
    0 R1 T9 F+ U# R) S& E$ b46
      {7 J  [1 {8 j; d% \47" m  g8 l9 F0 R
    48
    ; s( i; D9 v  F& y取消动效
    # ]) [  |& a/ ^( u, g4 O! j% D" `" p9 P* F8 A' Q; P! w
    // 组件销毁时取消动画
    : _9 V! d8 ?( f' T8 {3 C2 conUnmounted(() => {
    : y& V4 R3 \# K) Y5 o7 _6 [$ L  cancelAnimationFrame(state.rAF)
    ! G; ~; t3 z; Y4 G. N& [" S: r})! W3 d9 |) c* s) I% u5 D, ~
    1
    7 u& v' ~4 Q" x) g/ [( F2
    / s/ ]/ L& U( |3 n) C6 K1 G+ Y3
    ; r5 y1 |7 l% b9 q# n48 H9 d1 d5 r" J% Z: T- n8 {  L
    完整代码
    " z( v9 D% M9 o& c/ V: \
    & a6 P1 J( E' ?, {1 i% I<template>7 z3 X8 [9 F; f" U; ?6 \% j
      {{ state.displayValue }}9 j" r! j: x" s6 h! [+ i
    </template>0 y5 l3 S4 L# X4 ^  \0 d
    4 _6 U. [( Y# S6 a
    <script setup>  // vue3.2新的语法糖, 编写代码更加简洁高效
    ( Z% ~. E( x! M0 ]5 X( [+ D, Y8 aimport { onMounted, onUnmounted, reactive } from "@vue/runtime-core";
    & e& ^* W9 ^% E( z6 ~4 U, Simport { watch, computed } from 'vue';9 r5 |: x: H$ N# d
    import { requestAnimationFrame, cancelAnimationFrame } from './requestAnimationFrame.js'- y' O; e4 ?1 J7 A2 Y1 L
    // 定义父组件传递的参数3 `0 J' P/ z, ~  I% H
    const props = defineProps({8 S. n0 O+ [1 w0 A
      start: {: S! u: y9 h) ~/ Z" A7 _2 J
        type: Number,
    . s! V" E/ ^- U, c# d3 ]5 T    required: false,% [9 W/ [3 u( ~$ ?' Y4 X7 ]
        default: 0  j- ?* V8 b: l+ H# r1 K, c
      },1 y% E2 A  X6 C8 ?/ z2 r$ X
      end: {) S' x2 k; l) e) S! C
        type: Number,
    . |& [% q6 \, J    required: false,
    & r1 o- t: [3 Z% ~" S/ }: M, F    default: 0) H3 R7 K% F& ]/ v% ]4 a" I
      },! A/ C0 p* ~& ?# M
      duration: {9 z" S& j- J7 M, Z
        type: Number,
    5 a) W2 K. W3 ^1 S0 i: Z9 ]) R+ N    required: false,
    : G( b! Q0 P4 }- l' o; v    default: 5000( l  d, a+ z% @3 A2 w# r! H
      },  I( W: d2 b( N1 l  s
      autoPlay: {
    / R. K6 ]& ^' l& J    type: Boolean,
    3 `) y' k3 g+ ^3 ]3 Q    required: false,
    8 B6 b% t  q; K) t1 M    default: true. D7 t" p2 D4 M" T- Y1 ?
      },% N# E; m; x( m
      decimals: {5 A; z8 ]$ Y3 Q/ o) o$ I4 r& {5 L
        type: Number,
    + ]" Y" w+ w: p7 S    required: false,
    1 A  j1 [( O- V9 N8 i    default: 0,
    7 X$ R' s3 z' d; I8 G8 h, g' F9 w    validator (value) {3 _7 s& Q1 F! t+ v7 c
          return value >= 08 `% p$ v+ m+ n
        }
    : s) k* N; n* M# U  },
    9 R3 S8 `0 B& X  decimal: {
    1 n; O0 G' C+ M% `    type: String,- }4 g, t+ Z, ?9 @9 \
        required: false,5 M' ?8 z' E: b. o0 X. O8 W0 G
        default: '.'" v" k$ ]  j; f9 B% V, ^
      },% l: ~. W. j' o6 L+ F# \5 f
      separator: {: R* s9 n- ]) X* ^
        type: String,
    ) g8 j' K$ p$ r$ x    required: false," d5 V% X* _8 ^+ A
        default: ','4 M- q6 Q5 S! f. j6 V' k6 X* Z
      },0 P/ {6 I' {6 q7 N, ]1 [$ x3 \  ^
      prefix: {4 T5 o' q4 P9 X$ a2 h$ z
        type: String,/ U/ u8 u3 S$ K
        required: false,' {8 j% u- ]( N! k
        default: ''
      Q* _$ E  Z+ }% k  },
    * N' x" X3 K! C6 c" S# W  suffix: {2 M: U$ _1 O$ Y3 j5 G! A, M3 p
        type: String,9 N8 Y& K( d4 Q: ~, ?
        required: false,8 m  f# i! e" A* |
        default: ''( @3 p5 o: h/ l
      },8 h2 m2 {7 _1 H1 w  n* A6 p
      useEasing: {/ v6 |! f' [# _$ ~7 Y; q
        type: Boolean,% s' D0 [) q. p7 C7 f* `
        required: false,
    ; o4 V; b/ b: r1 u9 ~& K5 H4 ?( l    default: true6 e! ~7 {. o% P6 C+ o% \$ h8 U
      },
    / E2 Z( o. ~7 {: P  f$ B9 n: w/ t/ \1 o  easingFn: {
    # r* z) }$ ?! }  m5 h. @. r7 p; H+ E+ O7 w    type: Function,
      v, Y5 |+ ^; B    default(t, b, c, d) {6 ^3 N/ k, s& \: q' ^4 P3 p
          return c * (-Math.pow(2, -10 * t / d) + 1) * 1024 / 1023 + b;7 G8 L7 T$ P7 F/ y# A) e
        }
      @3 B0 Y+ A! U2 ^  }7 Z6 V" o8 F* c1 o( m0 q
    })
    9 f6 I$ U  o& Z" Q7 U7 n: B! n& v$ R" X' M; [9 f) Y  y: S
    const isNumber = (val) => {0 e7 e- t1 F, j: u
      return !isNaN(parseFloat(val)); V2 F, W2 m% a5 ]' n8 q; [* G
    }# j5 N, P" h) l* }
    ! H1 W7 p7 k: I
    // 格式化数据,返回想要展示的数据格式0 _. U! J& {/ A& N% [
    const formatNumber = (val) => {
    ( s( J/ ]& u! b* N% n  val = val.toFixed(props.default)/ y9 [% x  V0 E$ C  ?7 |4 j" x& t
      val += ''. W9 Q6 V8 C6 \9 t4 o
      const x = val.split('.')
      ^2 @& M0 ?3 Q4 e  let x1 = x[0]) [& |2 o% E; q. J
      const x2 = x.length > 1 ? props.decimal + x[1] : ''6 v1 l4 A5 {; F' N
      const rgx = /(\d+)(\d{3})/
    ' t% |/ Q* s7 c. q) @5 q  if (props.separator && !isNumber(props.separator)) {4 E7 J% {% Y2 u
        while (rgx.test(x1)) {; `- k& {: Q, X$ L5 B: U
          x1 = x1.replace(rgx, '$1' + props.separator + '$2')2 {0 G6 f' q5 M
        }
    ! K! H& H# G1 x- Y  }
      \- ?2 F% D; q! w2 U; e  return props.prefix + x1 + x2 + props.suffix) H1 w% s; e0 q5 {) Y0 G
    }
    ) p7 F7 `- _4 J7 H  c/ X3 J' m0 G# b6 V) `8 t
    // 相当于vue2中的data中所定义的变量部分% c- y  G, |: d$ Q, t6 Z- [0 {
    const state = reactive({7 q/ R' B- e) ?4 X; E% N4 d( t
      localStart: props.start,1 @& O' i% W5 y: I$ o7 U
      displayValue: formatNumber(props.start),
    ( b$ ~  W5 |) O' x5 p- E  n4 k  printVal: null,
    1 n: j4 L! b1 @/ J' [  paused: false,2 Z$ S; {0 A: U7 I/ Z& D6 J) Q  h
      localDuration: props.duration,
    , Y0 P) P: k7 r  startTime: null,
    1 C# |4 ~9 T: I! Q  timestamp: null,
    + D" b* s; l3 H. q( v  remaining: null,
    0 r( k; a& i) V  rAF: null
    1 E+ J9 ]7 ~! q0 q# p  e! t9 Y) W})# q& O. k9 U% Q& _$ o) w
    4 V# q& |3 T5 w. O1 s3 N$ W9 z
    // 定义一个计算属性,当开始数字大于结束数字时返回true* j, i8 H) w, L  z/ e2 J& w9 S; \
    const stopCount = computed(() => {2 X5 W8 r5 E  }4 o6 S; i& K0 R
      return props.start > props.end, v9 F" U2 p  t
    })
    - z( x* B) T* t# ~; e: i2 v// 定义父组件的自定义事件,子组件以触发父组件的自定义事件
    " c% V1 \5 n2 |/ P( C" xconst emits = defineEmits(['onMountedcallback', 'callback'])/ F; Z9 w- U2 ]5 S

    6 [/ x' L2 \5 ~1 |+ }" C: |8 L2 p0 Tconst startCount = () => {
    " ]+ Z5 U& v  N1 y4 T( i1 R0 S' Q  state.localStart = props.start
    : d6 t' p( Q" ~+ y% o( I4 ~  state.startTime = null
    ' T# p" P5 j5 G# R: g9 k) {  state.localDuration = props.duration
    / P* S7 W1 u$ z  state.paused = false# B4 x! r4 z: _! M7 S+ c" e
      state.rAF = requestAnimationFrame(count)
    " O% f; n% f* ~' e' B}
    ) u. [# U/ @+ n2 |' a5 X4 ]; H3 O+ y. I; t! I4 |$ A; @
    watch(() => props.start, () => {
    ' q$ }1 g3 A; K' M) }, [! H/ d& [  if (props.autoPlay) {8 l5 E7 n9 O3 y4 P/ [3 b9 R* t+ q
        startCount()
    1 y9 ]- f  Q" D; M  }6 V: x4 d  }. t: b% ^/ x/ l
    })
    + u2 Z# V) r1 u7 Q( H" c  j: K# T8 E. @) u5 \9 _
    watch(() => props.end, () => {6 w8 m6 o* T- U; G  u9 H7 G
      if (props.autoPlay) {" ^, F: n, \! Y# Q/ H. ^/ o/ y" I- l& ^
        startCount()# R4 O% a+ \" T" g7 Y
      }( }5 ^8 G2 q; T$ s$ u7 j; L- `
    })" g1 q& J; j4 y4 r4 h& j
    // dom挂在完成后执行一些操作
    9 ~  }, L) H, N4 f" d, donMounted(() => {7 O5 ?% g. L: q+ k4 H2 h9 {4 r
      if (props.autoPlay) {
    . g' t* @3 O' a) y    startCount()5 J% n1 \& T6 \4 P$ W9 o
      }
    ( @* X* d' e: F" n- {4 @! w  a  emits('onMountedcallback')$ X6 q1 i" P0 B! O3 D
    })! H5 c: Z7 B9 j0 Z2 V$ Z& W2 r
    // 暂停计数
    0 E% z9 k2 Q9 g0 Pconst pause = () => {/ y6 ]0 g8 A  {
      cancelAnimationFrame(state.rAF)
    - V. K, {* P, Y5 ~# q! d6 D5 y5 \2 P}$ @% m  Q( V0 }+ y
    // 恢复计数
    / t, n: T: R0 U- n' Yconst resume = () => {
    & G+ n. L8 w& Y! p3 n: Y# G! Y' W  state.startTime = null8 ?, c" L' s: K# A- W# ?
      state.localDuration = +state.remaining3 z( s$ N# }( V) v) E
      state.localStart = +state.printVal5 c1 Y+ X0 t5 ^" d& n
      requestAnimationFrame(count)6 `- E" n  J/ R. I9 ?! w& G
    }; M+ A0 K) A- S7 o6 i! v
    # e- k3 s" q. L* k
    const pauseResume = () => {& d3 S% c5 \9 ?! g' `' }+ o
      if (state.paused) {
      {, J% ~$ `5 y% I# H6 z8 F    resume()
    : O; @4 d; }3 D& k    state.paused = false
      b7 M# Y1 g5 @& e2 _  } else {: j; G' `7 z0 h/ C% ?
        pause()% ~5 n0 k7 m/ e/ D, n
        state.paused = true1 c  a, {: H, E) Q3 m/ @+ Z* ]# K6 h
      }/ U# l. S+ Q9 |
    }
    6 o* Q6 A0 C2 S# F! U  {' Y4 u8 z9 S' F  Z6 l
    const reset = () => {
    8 v# `5 D" B4 y: ^! a- b  state.startTime = null
    ! `( U6 }  `) Y  cancelAnimationFrame(state.rAF)
    7 n8 b5 X8 A  g) ]6 Q  state.displayValue = formatNumber(props.start)6 ?7 I; M. f7 M* R
    }
    5 L1 T7 v. ^; M8 J7 v) }5 L4 ~1 A, n" ?9 N
    const count = (timestamp) => {
    $ }: h0 K% B( Z( M! K! f2 W* U) o, f  if (!state.startTime) state.startTime = timestamp
    + B! B8 }- h" k# g* o  state.timestamp = timestamp
    2 u/ c- W) k& n/ q  const progress = timestamp - state.startTime2 o6 _& v% B- _% u. e% M3 H
      state.remaining = state.localDuration - progress
    1 g9 t! W5 l) S  // 是否使用速度变化曲线
    2 K2 B0 I$ e0 u1 m! T  if (props.useEasing) {0 {( `5 K6 Z) b. z- G, b4 x! z
        if (stopCount.value) {
    5 d2 t% {& M; g6 v& Z      state.printVal = state.localStart - props.easingFn(progress, 0, state.localStart - props.end, state.localDuration)
      x% ?8 z; K; u" p7 C    } else {9 t" {, J$ w' r
          state.printVal = props.easingFn(progress, state.localStart, props.end - state.localStart, state.localDuration)' T! a1 J* g$ F' X
        }
    ! h5 I8 q, w2 F" A  } else {
    / m3 v. D5 k( x8 p- y7 p2 `! M    if (stopCount.value) {
    . M: U& y8 B' R1 ?' B" B/ U) c7 I      state.printVal = state.localStart - ((state.localStart - props.end) * (progress / state.localDuration))4 i! T. q( h/ ^+ `) z' t
        } else {, r' a( P/ Z' a# f: a
          state.printVal = state.localStart + (props.end - state.localStart) * (progress / state.localDuration)! P0 r5 x6 |, t
        }- }& f( V9 I; e- H, O! w
      }
    * J# R) W$ P; g+ ~  if (stopCount.value) {
    # L7 U& Z0 j% D/ z; ~8 s: t    state.printVal = state.printVal < props.end ? props.end : state.printVal
    # h8 j/ S7 {2 n  } else {
    ; V7 ]4 q% [2 {. n; t' |    state.printVal = state.printVal > props.end ? props.end : state.printVal; w9 h9 U( k, p
      }
    " @% }2 _, n/ y# O0 Z
    ( }% B1 I7 K4 B" R  state.displayValue = formatNumber(state.printVal)
    0 W  C/ n, o; C3 U- n  B! O) E( O  if (progress < state.localDuration) {
    . R" J- A6 @5 z9 R5 d    state.rAF = requestAnimationFrame(count)( d, t1 o& ~5 o' k/ L
      } else {2 S$ E( h2 U+ ^+ t$ A* ~% f
        emits('callback'), v' P8 L/ V+ Z0 c" R$ |
      }
    & S5 \3 E% M' k8 z/ l3 \" |}
    9 I+ j( D( I+ o3 @4 `/ ?// 组件销毁时取消动画
    ; Z& @; P( ^$ n9 }: o$ donUnmounted(() => {$ J; P" S; Z9 \/ Y) l7 @
      cancelAnimationFrame(state.rAF)
    3 M' _( a7 u$ x! M% A- {1 W})) [7 m+ m# K0 A. A2 f; n5 q
    </script>
    , P( l% F! P- J" \0 F0 @* k
    9 R8 E, T6 L$ s. O, B# d1: p1 J9 Y9 |! p4 `# F% Z2 [. a' U3 U0 l
    2, Z$ @$ K3 N' [1 R4 [6 [$ U8 ~
    36 }4 k3 \" p$ U. G. ]8 R
    4
    ( h) c- G  t3 o. W5
    + J$ B" {0 \& n- J- f/ v69 I  t/ V: U: p; x
    7
    5 D. {. }/ {! r" J0 c( N! a$ @7 p8; l; f9 u2 W( I7 P, k/ d
    9% k& b5 ~# P  V2 g  U/ E
    10
    " H/ q; |1 U% }6 i# W* R/ n11. I1 d! g. c4 M7 ?; w  ?
    12
      ?: U# N5 F6 n8 [7 c7 i$ B5 w% u! H7 I13: L3 F- c( C# \' ^
    14+ ?3 I9 N  r7 a( T, |" [
    15( x  K9 Y; z, F
    16
    4 B* b0 |$ R% r9 d8 D17" d7 g  Q* ~: A! _, P( X" ?! X% M& m
    18
    . x8 M4 [/ l+ T4 g; `2 q19
    / l( C6 m' R8 Y0 `0 S9 V20/ ?1 o- f, Y' r- X; D
    21
    ( {/ H& N0 S# G& L) r/ H: [22) k- B% |% n" [1 I3 H/ j4 {( l3 h
    23: @; K. J8 ]% [: a3 K
    24
    0 @) J! V8 l& U7 T1 D# V- _259 b; t& w4 f+ P
    26
    ) v6 b8 h4 j+ _276 u1 z+ c0 c! \& i
    289 ?# v+ Z% N; U$ p: Y# G
    29
    - J& w; Q, a# g7 f; t( @30
    ' l) s. o7 B/ @! O31
    3 _8 e$ l0 v' b) ?+ K* \7 v32& g; _8 J, }6 E7 _
    33. O3 }* \4 h. ]5 a8 Z" m
    34, A; E8 [% D7 V- [
    35
    . s  {  ]4 O7 C( ^( s36+ F: Q# v6 ?" w
    376 Z* W0 d, h8 |( a; Z' D
    38
    ( \/ N  s; F- M39
    / L. G$ K$ H" M$ U- u- \- J* o40
    $ A2 O: ^/ L- u( h' |; l  q413 s1 p  a; h3 r$ d0 P
    42
    " T$ p3 U) \4 `" ]% _, R7 e435 e0 I. _* N6 I4 N" }
    44
    + X1 h' E: _0 g454 L1 A& w9 W8 q5 ~7 _( M9 `2 l/ i
    46
    3 e" a: k0 C1 n7 v' c& Z0 K5 m! C3 e47) Y' i/ h7 q/ }7 ?. k; ~
    48
    # t1 I6 `1 `* J! j' P49! }5 O. N3 }) d% ~  k
    50) N  J4 h% T0 A" u9 _# H$ Q
    51$ i) U. Y4 T1 ^" I* d6 U
    52) c* X0 J$ L9 {3 ~4 J
    53! E. r/ s' [  ^& f6 F4 _( k5 w
    54, Y3 e4 Y' L0 p! O; `! A. o- W( ~
    55: S5 C( q0 v$ x% N  W2 ]# |4 Q0 g
    56
    + |; p1 Q& a6 Q/ @; K57
    ; m& L7 ~( D" @  W58' d7 b& k/ X7 \' Z+ j. S7 r
    592 Z, i- u8 v* J/ d2 f
    60
    + o- ^* D8 p2 b  A' l61
    8 L' Y8 f2 E- u62
    / t7 n, [- G) Z/ |  U) m$ m$ C1 J$ D, e63
    ( }, N, t& c9 C" j64
    7 @2 t* n5 }# x  F4 M' h* T65& r( }) e: s0 O4 X8 j
    66
    / j; g; F: W, @6 i7 ^( f$ {/ Q& m67
    7 T, I0 f7 O  x68
    3 G$ s* K0 h+ h* z69
    . Y. \9 f& N- [70$ q/ `  a  a# _4 |8 C6 P6 F9 A0 x
    71
      t4 _) ~  X1 j72
    1 M" J9 }' `, G1 M7 W73( G% [+ ~7 E' Z: s
    74$ j& J" f9 w( T8 s
    75
    3 Z; p5 P2 K1 L& W76! k' i  T7 C3 S6 Y2 _% x2 f
    77# m+ a) K! d) H; D8 M* u+ u8 k& H
    78
    ; [* q" e' x9 x4 b2 X# `79
    ( k7 a1 b/ K  y80+ }/ ^( v6 ?* E2 k0 B
    81' F8 k$ x8 R5 z' }
    82* S$ G" i: P( @* R9 @& S& |( X+ T5 u
    83
    3 k7 D1 ?' a/ p( `0 F  e8 P9 |6 P84/ t6 Z7 ^1 j$ l+ Y! F' R: P: X
    85
    - i5 m3 K" I- }) c( }, _; r86& h# I  ~+ p; j5 ^/ T
    87
    3 h: ~: n) J8 P# [% h, K) r) \887 l8 T# ?* ?1 ~9 R
    89" R. D4 p2 t( u7 P1 D0 b/ z7 ]1 `
    904 B2 ~8 c. @) X4 [# m# f9 O  n1 @0 @; v
    91" R2 q2 w1 C# h- S
    929 z1 u( e; D# I1 U
    93. x' q- z$ u+ a: o
    94$ m" I' U% ^5 A" j3 b
    95
      f$ [' `+ i# l( }: d3 }& i9 p961 w* y( J* x; ]" O  G7 m
    97$ D% }/ [4 p5 U, O$ k& b! J
    987 D. b, z1 }. I9 j. y% W/ t& J
    999 a' c; k+ q; C
    100
    0 {" b+ F- Q/ {* @8 T# l1 m* F1018 D$ S* L1 o+ j
    102. b  |1 @# h0 v3 W1 o1 [' P7 F
    103: V% d; o, y5 m# {
    104
    . ~0 _3 p7 |4 t5 @! Z+ T" C/ H3 E105
    0 E* S6 F5 N: x" `106
    9 r& j& y' m: o  ]- |8 ]107
    " r! b- |! m* `6 O# \  [' L108
    * {' S0 ^+ j# d. c7 M5 k6 J/ }7 Y109% W. S* D8 M6 q" T4 l$ f1 K
    1103 V& \/ E- w1 ~2 d  c
    111. k; P. C- l  e4 O0 x( a2 T5 i
    112
    ! O% n5 J. s7 k' n& |$ g' [4 f( M! Y0 F113; [/ n! [4 r% z2 {
    114$ _/ f& K' y. v* g) o( L; O' K
    115+ e. E* k  q- @9 `  D+ P
    116
    / h5 B( c5 F8 q0 `+ f1173 V, {+ C! P- Z4 i- W' U$ G, V
    118
    , ?' c$ |' u4 J. a. z5 i1190 T4 W& }0 D7 f7 ]& Y" }
    1204 l, c, R; w% Z% _& i4 Q
    121
    ! z) u2 B& X" `; r1 u122
    - k( p, w4 V3 C: V! r1238 N1 u) P% n% s8 ]1 d/ J
    124
    ( d0 K/ `1 O. z0 \/ ?! n- e1254 i  f. T- I8 o% i1 w" X2 z3 N
    1265 d) p; W! v6 D, V
    127& S8 c; l) ~) {* \( A
    128' f' P2 E& l8 z9 e8 N, j
    129
    ) N; U. w4 ^/ e130; {, F" R1 m, R9 X0 \+ c' f+ G
    131* y! i& p( y& H
    1326 L+ _5 f) \; Z- t9 t4 p9 o& c6 C/ |
    1335 m' n3 [1 x+ z3 K
    134* }& j* a3 ~$ N; X7 t5 D
    1355 J0 O, R% F6 j7 C2 d, q
    136
    ! o+ X" r' f0 E2 P- o. j% B' L137$ [' |7 Z3 v* C3 I# p
    138
    , ]# V" |8 E5 I; P139
    . R  w9 {$ G% A& ~140
    " c4 a4 ?3 x. u6 u7 T141
    " `( O' l, d: o; I- F8 P( D( d142
    * g; X* x  d) I2 {5 t143! I5 W, c; t. Z/ _, X0 m3 _3 D1 X) X
    144
    2 {. C) C+ Q( P0 g8 F145. }/ _- B7 }" G
    1463 K+ h( M* J6 S0 c
    147  m/ b. ]4 Z( d( N/ M1 r
    148* M" @* A5 G# s. J; I
    149
    7 w' ^. Z* U$ D( r/ L+ o& E150
    2 s4 m% F" U0 G0 a  q151, F3 c& k8 _7 K+ u# m
    152
    0 R5 P+ F( s) c7 R" R+ ]% B1531 m# J# |, B" `
    154
    . X) `0 h. o! o, ]& X" z  ~155* L% D7 o! e6 B4 s7 J
    156/ E2 U* F% o! }4 H2 [4 M
    1574 T% H& F& V8 X# W  c
    158
    : F8 p/ ^; ^9 j& I, _! [/ Q159
    ) L: V1 L: Q( ?' A7 N$ m160! j$ O( }0 d, G& s0 i: Z
    161/ f3 M& B( y7 u* _$ X& }# C
    1627 ~# b6 O; e. L# {
    163
    ; f2 v' i1 i) f/ K* N1641 X) n; X; |8 B: {. C" ^* K
    165- `, n8 D4 a+ h
    166
    0 `7 O5 o9 Y1 W, y9 }7 y9 G1673 ?+ V/ U( E, D4 i! l  s
    168, t( ]- U' I) _# W$ d
    169
    . s* C0 V1 k( f7 A7 Q5 A170
    & y' K) V- ]$ S* \2 c$ g$ J171
    3 y+ L; T& w; y" q( K; |172  M: f+ g6 E% M/ T: k. S
    173- {4 y, t) K# U4 B9 `6 Z; Z8 @
    1747 C# w# y$ \- I6 x1 a
    175
    7 ^5 |1 p4 y" A2 s8 J1765 X! M$ c  ?/ p2 {
    1779 L* C2 o' I  r. \- F* i  k* b- {
    1786 ^  A- C# \. ^  C+ E5 f0 q, `
    1791 `' c) ~+ z+ x' Q" U8 b* i* C0 q
    180
    ' V7 }! A4 Q3 {; a0 F181
    7 L" L/ g* ]$ u7 Z1828 @6 ?4 z; z) Z& Y
    183% t1 E9 G1 q: l
    184) B5 j3 z) t! Z, y8 W
    185
    " _$ x! l- @8 x  L* @2 w, L186
    6 `. ?$ \9 F+ B& Y" o1873 Z* t) ^2 G' X
    188* E7 g8 X* D" I# \; F
    1894 a0 R1 \; Q& A9 K! K
    190* g0 w8 M1 m! D4 A
    191
    ! N2 J! z5 E+ R192
    " s0 `" }+ M+ \, d3 G6 g$ X' T193
      a  l8 g, e: G1 P( y, m9 z9 N' t194: A6 w, \2 M6 {( j
    195
    1 S  I; ~7 U7 }$ V8 E7 a1964 Z) x5 v; n, _3 |, m4 ~% B
    1976 F% ^( @, e9 o% F1 K- P
    198
    6 M7 d9 R4 d) v199, Q  o4 p2 Y$ [" M1 w3 |0 B
    200
    & D' n& }5 g/ ?, f7 Z201
    2 C& I) `0 ^7 a  q) z2 [' v+ N202
    3 v: v+ }, J/ L( `  V总结" G  Z7 y0 G1 |
    自己封装数字动态效果需要注意各个浏览器直接的差异,手动pollyfill,暴露出去的props参数需要有默认值,数据的格式化可以才有正则表达式的方式,组件的驱动必须是数据变化,根据数据来驱动页面渲染,防止页面出现卡顿,不要强行操作dom,引入的组件可以全局配置,后续组件可以服用,码字不易,请各位看官大佬多多支持,一键三连了~❤️❤️❤️
    : U- a% h/ X& H
    ( b6 w3 ~9 V( f7 _8 p& l& Ddemo演示
    6 w# z3 W7 j/ H3 c后续的线上demo演示会放在$ n9 F+ e2 d9 W  ?2 X* G
    demo演示
    / D, _1 [7 E  o, \8 ]/ h  A! s6 Z% O完整代码会放在
    % D( ^- _7 K* d& W  x9 v& a个人主页
    ' b% f- ?0 C0 R$ F- ]
    ; H  q- c/ [( g# L希望对vue开发者有所帮助~
    ( C- b! n! n# y- r# h
    : S8 J5 `) E) d, j" ?个人简介:承吾. t, |" D  j6 m4 n3 [, ^
    工作年限:5年前端( j! |3 G& Z$ y
    地区:上海
    ' b' x/ j2 g. G$ _" b8 `个人宣言:立志出好文,传播我所会的,有好东西就及时与大家共享!- H1 V8 \6 s8 F# s
    ; J3 P- m( T9 J/ d

    9 k4 f# O  o  l! {: c7 A# y. `5 `& N- L2 c7 h# ^, W  E
    # S% `% O9 ^) R% h. C- [. ^" Z
    ————————————————& w; y. G& _+ t( \' h' j) ?
    版权声明:本文为CSDN博主「KinHKin(五年前端)」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
    # l1 p& Z; g* @1 j原文链接:https://blog.csdn.net/weixin_42974827/article/details/126831847/ y- g% ~; Z" `/ z) V- O3 _
    ' f/ I7 I6 s2 }6 T

    8 F" y5 [3 ~2 e3 H
    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-4-10 08:28 , Processed in 0.446354 second(s), 51 queries .

    回顶部