QQ登录

只需要一步,快速开始

 注册地址  找回密码
查看: 3914|回复: 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 | 数据可视化实现数字滚动特效/ N& Q+ n1 u) M! T
    7 j2 q: ^0 S4 u1 O8 a- M6 f, t7 y* V
    前言
    % \: L" u2 W  wvue3不支持vue-count-to插件,无法使用vue-count-to实现数字动效,数字自动分割,vue-count-to主要针对vue2使用,vue3按照会报错:
    9 R8 {1 }+ j: W( QTypeError: Cannot read properties of undefined (reading '_c')
    ! I0 U' V5 d" p& p( [) @0 G1 |的错误信息。这个时候我们只能自己封装一个CountTo组件实现数字动效。先来看效果图:* s; u5 ]- ^" h' \
    ) u6 u8 J' P2 y) f. _: ~% p+ z

    ; \; z2 K' j0 a& G思路: F2 _) w+ x1 W# \$ `
    使用Vue.component定义公共组件,使用window.requestAnimationFrame(首选,次选setTimeout)来循环数字动画,window.cancelAnimationFrame取消数字动画效果,封装一个requestAnimationFrame.js公共文件,CountTo.vue组件,入口导出文件index.js。7 `& T: \- }$ U3 E# p' {/ A
    % u* A3 [9 [( @- A, c* z
    文件目录
    9 z5 J, |" |1 ~, L
    # f& [/ x1 }7 x* t) ^5 G9 W" e
    $ e1 Z' }1 F  c$ j% @" d4 D使用示例
    + n. [; o3 O5 g9 F5 `4 X$ @8 ~<CountTo
    + n" a0 z# T) J* e7 e :start="0" // 从数字多少开始+ X8 u9 I* D1 W& z. J$ r
    :end="endCount" // 到数字多少结束
    , l- y1 z, p2 n' {: B; u; p1 i# X :autoPlay="true" // 自动播放
    & }( A7 V! p% t9 f :duration="3000" // 过渡时间
    ' w* C3 r- M! W- T. U prefix="¥"   // 前缀符号
    % F8 Y8 @1 o/ S suffix="rmb" // 后缀符号
    " |- S6 h$ E- E) Z" w />
    * R0 n" L" W  u) K9 O- p12 A% e0 b- ]6 V- |5 t
    2
    ( B  |. x: R; ~9 p" I/ L* \3
      c, K! Y# `* N' m43 f( T$ H& E( Q' N! k
    5! @3 _2 L" ?2 }1 I  t4 E
    6! A9 v. y+ h6 ~! U3 C
    72 b0 G% [; K3 |. Y* |
    8
    + e9 b) }  P1 E: J; h入口文件index.js$ n, `7 X3 @# Z6 B
    ; [0 p" F' s2 L0 ~: G& m
    const UILib = {
    1 g) g' k- }4 E- }  install(Vue) {
    0 A# w8 k& {1 L: y    Vue.component('CountTo', CountTo)! Y3 ?: h# L% x
      }4 Z) c; x6 u" d) k/ s7 H' N2 e8 Y
    }8 y( N$ K9 q  O6 N  e& H
    * f2 U' [6 \6 n5 l) F% o6 e
    export default UILib
    6 y& J# x! p+ u# ]$ U8 @: f6 u' x0 Z( Z' s/ W/ c; E
    1, W$ g6 [8 T, _' H& D( S' I
    2' ]; A! t- e) ]- H, G0 |& O
    3, }/ F' X8 r$ }; M2 E
    4- W+ w8 ^) d. y- d8 Q/ M5 P; N% ^2 t
    5
    + K5 N2 y4 Y9 E+ j5 d  e6
    . T4 q& J. Y5 X& g5 k9 |7( X" T3 F5 K% K+ m) H, U
    82 Z* A+ j- ~1 p. [& C& J
    9
    % O: v  L6 @" q, O# L& t3 b" Ymain.js使用
    6 b# }% ?$ _) M' y, e: [; l2 n5 Wimport CountTo from './components/count-to/index';
    9 [  `9 v0 g" \2 a0 x# Z$ o, yapp.use(CountTo)
    : _, }5 ~% V% T2 u8 [1
    % ?( I8 A0 v! X7 d9 Q& G9 |2
    $ ?- j7 C6 e3 t+ V6 X% @$ A2 ~- arequestAnimationFrame.js思路! Q  u$ V/ |4 b" M; G- A
    先判断是不是浏览器还是其他环境) b% k+ z$ [  z$ ~  h
    如果是浏览器判断浏览器内核类型
    ! z$ N. ~, F- w! f- Y9 c0 s9 v如果浏览器不支持requestAnimationFrame,cancelAnimationFrame方法,改写setTimeout定时器1 y5 h' @% @- Y
    导出两个方法 requestAnimationFrame, cancelAnimationFrame* k6 C, \: ~. t; D" K: D& R
    各个浏览器前缀:let prefixes =  'webkit moz ms o';
    & C4 ?5 ~- o% \2 O8 c4 {5 m- A判断是不是浏览器:let isServe = typeof window == 'undefined';
    8 L. B/ P; w# E0 [6 z增加各个浏览器前缀:  
    1 O0 R: [  E/ hlet prefix;
    9 K' |- N6 \; X+ {$ W$ \let requestAnimationFrame;. x* B- |# y" l0 P# c) U
    let cancelAnimationFrame;) U6 K/ A; z" z8 a, ]2 v' P9 K  @
    // 通过遍历各浏览器前缀,来得到requestAnimationFrame和cancelAnimationFrame在当前浏览器的实现形式
    9 H% T: d# D- B+ t    for (let i = 0; i < prefixes.length; i++) {! H/ [. n0 _5 ?) ^, _" j: y
            if (requestAnimationFrame && cancelAnimationFrame) { break }& Q7 j# M1 I; ?
            prefix = prefixes, G" W# d# Z4 f2 h5 ]
            requestAnimationFrame = requestAnimationFrame || window[prefix + 'RequestAnimationFrame']
    % t: s7 G- ]& Q5 B& l4 H6 B        cancelAnimationFrame = cancelAnimationFrame || window[prefix + 'CancelAnimationFrame'] || window[prefix + 'CancelRequestAnimationFrame']+ h8 k* E: z' N, q
        }
    / i  S4 ?0 w6 e9 c4 c+ w; W/ W  B7 N0 g) R& T& p
      //不支持使用setTimeout方式替换:模拟60帧的效果
    1 A8 l/ L% O; [. t3 \- L' A  // 如果当前浏览器不支持requestAnimationFrame和cancelAnimationFrame,则会退到setTimeout
    7 s) t, f/ b# i! g    if (!requestAnimationFrame || !cancelAnimationFrame) {
    + q  W8 r0 t( [' m8 t7 q        requestAnimationFrame = function (callback) {# L/ S, j' H% b/ G/ }: \
                const currTime = new Date().getTime()
    # A1 e; B: r0 r! f            // 为了使setTimteout的尽可能的接近每秒60帧的效果( i1 N; p7 Q' U+ \" J9 l: W$ O3 q
                const timeToCall = Math.max(0, 16 - (currTime - lastTime))# Y  c8 w0 N4 T. D- Q- n
                const id = window.setTimeout(() => {" V" I/ Q" P9 K9 |) t$ }# k
                    callback(currTime + timeToCall)
    - e  R) a1 s$ }2 d            }, timeToCall)
    . `( s: z: G# E! f! }* ?6 f) s9 @& c            lastTime = currTime + timeToCall/ q, ~" a" l1 U4 \. r+ x
                return id, }8 l# Z, f* C3 k. ?: W% J5 b
            }/ E) z: {' j! x
    ! N( z: Z" M5 j' {/ z  q& w
            cancelAnimationFrame = function (id) {0 J3 x9 m5 d7 M7 C
                window.clearTimeout(id)
    $ z" Q- ?7 @, D        }0 d5 P+ \  k% O" W* x0 t
        }
    1 c8 Y4 t2 K/ m3 l( {
    " E* ]# c1 _4 y" T3 J1
    + B, H  q! x$ W* O6 d/ Y6 V' Q27 K1 V; _) c7 i+ }7 D- b, @3 ?9 w
    3) t5 N# R0 c& G) q4 T0 B9 |
    4# O5 e: S+ M# _7 `8 Y; {5 |
    5+ D# K0 w: y3 Q6 \; c5 Q1 L
    6- G! p. K3 Y. s4 ]5 L$ _' j1 l
    7# l! W0 B* V5 ]5 m% W
    80 c) Z8 W) l" j7 v; R3 @
    9
    0 Z4 G# a% B4 l. [" j10  ]8 V  v* c8 O; q6 X
    111 k5 Q) H3 r; {% X" G, U- k, e
    12+ V' @. h5 }+ S  z) |; d& g
    139 V% E  S8 v! r2 L
    14
    5 n, J- h: m4 R4 L4 r1 W5 A- r# n9 g# P' |15
    $ X& S5 A3 @6 Y# F; \8 u16$ p3 G( ?* r% P. w; R4 [1 Z
    17+ }- u- `: T4 S$ U& h( e; U6 P
    18
    6 c# o6 Y% t6 f/ V% N+ V9 t" a19& y  [8 l% Z2 a; ]. R3 Q
    209 n, T/ Z! L( b, b8 X+ T2 M
    21
    7 U- B) ]3 U$ g9 ^22! I: R" G$ f$ J6 U- y7 Z" C. F
    23
    4 j0 f1 ?4 T$ m242 S1 V/ q  \1 ]% M
    25, e0 I6 j. r/ \3 b4 U& I
    26
    & w, @. Q& f+ L3 f! s0 Z! E270 p) e" c4 v& \& |
    28
    1 P% ^$ ]$ A4 D/ n# u& B1 Z7 |5 I29
    7 h: s5 L) a0 g4 A2 F30/ N4 @! Y( K2 v
    31
    & D9 Y# ^4 p, G- v# c327 ~/ L/ z: a& s2 q5 V
    完整代码:
    7 `- L& E6 w- y; o# {# krequestAnimationFrame.js
    & \: i: b* V( r2 i0 S. N, U% D
    $ ^+ o0 E4 M% wlet lastTime = 03 {3 i# d, v% o  T
    const prefixes = 'webkit moz ms o'.split(' ') // 各浏览器前缀
    1 Y) P7 _' G  O" i9 W
    " X' B" c8 X5 p& w1 ]. ?! q% Mlet requestAnimationFrame
    $ E/ Q& G7 e- ~" elet cancelAnimationFrame2 Y. ]( y+ c4 X; J/ @5 F& J

    " e  @+ I5 x) r  Z// 判断是否是服务器环境- g0 u/ C* b' y* G0 p1 l
    const isServer = typeof window === 'undefined'
    4 ]( ~& \% F  ^" n5 k& [6 K& N' Bif (isServer) {8 f! e& N( Q( o; A* e3 E
        requestAnimationFrame = function () {% f& r$ v# h: s& R! j* O
            return
    1 S7 D& }( x; J    }) }  U/ A- B: U. w3 n: s
        cancelAnimationFrame = function () {
      S8 k5 ]) h- S  y1 X, C        return
    ( D; H7 u) }7 T/ i1 n/ E5 p    }
    " |5 b1 Y4 v5 D" b( }6 H% u3 O1 c8 n} else {
    - w* E) A) f- p, ^    requestAnimationFrame = window.requestAnimationFrame
    " y+ e, {4 O0 O8 I# p    cancelAnimationFrame = window.cancelAnimationFrame
    + ~- `4 U# K& M" x5 p1 Y  _1 }/ A. @    let prefix# {& _3 K# P5 \- w% R8 a5 z4 z
        // 通过遍历各浏览器前缀,来得到requestAnimationFrame和cancelAnimationFrame在当前浏览器的实现形式5 \6 R  ~+ ^3 o9 y2 M, [7 [3 E9 E. ~
        for (let i = 0; i < prefixes.length; i++) {$ H& v0 B5 j% b5 V1 ]6 U5 l% }6 ^
            if (requestAnimationFrame && cancelAnimationFrame) { break }5 f6 l* R3 [3 w' f/ `4 J0 `/ I
            prefix = prefixes+ D1 w, E8 y1 w* q. h
            requestAnimationFrame = requestAnimationFrame || window[prefix + 'RequestAnimationFrame']0 M& K1 H9 Y2 N+ H5 b3 s' M
            cancelAnimationFrame = cancelAnimationFrame || window[prefix + 'CancelAnimationFrame'] || window[prefix + 'CancelRequestAnimationFrame']
    0 I9 Y2 s6 v1 g2 E3 m" D7 B    }
    0 Y" H  l5 q3 E" h$ J
    " L4 h0 f: M# y1 O2 g; V' U    // 如果当前浏览器不支持requestAnimationFrame和cancelAnimationFrame,则会退到setTimeout6 N4 Y0 t; r2 E& J3 k  o( j
        if (!requestAnimationFrame || !cancelAnimationFrame) {4 Z; K# r8 p5 Q+ E% E
            requestAnimationFrame = function (callback) {+ e" s: K& r/ t
                const currTime = new Date().getTime()$ n5 }% p+ \8 y# Y( z' h! }3 S
                // 为了使setTimteout的尽可能的接近每秒60帧的效果& q& h- a# h+ s0 m0 B- q" B$ |
                const timeToCall = Math.max(0, 16 - (currTime - lastTime))
    5 D- K4 h" t: C! C! A7 v            const id = window.setTimeout(() => {
    ' q3 J. k, }0 P+ t# F* c" ?  \                callback(currTime + timeToCall)5 k! Q3 g, x8 R
                }, timeToCall), e) U$ A- f) K0 E  @) t$ j& ~
                lastTime = currTime + timeToCall: R1 y" B3 b6 _: U' G- G. Z9 w
                return id% W( X6 M6 w3 A# Q2 I1 D. M9 b
            }
    , L# F/ q) j- a' n7 ?7 Q! m& {* w, U, t" c  j
            cancelAnimationFrame = function (id) {, s: K0 S& X9 b5 s
                window.clearTimeout(id)  _% _% @, W  w' ~( W9 |/ L; @
            }
    9 S/ X  `# Y( U  l. b9 S" @- v( m    }- R- W9 E: p6 J/ [  u- x; b
    }
    1 i, ~$ ^4 K7 o* B- F% u& H6 {: \: @7 ^4 Z  r8 B
    export { requestAnimationFrame, cancelAnimationFrame }* L% k' S, s4 @- ?6 m7 l+ w4 d( r

    5 W2 L$ E# a+ P! G- M# k! P0 g2 ~2 O) n
    1
    ( Z" Q' l- G5 ?  v% ~4 b2( H) j3 ?. N, |
    3- U3 p# Z* K9 n+ t7 ]+ P
    4
    ) \/ U+ @5 ]) ~4 }% ~5, ^9 S% G2 [5 T' S# g0 n& z
    6
      e- C0 e' \# ~1 E2 I77 u5 m" _+ q1 O9 I% |
    8
    9 f+ I6 ^3 f" X1 p0 d* P/ {9
      _) T$ ^! |% t- E& n103 b, p! W* k9 k: S' }9 c- e* Y3 [
    11+ C9 u2 ^  x  z) w& q6 C7 i
    12$ Z% B& P. B/ N) C3 f! C5 V5 y
    13- }' l6 L6 f$ q8 N2 Z/ W
    14
    $ @6 |6 [! P3 v+ l! j153 O$ O6 o# R1 _' {, u$ {) X1 p
    16& E, P. R' C+ b" l+ X
    17
    % D. e( x  H% Y" K5 o- x8 L18; U  X9 w1 f! a9 v9 O
    19
    2 }" v3 v2 @7 b& a4 p4 Q20
    / O" g4 Y. [7 t+ v, p! x4 z$ M0 |210 h8 Z, ?& M# e& s* R
    22* h$ G7 R3 t  l: N6 K3 J
    23
    9 E' F' v: P# m2 G7 M! E24/ h+ X6 U# ]0 u1 S4 f" \
    25! P2 y+ d/ G9 T$ w: R, F. R
    26+ G* K8 {$ y$ t+ {6 K
    27' f) l# V& w& Z2 }; z" D3 H
    28( g8 H8 F8 F) O6 t+ w
    298 p6 i$ d6 D, {; _2 d7 P+ I) U& w: i
    30
    8 B0 Z$ e& g+ a9 B/ x7 R# L! V31
    % N! v  {! L" C/ |. L32' c+ Z9 J/ }0 P' ]
    33# D6 q1 l+ V. j. N
    34
    - g6 g  w  }% V2 E. N35% o+ c+ ?6 J, _0 s/ u# e
    36: p+ M% [6 `2 Q5 f) k
    37
    : c$ r6 ^& {: H& @; k1 [6 @; ]38
    , ]. s0 E8 H$ F7 o1 Y& [3 [! e+ F39
    8 Q$ U2 v) i4 E5 A$ w; v" w8 h40
    5 z+ N8 ?2 c/ B/ o/ w6 _$ l. [41
    ( L7 R5 M' u# Z& J& r42
    8 ^3 k8 }1 y, `6 B! f( F43
    / _+ _& ?+ M0 j1 O2 O( I2 d44
    % k+ F/ L: ]$ F4 Z0 _) }45$ B1 }& p7 T7 [" v9 {' C3 c1 T  z
    46( R, A8 _3 }4 s9 i5 T4 m; y( `
    47
    : [" W0 i# E7 l& o% |3 t48
    9 k6 H0 l6 D1 ]# x' v2 ^$ [; P+ RCountTo.vue组件思路
    , J6 B( n# {- c% N2 z; x首先引入requestAnimationFrame.js,使用requestAnimationFrame方法接受count函数,还需要格式化数字,进行正则表达式转换,返回我们想要的数据格式。8 [1 V- G" A" O( f
    8 Y. q0 p, }/ x) M, r7 ]
    引入 import { requestAnimationFrame, cancelAnimationFrame } from './requestAnimationFrame.js'
    1 S4 B5 P$ O$ P% w( O' o# Q1
    3 ~5 y+ m' A# K5 D; u. ~" o需要接受的参数:
    # n* s0 ~* t. @# {7 D+ e5 L* ]
    * B" O( A% r' \8 Kconst props = defineProps({
    9 B$ m- O8 L7 H6 Q5 ~9 N  start: {' f6 e. A  j* S/ e9 D
        type: Number,+ d4 _& r* ]( Y% \: \' b8 a
        required: false,
    / x) }" {( E4 ?9 J    default: 0
    : F/ @3 U, F! m, Z  s% @1 q1 J) @  },9 M" {+ h. t* q( I+ k) O) d. z
      end: {0 Z5 k! z: l6 [2 j/ O% Y  V1 Y
        type: Number,
    + Z+ `+ T' c7 N, `    required: false,$ }: d' j0 D2 t6 u  ?
        default: 0
    + I, w  b0 R+ S9 r- i  },* n: o& C( r0 M0 _0 H+ _  d" c
      duration: {; o5 I- z$ P8 M1 V; O4 l. H
        type: Number,/ T$ Q8 ]; g+ L1 X! J
        required: false,( l: D; p: ]& s$ h3 X
        default: 5000- q% R, v/ p  K, c
      },  M4 w, [* o8 Q* ~
      autoPlay: {% M5 d3 x0 D9 n/ l1 r2 @
        type: Boolean,
    4 }  q; B6 t, f- I3 w    required: false,' ]2 q* |5 ]6 I0 d" i2 ]( F
        default: true
    $ W  f, Y) _. |6 c1 U  },* X1 b* T3 \5 e) \' y
      decimals: {- k$ `6 ?3 `& M' {) [! ~
        type: Number,
    8 ^/ ~1 y1 T$ B: b& e6 A% {    required: false,& p) V9 ]3 D; {7 R! ^  m" C
        default: 0,
    ; g$ H6 s$ N$ \" r& O, T    validator (value) {
    # F3 u1 g# ^0 _. `( k0 d      return value >= 0) R, ]7 S; @( i7 T: V' M2 Z
        }
    ! e' N# }. V; G" D  },$ {7 g  U0 r- g1 c8 S$ k
      decimal: {
      O) F3 }  @, s, m" t2 V8 X& o    type: String,0 r  ~$ A9 |  Y% e
        required: false,3 }+ f2 Q' m* x' x7 A  ]
        default: '.'
    * t0 S6 @1 W* h  _6 ~: k9 j  },- B1 |3 g" e' l& B  @. _- `. a1 J; i
      separator: {6 P- h( H0 _( Y% }0 _7 X2 }/ B
        type: String,
    9 _" }  F2 e8 V. Q1 N& b    required: false,! ~4 J  I$ X* w
        default: ','
    8 U! F7 h: N- W  }5 J: r! e( ^# h8 l  },* i. Q2 j+ j) r# E- I% P4 m0 r
      prefix: {
    8 M0 i  y1 t; D& J( i2 m: y* n# \4 ?/ K    type: String,
    7 d' N  J( j6 U9 Q7 O) ^- O+ C/ o' [0 V    required: false,% F2 K4 }* Y: f# x- T& F
        default: ''
    8 \6 o2 l, {2 T  },1 \% {+ T9 [- b& O3 {& b9 Q% `! v
      suffix: {
    * J: O1 d2 L4 B5 Z) a    type: String,
    ( b/ N1 E6 U+ g1 A6 v    required: false,
    4 v, X' i* `. ?/ y2 m    default: ''
    9 M% L# M% J) u: R  },% m( u- @" ?$ {. F
      useEasing: {' O0 F/ m' h5 `' S9 c
        type: Boolean,
    8 A7 [& u8 U, J' J; U: o- O    required: false,, H( {) X- R$ ^2 i
        default: true
    / X# k$ Y( r- q. ]  },
    ( S1 y. ?( [& k/ z6 Y- g  easingFn: {
    8 A' j7 G) |1 W    type: Function,
    - I" R' R. P& P' S4 N    default(t, b, c, d) {
    9 q$ u  ?6 k& b% k" {- k      return c * (-Math.pow(2, -10 * t / d) + 1) * 1024 / 1023 + b;- }+ A3 V) G1 B& E
        }
    9 D+ [( Z( K" e) |  J3 i- K  }
    ! \9 j$ e1 ~1 ~: }& q* \})
    0 m6 g/ \! |+ Z8 Z. [8 h& K1 f, l; M& `3 d1 @( n
    ( M3 H+ {/ y5 l
    1# w! Q1 |5 L7 V
    2$ T- ~+ R( `( X6 k
    3  _0 ~; n/ \  X- w; O/ p
    4! s  H# l1 [# H( ]7 @& K
    5, F( O  r5 F, ^) Q; x5 Y9 ]
    6  [0 T, z, J" f, [3 M
    7! L* Z/ n/ R( I# m
    8
    2 H6 k( X! V6 Y6 i9
    . }; W2 ?9 y0 ^/ S( e0 M9 P10
    0 @, ?- ~8 y) O6 u$ e. i+ V11
    % ^/ f' @0 T* s4 M9 m3 q( t, a12# _' k3 E" I. s) X9 B# U
    136 ?& F7 f8 i9 X8 w, [" x9 [- t
    147 P0 C& @2 P4 O! S( j. o. v
    15
    3 m- z: ]6 X! o, W0 D  e9 U6 o16" g$ k' q* Z9 r9 M1 L) m9 C4 l
    17- ?8 V0 _, H1 j
    181 k1 l( g% S9 Q1 K' w
    19
    0 ^  s# E# k8 p+ `$ _20: l6 O% C2 P! `% j/ n3 _0 U# l
    21- ?/ P$ o9 e7 v1 c
    226 q6 c2 u. ^+ A" L3 j$ |
    23" e  p9 H. }% g- g$ w) L* W
    24; T5 ^! r+ \) ?& `
    25
    3 B1 H9 o$ p; l; }1 W' }& E% a4 A264 z0 A+ f0 i& t- m" L
    27
    * i& l8 H- @; i) p28
    , y! ?" q2 M$ q5 P298 M  r% H9 M: x0 ?2 C
    30
    * X! ?- \, @# @& a5 z31. _) m6 ~9 p% D) Q3 |/ C- K
    32
    $ x  G- S" X1 o, ~6 N33+ Q9 @) Z5 r8 H! {$ L) B  H  z- r
    34
    1 S9 y4 l& z# c1 @6 f# v6 x) \358 \6 z% W4 t2 Q; B6 b
    36
    + |& D( ]2 Z. C# F37/ n+ Y( ^- D- S- i/ _& N4 g
    38) \, e4 V4 O" _: a  _' T6 [6 H
    39
      n$ A8 X: J% {$ i/ J9 d* `$ X40
    - ~. n' |3 p* w3 v416 k) k& Q$ W9 ~7 q
    42" h, `- U4 G1 C. W
    43( E+ }! H4 O$ C  w1 n
    44
    - A0 m5 N" k( ]1 Z0 k/ k45. ~5 t0 Q! H0 g5 L
    46/ u& T2 z" `& @+ F5 F; I* V) r
    473 X9 j6 ^: b3 X% O- q8 e% z4 [: A/ p
    48
    3 G3 b/ L( ~; P1 D' |  F49
    : i# K3 l) B( w# J504 Q' O, P: \  Z3 e( x+ E
    51% @7 b: N1 z& h% F- Y
    529 ]  C7 X! C) O( p$ w) ?
    531 T0 l# Y0 k. U6 ~' H
    54( g  I3 K# |; x
    55
    $ K* C1 u8 t! {56
    % u* E( u/ y5 e& {. z) e573 f. h) V/ M* m2 `
    58/ l5 S: R% h  o9 [$ ]/ d
    597 W5 j& X4 p3 Y2 x  a# C
    60
    ; z4 k: f( a& M$ l8 D9 t5 d! X61
    9 X4 M1 x& `+ V0 a62% R$ ]* J/ y0 C+ n
    启动数字动效0 [4 V( u4 J4 O' T7 p/ `! X

    5 K) \5 M$ z, oconst startCount = () => {
    % J4 U& a+ b! i9 b- A  state.localStart = props.start
    0 t) l+ L' f8 o' A  state.startTime = null" E# T8 ]' ?0 p
      state.localDuration = props.duration9 N/ Z6 _$ m7 B8 n
      state.paused = false
    9 \8 U  t5 P5 K" e  state.rAF = requestAnimationFrame(count)3 f6 o* P8 E. `/ ^: p2 r/ R+ N
    }
    9 i. u. G. A' d& y8 n( ~  f' T! r4 j1
    2 Z4 z6 u9 k* C5 w; e7 ]2
    3 G. i( ?* p7 w' J* J3, [1 U8 e$ f; ?+ m
    4" }# `" j. {1 v/ Z, K
    5
    / f* _! o8 u  O64 T" |1 \4 g+ ~! n5 o8 w( l
    7
    ) h. n* K. e% z+ o1 g核心函数,对数字进行转动, x2 F9 R1 g7 m  Y$ B
    ; z# V. G! A& k4 F
      if (!state.startTime) state.startTime = timestamp; A) ^+ ]: s' k8 L, {
      state.timestamp = timestamp
    5 E' q5 c( I' {; ^0 p  const progress = timestamp - state.startTime5 X$ j/ Y% s* X" Y: i* @
      state.remaining = state.localDuration - progress
    9 C- K+ h" D2 D4 ~# A4 q  // 是否使用速度变化曲线+ L$ g: e/ S1 \. g' z( {+ n
      if (props.useEasing) {
    " R9 A4 n, k  i. E; [2 w    if (stopCount.value) {
    9 ^9 d8 x) l4 Q0 d6 ?      state.printVal = state.localStart - props.easingFn(progress, 0, state.localStart - props.end, state.localDuration)0 M) U$ n' O5 P/ J& E1 b
        } else {. m. c7 u( W8 _6 d7 A* f2 S- d
          state.printVal = props.easingFn(progress, state.localStart, props.end - state.localStart, state.localDuration)
    4 @1 C$ k( v; I    }
    2 K; c4 o+ f) |* p" O2 i/ E4 o4 k  } else {
    . k+ I- a. G4 t8 l0 f0 G( P    if (stopCount.value) {
    0 P. N) V5 Z" n5 P5 L0 K      state.printVal = state.localStart - ((state.localStart - props.end) * (progress / state.localDuration))
    1 }. T! D0 p# s1 n& R0 V8 e% }    } else {6 ]# N9 r- q: D/ C9 a2 d
          state.printVal = state.localStart + (props.end - state.localStart) * (progress / state.localDuration)
    ( z* E+ K, m' X# Q3 m& U; a    }2 s. A; w6 M# u
      }
    5 ]; l* x0 s8 q$ N& l  if (stopCount.value) {# Z" l  C( F7 E
        state.printVal = state.printVal < props.end ? props.end : state.printVal% t- e& ^" H3 o, ~/ E: l9 `3 p$ H# m
      } else {
    ; T6 d3 M) Q7 S) O$ l' O    state.printVal = state.printVal > props.end ? props.end : state.printVal
    " Y* X4 A! H1 g- Y, P  }' A2 [( `" @+ v

    3 a' X4 g0 W5 A% `7 A  state.displayValue = formatNumber(state.printVal)8 Z- M3 h  v, F+ ~
      if (progress < state.localDuration) {
    5 G6 Q- ], M( X3 U% \+ l6 I    state.rAF = requestAnimationFrame(count)
    ( [4 U# V! J% E; q+ Z  } else {
    . t) F* T. D, }, d    emits('callback')
    2 P/ p7 e) x6 G; H, G5 J  }
    & g* ~. I3 E, m! n6 w0 ]$ l( _2 |; l}) b& e6 ?  ~7 W) Q# v' \
    # ]+ d$ P* R% w: M
    0 y1 ^* E  o; N6 L: O
    // 格式化数据,返回想要展示的数据格式
    # _" A, q" ^1 I6 u! U* `const formatNumber = (val) => {' z8 H9 e& x, z, V( S/ x* d
      val = val.toFixed(props.default)
    ' A1 W" H* [8 R  val += ''
    8 O  u  M1 ^. p0 E. z7 v  const x = val.split('.')
    0 ]# s, q. F) P: u  let x1 = x[0]3 H/ I# s0 ~8 M1 p& K
      const x2 = x.length > 1 ? props.decimal + x[1] : ''  N7 y' p6 t" y- P
      const rgx = /(\d+)(\d{3})/! O3 }  \+ H+ e' Z
      if (props.separator && !isNumber(props.separator)) {
    % u4 B5 l$ h( q( y. _$ h% u$ d- ]+ c    while (rgx.test(x1)) {2 R# o8 J* k7 d
          x1 = x1.replace(rgx, '$1' + props.separator + '$2')
    8 o: \9 @& w4 B3 e1 d+ j    }& z) P/ Z" P0 y: E% d0 a; |- S
      }4 R. @) U$ v" q  R5 I" m
      return props.prefix + x1 + x2 + props.suffix
    7 ?3 y* r$ x4 Q! n}9 n' w& G7 {: e+ ~

    - Q0 }+ z# b4 X: A% T6 p/ ]1
    / y! W3 i! G1 ]; v- P* `2
    4 Z9 h, q4 f( r2 R2 b! V3$ T4 V: {: N- e; b) G/ Y6 a
    4
      ^- R( h& q) C9 w- P, x; \5# `9 O; Y  _$ L3 I9 `5 a6 W
    6
    ; \% ?, b' _7 C) ~8 `78 @7 x; u, X; J8 i/ @3 o! o
    8; O" x9 ^/ _' B/ b5 R% l
    96 R- `# S+ W2 }
    105 d; f, d9 j' V0 h+ X& F  y
    11# j; c- n/ y0 I! H4 m
    128 Z) y& B& k4 T0 D  e
    13# Q. R, H( D% j* \2 ^1 K0 O( ^+ _, ^
    14
    ) `; D, t6 _/ [9 @2 ~9 @155 `! \: g! i7 G4 Y
    16% g! m! q# h4 J; H, q+ M6 h
    17+ D; r0 V3 @' v( H! |2 C# n
    18
    ' y& y2 g0 X  _8 ?2 g" M) s- H" ?* a, }19: `, d1 j- V+ `& z
    206 e/ z/ Q! ~5 P. b% ~/ u
    215 u0 d7 y! K7 P
    22- t8 e( s$ y5 J6 T9 N1 P9 B- a
    23; o5 y& B( f2 M. I/ q  W2 E" ^7 ~
    24
    - A' k# r) Y, e5 K250 W6 l. I7 L9 z& c+ }5 u
    26
    ; l1 O1 q7 D; S0 G; K270 q% m  I: Y4 a0 B+ r( L
    28+ B  X/ a% Y1 D8 M( d+ o
    291 W- i9 R+ H% u" Q
    30& U5 {( U0 m% D' S7 v1 p
    31+ O5 i* b% p1 a/ V6 ?
    32
    7 [0 t1 H& X2 x. A33
    1 H: u$ J& H, l1 `4 J34
    3 W/ h5 T' e/ d( g1 p35  c, a5 s0 }1 A: M
    36: ~) h$ G9 o0 ^8 c
    37
    " T, U5 C) S6 y38
    6 h7 y& v* z$ L& c: \, \39; L' F% L" r9 ^$ D  P; y/ v
    40+ c0 Y7 [7 \2 K3 ?2 l7 d4 ^
    41
    $ G& V3 [  F6 J2 _/ j9 w! h42
    ' {1 p" }5 |! l! K4 ^0 Z) M9 G) s2 z; S43
    . R  e' q3 r: O4 w8 g6 @# p* D6 j# X44
    # e# }$ V0 W* _- O9 Q9 v45+ {( g8 L) F( P1 n  I# u, d
    46
    * r- ~; U; x' Q8 W47* z# @# N. w; R% ^8 h3 f
    48
    " Z8 D0 H1 f! X" g! B( V* ~. J9 N) F取消动效
    5 x$ p, I1 n7 s
    9 D6 g* P1 Q) g9 U// 组件销毁时取消动画
    ; W' f0 W# v, r5 d7 g- g7 _onUnmounted(() => {
    , V% B5 C. [3 t  cancelAnimationFrame(state.rAF)! Q7 w! K$ y# ~& i* U6 ~( z
    })
    * u8 Y+ ~9 Y: N$ t. g; F) b1- W7 S2 k7 ?4 V. I
    2
    " \$ s( L3 K4 U6 h3
    % g8 S' Y! y8 v  p+ Z& L! K4
    7 `" n0 g% w$ e0 J: {! B完整代码
    - G( `2 X) V% w+ e$ V0 i4 n! s  d9 L5 V0 K" j$ u
    <template>* i. k( D2 r. w; m
      {{ state.displayValue }}: ]4 x" e  V$ R8 f" ^
    </template>4 N( i. S: R% T6 l/ C5 l( X1 [

    6 C% U- M8 d  M4 p1 S9 L! T; ?<script setup>  // vue3.2新的语法糖, 编写代码更加简洁高效& N1 B; i8 _' t/ G5 ?
    import { onMounted, onUnmounted, reactive } from "@vue/runtime-core";
    ! \  [) m+ @: i+ Nimport { watch, computed } from 'vue';
    & D9 x! ^6 \( ^import { requestAnimationFrame, cancelAnimationFrame } from './requestAnimationFrame.js'
    ) H* u. w/ I! H// 定义父组件传递的参数* g- x( \( g% |' t
    const props = defineProps({. @4 }) }8 I& K  }7 _( Q7 m
      start: {6 F, m/ N7 S8 A7 V5 V9 y
        type: Number,
    0 d" E4 i/ S$ H( T    required: false,
    9 Q3 n/ M3 Q- Q5 V/ G" W    default: 0
      s5 C( e/ J) m4 y' _# a( H/ A  },
    7 F1 O. f- l* j2 j. ^  end: {, @# K, c% ]6 Y5 d
        type: Number,
    5 W1 Z; X. V! M4 A8 k    required: false,
      R7 e# F  E( m1 ~    default: 09 A+ b8 W9 n0 l- x  W7 Z
      },
    & f8 O0 m, E+ m  duration: {# o! p% V! M3 r4 G; v8 @( V/ b
        type: Number,
    2 ~$ @3 `: v) }& ^( G2 `# H/ A    required: false,& e; S) T8 E- H( J, n) K2 `$ z
        default: 5000
    % x2 i& |9 @: G2 J# Q& K  },
    ' \; Z: E/ A; _9 z  p  autoPlay: {
    3 Q3 O2 l5 C/ N+ E    type: Boolean,
    5 d( k$ p; L  c, P* H  I) ^+ o    required: false,0 Z! F3 I0 d" s# K
        default: true
    8 B! E6 Z2 g* w" a$ ^; r  },
    " T: q* T" j3 `; c3 x( P  decimals: {
    $ z( C! X: Q" f( ^) A3 \# E& P' ^    type: Number,
    # p( I) G# P/ R. p, }/ J/ l" X    required: false,; ^4 ?/ `9 s8 ]2 U
        default: 0,; l& D8 L; S& C, q  r
        validator (value) {4 Z; U8 L6 ^2 R7 ^5 G
          return value >= 0
    4 {5 y( @. s4 `8 z0 t" \, t) W8 y" h    }
    / T2 K4 C' n+ C. M" o  },, X% z: J3 C8 D/ ?9 L* b
      decimal: {
    ! A9 a& m8 q1 ^. q4 h8 k# R    type: String,
    % x# `% M' l5 r. I    required: false,2 H/ B7 R' x( [
        default: '.'
    , j" x! j7 L8 S0 t  },
    ! S: v3 s$ Z# j) m* Y  separator: {( ^2 n: O7 I8 y) w3 Z
        type: String,
    # X: h9 }' |; `; J    required: false,
    ; M% t( F9 `' x; y* b    default: ','
    5 E, j" W4 K, ~) e+ g4 y- a. B  },
    2 b: \* v) A" A( Q8 h  prefix: {
    1 q" y: O5 a  D# q( s: j7 k    type: String,' V$ X4 z' G% S4 z+ k* p! j
        required: false,, t9 H- j3 t! V4 A1 }' e& [; e
        default: ''3 l, T- ^+ N& l- v' t9 A
      },
    2 j) w4 y& ]. U/ S8 f# E' y7 b1 N7 J  suffix: {
    , C1 ^. l+ ~. S8 n4 f    type: String,
    ( E  P5 X4 e& D1 `  s    required: false,
    0 ?4 l8 [7 [. ~( z    default: ''
    ' P4 Q" M* l' k0 b3 i* S6 G  },
    5 U8 }0 p: [1 t. [  useEasing: {) J% D# Z' |* d" M6 u% r: }
        type: Boolean," t+ w) K% R6 X4 I
        required: false,
    5 A- f- g" G/ c$ T' ~    default: true. U& B. Q# e( g1 p5 Z( V* V
      }," W+ H! B: {8 F! n: w  P) T/ j
      easingFn: {' M: j/ ^- f/ l- a2 p1 ?
        type: Function,
    " W% C' h- N, G, b) s( r    default(t, b, c, d) {
    & u# A! D$ B( R0 b% ]" N      return c * (-Math.pow(2, -10 * t / d) + 1) * 1024 / 1023 + b;
    7 R# p8 y" g0 o" ^+ S  ?$ ?    }* G  u. L5 [2 ^0 }# X' A/ T
      }
    . `$ @2 [) P3 _! @+ |})
      |) G2 t( |& Y  G
    4 @- v* q( r% d. r% @const isNumber = (val) => {
    - A! X/ m, k% p6 X/ z  return !isNaN(parseFloat(val))
    , ?) O* _( Q: Q4 B, Z& k1 s0 C& C}
    9 H0 {+ ]4 z  X( ~' B7 T) N% I* i7 J
    + B& z- J9 l4 K$ A// 格式化数据,返回想要展示的数据格式
    2 I; ?, B9 Y! [/ lconst formatNumber = (val) => {2 W" ~$ @8 K* Y" p) i
      val = val.toFixed(props.default)( @. [; C$ v- }( p$ d
      val += ''
    2 @$ p) c2 N. t2 R* d/ r% d; m  const x = val.split('.')
    3 C: g& o* h6 j9 p" u  let x1 = x[0]
    4 [& z! N5 i7 h7 [! q! B  const x2 = x.length > 1 ? props.decimal + x[1] : ''
    + w2 b0 ?! K" i, k& e7 q* y  const rgx = /(\d+)(\d{3})/
    3 l% B, v+ [' N2 g/ z. D' j  if (props.separator && !isNumber(props.separator)) {! d5 O( K6 p2 @6 A' d5 H( n, D; k  K
        while (rgx.test(x1)) {7 J8 [5 g1 }# R) `1 W2 S, L
          x1 = x1.replace(rgx, '$1' + props.separator + '$2')' A; l9 |+ @. @: ^# D$ g
        }
    . |) f4 L; }0 E/ x, h$ [- y* b6 x  }
    " A3 V0 b6 m" j- A  return props.prefix + x1 + x2 + props.suffix2 p7 E$ O  D7 |+ y, `
    }; C) L/ q) Z$ x- T$ ]; c
    # E( _; G2 |6 p( l: m
    // 相当于vue2中的data中所定义的变量部分4 c$ q+ V2 E3 Z- M4 T
    const state = reactive({3 w! A8 \7 M+ G1 L5 R) R5 T. W* i
      localStart: props.start,
    3 b( Z9 v% Z. D* V' _( Q& _  displayValue: formatNumber(props.start),6 h1 W5 x: x. E5 Z3 a" h
      printVal: null,
      s7 g+ T8 M/ n; O  paused: false,
    3 O  Q+ {& h- H% D0 k  localDuration: props.duration,1 ^& g+ y! g* h
      startTime: null,
    ( `) r. `- f* Z" {  timestamp: null,
    3 Z$ Z0 l& {; z  remaining: null,7 e2 x$ w6 k7 f9 W: d+ e' d
      rAF: null
    # p0 {, Q5 q+ k1 h5 `})
    & `" `+ W+ g1 ]7 T5 E/ m
    ( |9 X" n% c0 I4 Y) m0 @* ~$ w// 定义一个计算属性,当开始数字大于结束数字时返回true
    " e4 s& P* U' u# V4 x6 Dconst stopCount = computed(() => {& r8 @8 ~. g' m  `) \. |
      return props.start > props.end
    * ~5 y' P- l3 c9 @" r})
    , m' [) r1 v; x; z: `// 定义父组件的自定义事件,子组件以触发父组件的自定义事件' o* ^% C% a, ~7 M
    const emits = defineEmits(['onMountedcallback', 'callback'])' ]( u6 s* A1 x& Q3 s4 W
    6 Q& k1 x$ `' v4 w; W
    const startCount = () => {8 x& Z' {: E( {: x2 r3 d3 ?
      state.localStart = props.start
    6 G& R  n& G9 P8 U  state.startTime = null4 Y7 B* ~5 b+ T5 V5 K. @
      state.localDuration = props.duration2 ?4 D, d6 b7 L2 L  P  `
      state.paused = false% h: Q. \# w5 B
      state.rAF = requestAnimationFrame(count)( ^9 u' i0 h! R. }8 C4 u) ~
    }2 d3 n; G) _5 I3 Q' G* p8 H" T+ _

    / v* ~$ l; N$ I# k8 t' e* {' ?watch(() => props.start, () => {! |9 O+ I- s/ @) m: ^1 b" H4 K
      if (props.autoPlay) {
    0 ~9 K# w2 ?& H    startCount()# r3 T, }1 M7 D4 C4 G
      }
    ' Q( p, G- ?" ~  X})
    7 n  |2 f. w4 c8 z! t7 n) k) }# a, u; ^& @
    watch(() => props.end, () => {
    8 F* S  \) A  p) s  if (props.autoPlay) {
    6 W% o; O2 t; l2 m+ D8 v    startCount()' O( |; B8 j8 T- s- ]0 u
      }: C8 a  b; E0 Y, h0 e5 E. E+ ^5 y
    })% S, s1 L1 {* D  v7 U
    // dom挂在完成后执行一些操作1 j, F0 o: g6 {( S% p
    onMounted(() => {! |1 T8 z; Q+ N5 B8 a
      if (props.autoPlay) {9 P$ A% m3 V5 e0 N
        startCount()
    7 F+ K3 ]: z7 x6 e  }
    3 j/ q8 W) X! S! w- z: r6 C6 N4 z  emits('onMountedcallback')
    # t  E! Z, ]: G% s  t7 l})
    3 n9 ~6 H7 B* q( p( e9 p// 暂停计数7 B& q# E" M  Y- j) f
    const pause = () => {) o1 z. j7 x( P- l4 j9 l) L* n& w
      cancelAnimationFrame(state.rAF)
    , l6 S& j' C" J, L: M}
    ) r% @, A/ |, a& d$ J// 恢复计数, L3 J/ N3 B( Q- ~" ^% g( Z" U' i
    const resume = () => {
    2 s+ [$ L& e4 S1 ]2 i  state.startTime = null9 f; z7 \0 O6 V2 C- @2 `
      state.localDuration = +state.remaining
    : E' `& ?( C4 O  state.localStart = +state.printVal" j( Y) o3 }! @: D# \8 w
      requestAnimationFrame(count)
    $ {" W& q! `+ d}
    / d$ C- L! \$ `6 T& j' L# L8 T
    7 z! F0 {5 B0 u5 lconst pauseResume = () => {
    3 N& m: b: e! n0 }+ I: N% `7 @  if (state.paused) {: J; d6 r0 i3 w5 C; _- C7 P
        resume(); S7 N7 v( [  |3 q" H3 L
        state.paused = false
    : x0 ], w- u# c7 ^6 ^0 o: P  } else {
    4 c. n3 X) C1 t6 q& J    pause()
    ' F+ q7 o0 R! i3 a& ^( p) P4 n6 m, |# B    state.paused = true0 y9 j9 O3 ~& h1 k
      }$ B1 e- q8 ~+ T+ N/ ^
    }5 w& M4 O8 a+ o/ D6 q
    8 o; v( R3 f4 P- X
    const reset = () => {* `: D* K5 |8 M2 Y1 q: n
      state.startTime = null
    : }# e8 v# c* {" P" D1 D  cancelAnimationFrame(state.rAF)
    ) I* D4 r7 K" R& H. F  state.displayValue = formatNumber(props.start)" s) J; h" W# a+ V% }- f) H8 _2 M
    }
    5 ], }5 r$ t- s6 i- f2 o' f
    ; G5 |1 G) E- ]9 a+ t, I2 ]+ u8 Wconst count = (timestamp) => {- n; z6 w1 c' \1 b" l: X  G. P
      if (!state.startTime) state.startTime = timestamp( ^: N: f; H' M% `& V
      state.timestamp = timestamp+ i( J% a# N2 l6 r# P; v$ W" t
      const progress = timestamp - state.startTime6 t$ L, ^* r5 k+ ~& q8 p# x# ]# n
      state.remaining = state.localDuration - progress
    : H1 {$ r6 F7 Z  // 是否使用速度变化曲线
    0 R2 B/ N" @$ S7 }: R; I2 E  if (props.useEasing) {1 H2 {1 M% S) u0 r$ \5 z: z. ?
        if (stopCount.value) {
    * o3 Y& p4 S0 L1 T2 e) U* m      state.printVal = state.localStart - props.easingFn(progress, 0, state.localStart - props.end, state.localDuration)1 j2 c  M" a4 F0 r& C# G' @  o3 g
        } else {4 @) S* K. d2 Y- K1 }
          state.printVal = props.easingFn(progress, state.localStart, props.end - state.localStart, state.localDuration)
    " A$ d3 ?8 s6 m% j6 }% V, ^    }
    8 a6 k7 W/ b! G5 _' y- q) G! }  } else {2 k5 W5 p5 l7 w: y' V, {4 s
        if (stopCount.value) {
    , k1 ~7 E- C: j" p8 |9 ?, `      state.printVal = state.localStart - ((state.localStart - props.end) * (progress / state.localDuration))
    2 B; `6 F, g+ c6 v    } else {* C  j2 Y$ B3 z$ J+ W4 c
          state.printVal = state.localStart + (props.end - state.localStart) * (progress / state.localDuration)
    ' E& h, k. h9 @4 i    }
    8 |, B% }; [: T6 V  }9 J2 a" z3 x5 a) y, |4 I) E
      if (stopCount.value) {
    , q! d4 J# s) G! |& e    state.printVal = state.printVal < props.end ? props.end : state.printVal, @+ k* F! g3 O& u( t
      } else {
    - q& P! U. a1 d) |9 `3 k% D    state.printVal = state.printVal > props.end ? props.end : state.printVal
    . `4 [2 P3 J! W5 n& F  }
    3 e9 u  j) p8 p* g8 w' v' K4 ]. _5 N  D- k6 \, s/ A
      state.displayValue = formatNumber(state.printVal)7 x6 f$ b& n( K2 ^9 c
      if (progress < state.localDuration) {
    5 X7 Z  |( a3 s0 P7 `1 v- }    state.rAF = requestAnimationFrame(count)) o% X/ A8 E" a
      } else {
    : Y! b7 o! [  P/ N) `" O    emits('callback')
    . b; C9 p3 J4 t  }
    ; I+ }6 X+ h( T4 h: A3 L}7 L8 P+ M9 B! v  N6 C
    // 组件销毁时取消动画7 N  j' H, L+ {- D2 P" D& m
    onUnmounted(() => {2 @% h5 q# N1 r0 ^3 k
      cancelAnimationFrame(state.rAF)
    $ q* K0 I3 ]2 D' U7 y1 U& _% w" E})
    . ^4 p  \+ d% h$ S</script>
    8 u$ ?: N) Q' M$ f& d
    ; V6 p; k* Y: U" l# K% R3 z1, Q* S- a* G7 W! v) Z
    2; q6 A% _$ U8 V+ g3 ~1 q
    33 }, F! P0 h% C+ k  \
    4
    " S; r# D9 d/ m* c1 h' n& ^5 h, L59 O7 ~" ~# S* p7 W: S
    6, n4 d+ V1 x# w3 j6 v4 v
    7# L  l/ P8 K5 F$ _  f% E" a, _) F
    82 n+ Y/ z  e9 E- g5 K
    9( {7 Z/ W% w, {
    10
      U3 ^* E& U- }# [; }1 C- {1 M9 c11# f3 _: @+ x4 F/ f9 J
    12
    + y5 @% i' u: P# }; s5 {3 [13, {3 l+ I* R/ Y% [$ H
    143 i7 `* H7 T7 n. b3 G
    15
    1 @9 I4 u) _% ^* n- ^169 @- O. K8 M7 y# ]
    17
    * ^! F6 |  D* v- d18- |* J+ Z% Q  u  M7 n! j( [
    190 H6 P4 u# \* [1 J
    20
    3 ^* m2 Y  a" I" ~# }0 x8 i218 Q0 i4 A/ @% I% z6 I5 m5 J
    22
      ]; `/ z. Q. ]" U. k6 `4 o23
    % Q: `8 o7 L. w; r/ F2 `1 V24* E" i# o5 U- D
    25
    5 Z3 U! J$ q$ z" L. |3 s26
    . `' C9 v$ V4 P  t27
    " ]4 R1 T& {6 P/ t; Z* a28' C! O) ]) C  O" `
    29
    $ n( m: h7 e+ A$ x6 W6 x. K. r30
    2 G+ L3 r# R: W; r0 ]1 Z: X. p316 q1 }1 N& x% ?2 i9 v$ e4 h* A* W; [
    32  _  m5 q4 |7 T* r1 Q
    338 {1 ?9 @7 C; }# `) H  M
    34
    + N/ f+ d6 I# C) ^' Q35# p" Q8 M8 _+ k$ V' \
    36
    & i* ?7 r8 V7 x8 p37. h  x; ~2 O7 u7 n; w
    38
    , ?$ l' l+ |# W; e' ?5 i39
    ' T2 Z6 s) W& \0 Z8 m9 h% U40
    4 @) N0 _. Q' n" _4 ]! T# X1 k417 ]2 [' @3 D- }. m3 m+ z1 R
    42$ f$ \1 I& p/ b; L2 t
    43! T7 X! r" B0 p
    44
    - i" v! z* {, D# Q45
    % R' S- o+ f# w  s* W! ~0 E0 ^46& O0 o( `! M+ G  ?$ C
    47$ W6 N9 W+ C! E: k6 \
    48' G2 ^* Y! v0 a( H5 o
    49
    ; C' `3 Q0 x1 i0 U$ P50
    2 Q, w3 q6 y2 t. H0 `" c- o518 m- h& Y2 I& {* {# ?8 f) e  B
    524 `1 S- w- O$ e) G: J% K
    53; R  }% S, l! h) o  y
    54
    7 s0 M7 t3 \  V" B5 w. j" o& ^55
    # b# g; B# x: S1 h56: j# w: e. c3 z  Q, I# D' F
    57
      D# t% F, v( D588 j$ X9 f6 m0 V" K' o9 x4 P
    59
    ' x8 H. v; g* Q$ M0 K4 W60
    * j- o, r1 Z5 a8 h3 [61
    8 \* I: a! L( S. o( e% ^62
    9 e  m; _' I, @" g1 Y" f63
    ! J; c% g* h1 D2 V0 ~2 l64
    % D' z: e! q9 `: y9 a$ D2 Z65
    7 j( t6 B7 Y5 R) X  n6 B66$ H6 y# U' S) ~) Q
    67
    ! w$ f" W+ ]; h& Z* K( M& Z68
    . |" T3 ^/ |6 d69/ J' @  D6 {$ z. x1 a& |& H$ G
    70
    / z, Z% U0 }0 B71, i/ _* b& r6 n8 ~
    72
    4 a# N! Z2 x* ~" U8 T73( s1 y: g+ A# L3 j. \% @. q! K& `
    74
    5 ]4 }' y2 M3 R; P4 v75
    6 \2 \* y: E1 S$ F/ y76  |  V: v! k5 _* N4 }: a
    77
    ) t# r7 v% P% g% o  l6 h- q0 S78& H, O" N# x0 f0 {) P2 |2 u
    79
    0 n. z, I2 u9 l% d+ C80
    4 _4 h4 r5 O7 i* j9 k0 ~, [81' l% c# h7 Z% c9 P* Q" g4 W( a! m3 w
    82
    $ @3 S; X* \; a! v3 E83$ l/ G  r" {* o, C
    84
    7 z; K5 Y; [5 i# B! ]85
    3 n# r- |& h" h$ D86
    ! H% b7 Y' w8 @87
    3 T* A2 `# D, n( k2 A88# |& z, K  K8 D; L2 j1 q
    89
    * u4 ^5 r% V2 m& b( d" Y+ c90
    0 U$ \5 v( h" l, g% l4 M91
    4 E4 C) P% D; Z8 R; t7 o92% w" N( w: a8 [2 B: }
    93
    * o; J0 s1 [2 T942 V2 I' Y( i3 i* f, r
    95
    6 E$ G5 H0 c; W4 V0 O96( B  n% Q+ [" z/ B( Q
    97$ K+ r' q8 |, R
    98
    3 }, B4 I% I6 M9 @; t/ x2 d99
    7 _2 V, s) T2 w100
    % v  \7 ?  w) l101- ]( Y4 ~! X7 _3 N. J$ ]/ P5 G
    102
    ; V: ]6 i7 B' u9 o$ g103& M6 L9 x' n" @. W, {. O
    104$ V( N& g% Q5 ~+ m" c" t/ v
    1056 U: l5 `' H; y. M* V
    106
    ! x: r6 z: D2 C7 p* h! P3 r107
    5 n- F, K5 T% K5 F108
    & d8 s4 y! P' n3 T" e109. U2 ?  Z1 A/ D+ }, ]' ~) s* X
    110
    4 J6 d( d5 u- q9 y0 p6 ]9 \& i111! i8 Q  w8 J. P9 f, Z
    1125 w2 b0 Y; Y/ \6 B) |/ c6 l. r
    113, [" I$ h0 U" h: X4 U* p- Z
    114) L) a( s1 @9 D0 ?/ y; x, ^% ~
    115' i. h! v; M# y: S
    116$ [" u1 b& R( H: W: o
    1173 [! d5 }# R! n: V* ?
    118# F" Q" P/ A7 Y" |3 {" k0 X
    119
    ! S' C, N  u6 l6 Y$ D120
    1 E4 [& y9 E1 _/ s7 y" @- V* ~' ]1212 m& |1 \2 j! Q7 q6 V
    122
    / I' y& ?- ^. a, \1235 L' s9 x% C; ?, I" Y7 [
    124
    " f8 C  h' x  I- I; b7 A8 y1258 x5 \3 D' B5 {
    1262 d6 i) k4 e9 c* U& a. s+ J
    127
    - y/ \: R1 `. V5 k: [# ]; V( g& [4 g128
    % Q4 [6 t+ K7 A& ^: C; m! a2 Q129
    9 y# Y: l# w. `130) Y$ K& q: \' F& o
    131
    6 j- k# p( T+ U1 u, c- Y9 G132% n" H, V+ I8 V: Y/ T/ z
    133/ S; M$ Y: K7 K& _! t. y. Y
    134
    % k: [  B  r8 w  i7 W135
    # z+ q& r% d3 m136
    7 W. k: K. Q6 d" ~" ~* |6 c# ]1374 a9 ~5 o- m1 i- n! c
    138
    3 y! E. ~0 M' y2 }& p/ R139- l& K$ O. D( S2 L1 @+ x5 q1 E
    140, v" Z, @3 ^/ K9 e) G+ U
    141
    % a+ x2 z5 w/ a+ M3 c* A142
    ! x0 k& q0 K( J1430 D) Q' w% d7 i: N) r) }
    1447 m8 s0 X! R  R0 R9 W- S: G
    145
    ; i! ]1 u* g; I* A146
    ; y" A* |3 c6 n" h9 ^$ n147/ b% s0 P( \. ~# |+ z
    148
    . B% Z0 N2 V! x0 s5 y149
      o$ H$ S# s! s. @1 ]6 {. w150* o. s# i# i7 b. Z( V! ^: E
    151- p" S1 @# f/ S
    1522 a! x" }, ~9 `
    1531 i) k% w( V1 k$ Y* Q
    1546 k& t+ [9 F( L; A7 ]
    155
    2 S0 z( j0 o' J& B) f: z6 T: T6 v156
    ' z4 O. R! y( j1 ?+ J* @157! E5 h/ d6 F/ V% a% g
    158
    ' C+ i; P  z1 S$ i1596 b$ G) h" I3 N4 c5 \$ @5 G. h
    160
    $ ]4 c! X. n+ e6 ^, ~/ p1 @161' E% i+ j. @6 A3 G
    162
    : \  a: [8 d0 n' |" T8 r  |163
      z+ k1 W. C3 Q# L4 e' v1642 a: z  l! I; N3 h( e  W
    165
    % f8 i+ v. R4 i0 Q7 f; J3 s8 e. X( R166& \& T. u5 {2 K; n) e5 D0 ~( U& w
    167% _- s) m. A. [% l* O/ s! P
    1681 Z0 G, ]& \3 d: X' J4 @
    169# G, g) V$ s3 ]" W5 _) J
    170
    9 }: [) \  b7 h. k; z# b7 |* K171
    6 {/ t) `  Y3 E$ w" Y! w172; b6 A$ B6 M; P( j' |
    173
    ) ?# L# s: c8 A: j. L174
    2 z  ?- T( u8 X" N% V175& d. v, o+ U2 y0 D
    176
    5 f% B) q' Q4 J+ }# j2 e& [7 Q177$ T, H2 x8 Z) h; P9 X
    178! j" L% F# |$ E; H2 q" z) n
    179  e- y" c0 V& ?9 N
    180/ V8 g3 I& u0 G, k( `. Q
    1815 `$ w+ t% R$ c
    182& z0 V4 E' [& N$ v1 u
    1835 J2 L% N! C! J: w
    1845 ?2 y; j1 }9 z0 x- u
    185* X) W! F3 r4 r/ b
    186
    " T) @! ^! \% w- `% l( W. r* {1877 x; @- ^- c: b* F
    188
    4 x4 u' Z6 U2 U4 r; u) C, x1894 Y: J2 V/ t- L. D: [2 a
    190* i' y" Q0 c- Q
    191* P! E! b; K/ {& U, r  i
    192
    6 G# ^* Q( J" K0 l. C* p9 k- D193+ a4 c/ ?& z3 g, U
    1946 |) X) X8 m9 e+ ~( |5 r1 W
    195
    . X( _2 D5 Q1 Q4 B) `1964 ^' u6 ~: ?3 `5 C
    197
    " [4 `* [& Z: Z' z9 b, u; D: _198
    % P# q2 F) a+ D9 G0 D' l2 Z1990 x! T  i$ s* |$ Z/ a5 z
    200
    4 q' P" K  o: m; l7 ]201$ X* Q% W4 N6 J, U; d$ s4 Z) Z# f$ D
    202+ C7 l. b! d* F0 w; d; n& Z% T) ?9 y
    总结& z  s8 t- Q# o' T5 l+ ^" p
    自己封装数字动态效果需要注意各个浏览器直接的差异,手动pollyfill,暴露出去的props参数需要有默认值,数据的格式化可以才有正则表达式的方式,组件的驱动必须是数据变化,根据数据来驱动页面渲染,防止页面出现卡顿,不要强行操作dom,引入的组件可以全局配置,后续组件可以服用,码字不易,请各位看官大佬多多支持,一键三连了~❤️❤️❤️
    4 ]9 f7 h" h# `$ u3 ^
    ! I+ c1 Q# {6 t$ ]/ ~demo演示+ J3 m7 j* R- J# Y5 F# O
    后续的线上demo演示会放在; S& m6 B$ C! g& }- u. `6 ?
    demo演示
    " S  t8 a5 q7 m8 T完整代码会放在% X  s* \% r: H) o3 R! Y+ x7 D2 ~& S; i
    个人主页
    . {  W9 n7 u( K
    ; ^! j6 ~& A2 p% L# {+ [+ [& e. M( e希望对vue开发者有所帮助~/ {$ U5 O3 ~) ]& K0 L0 A- P
    9 ~5 N; M; ^( m) I
    个人简介:承吾% }1 @2 A) m6 f8 W8 R% {) E
    工作年限:5年前端
    0 ~+ x) l0 z# Z8 u+ D. }0 E1 r地区:上海- B- H. a# k9 u9 w; I  l
    个人宣言:立志出好文,传播我所会的,有好东西就及时与大家共享!8 A, a8 E+ L5 r; P5 H4 J

    7 h/ p1 X" ?6 }7 R; P7 k8 N2 m& b
    ! r$ h& D, t. V; v% [2 X3 j) Q2 e; ^7 o' k5 j7 h& X. ?
    / D$ `9 s% j, O
    ————————————————
    6 X$ D" a/ d5 ]7 ~* ^0 j- n版权声明:本文为CSDN博主「KinHKin(五年前端)」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
    9 `' E1 Q* o7 v8 m% g" y: d原文链接:https://blog.csdn.net/weixin_42974827/article/details/126831847
    & d: Y5 G9 ~9 v( K  `
    # X; j3 w! x# T* Y' _  f. d6 @$ Z: ~% a5 X9 T& t1 C* P
    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 03:40 , Processed in 0.485349 second(s), 51 queries .

    回顶部