- 在线时间
- 1630 小时
- 最后登录
- 2024-1-29
- 注册时间
- 2017-5-16
- 听众数
- 82
- 收听数
- 1
- 能力
- 120 分
- 体力
- 565164 点
- 威望
- 12 点
- 阅读权限
- 255
- 积分
- 174772
- 相册
- 1
- 日志
- 0
- 记录
- 0
- 帖子
- 5313
- 主题
- 5273
- 精华
- 3
- 分享
- 0
- 好友
- 163
TA的每日心情 | 开心 2021-8-11 17:59 |
|---|
签到天数: 17 天 [LV.4]偶尔看看III 网络挑战赛参赛者 网络挑战赛参赛者 - 自我介绍
- 本人女,毕业于内蒙古科技大学,担任文职专业,毕业专业英语。
 群组: 2018美赛大象算法课程 群组: 2018美赛护航培训课程 群组: 2019年 数学中国站长建 群组: 2019年数据分析师课程 群组: 2018年大象老师国赛优 |
vue3 | 数据可视化实现数字滚动特效
5 K( H4 s3 x4 j; O- D5 L6 i- ?9 B. o( p) T& e3 N
前言
# [8 s& B, m6 k' c& V1 e0 ]vue3不支持vue-count-to插件,无法使用vue-count-to实现数字动效,数字自动分割,vue-count-to主要针对vue2使用,vue3按照会报错:
2 }! ?! X& a; BTypeError: Cannot read properties of undefined (reading '_c')% p2 w/ v% C. {4 F9 Q
的错误信息。这个时候我们只能自己封装一个CountTo组件实现数字动效。先来看效果图:
+ ^' g H! v7 A+ A3 P* q, d
* T. u' |7 z. H! K5 r2 s' B% ~5 w. A% H: G0 \& O9 C
思路, T$ G5 Z. _0 O" H
使用Vue.component定义公共组件,使用window.requestAnimationFrame(首选,次选setTimeout)来循环数字动画,window.cancelAnimationFrame取消数字动画效果,封装一个requestAnimationFrame.js公共文件,CountTo.vue组件,入口导出文件index.js。
$ x8 `- n6 v2 n, K9 ^# o
- b$ l0 W: }! ?) M7 a文件目录
) |8 A! J% S- B8 V. O3 J4 ?- J0 {
' h- Y' e% C+ j) W/ s% y! ?使用示例
) I) H' P$ ]' H2 {. V<CountTo* \1 V$ X6 \. [4 ]' I1 @
:start="0" // 从数字多少开始
) P/ }* g; A1 C$ h% U1 _, m2 N :end="endCount" // 到数字多少结束
& m! I! m4 Z, m2 n0 o! n8 v :autoPlay="true" // 自动播放
1 F9 p( U! T7 S :duration="3000" // 过渡时间
9 @8 n, Y( Q+ x* O5 P# B2 H) L prefix="¥" // 前缀符号
2 r8 u) E M( b5 g: ~ suffix="rmb" // 后缀符号
- p P" q4 C8 K' _ />- |1 S( T2 g6 [( j
13 q, I2 L" F( e6 W
2
: f# J. B% r6 D37 O$ O! w5 ?0 _1 \2 @4 U$ X/ s# d
4
5 r0 _0 r7 A: `8 p8 ^4 g2 h5- m4 ]. K# n. i, Z9 T1 e
6
$ o7 w5 x z9 Q9 J9 h+ Y* W7
. Y* j5 P5 ]3 T) a5 [3 y8$ K0 E5 b+ m0 n
入口文件index.js
$ m7 X+ q- W E4 w% U# @
, \6 J7 J- a: C& `5 Dconst UILib = {9 _, }" S3 Z% t+ }! p
install(Vue) {
; V; i& ~+ `2 o: Q8 U/ w Vue.component('CountTo', CountTo)3 Q X9 _1 ^% o5 y+ J
}
" V9 D- W: T2 m}: L' y8 @% f# x; V/ Z! z' m! n- d% I5 w
# S3 r% X' S8 _2 K n3 g- F
export default UILib1 Y o* Y, h2 I2 K- `0 o
9 y s8 s. q- K) ^/ Y1
: i4 r: o9 [3 A- s& F2' C" B- j3 V# E& |- I
36 s" ^' g! D" V( a
4: p- _, X9 W0 x, B- U
56 J/ L9 F4 n. C* X
6% q/ F% G" J3 T. a. {+ r
7. a! p7 q/ [$ Q; y2 J3 K
8
- l- i% H/ T# u5 @9
4 Y& S# R) }$ Q7 l( I: mmain.js使用1 R9 C# S" g1 J9 \) Q; F' k
import CountTo from './components/count-to/index';
6 L# H) l# n$ S. _/ x, @app.use(CountTo)
+ _7 S' E$ G" V( H y& P1
1 r! G+ J8 G# M2
$ V0 M2 H0 ~( d& c0 ?! a( l0 LrequestAnimationFrame.js思路
: I8 g6 j* ?! G& c先判断是不是浏览器还是其他环境
3 [) s6 n' t' w* T3 C$ U$ V ~# c5 ]如果是浏览器判断浏览器内核类型& ]( z* t$ c; ]& ~
如果浏览器不支持requestAnimationFrame,cancelAnimationFrame方法,改写setTimeout定时器
z- d: j% f6 B7 h6 f$ `导出两个方法 requestAnimationFrame, cancelAnimationFrame* h4 U. q, e0 |, {% }
各个浏览器前缀:let prefixes = 'webkit moz ms o';3 b4 |2 c2 K3 N7 R9 \
判断是不是浏览器:let isServe = typeof window == 'undefined';
; t* e. P3 c! `. t( u增加各个浏览器前缀: 9 O; y% H5 D/ R4 ?, |; J- y/ G
let prefix;
: \) {5 D% n2 n) f4 b/ ?let requestAnimationFrame;
: E" k$ U6 m) B* k5 `4 r3 b$ ylet cancelAnimationFrame;1 T. L3 p2 ~% R; p$ |( c2 N
// 通过遍历各浏览器前缀,来得到requestAnimationFrame和cancelAnimationFrame在当前浏览器的实现形式) T; {8 Z' v6 [$ P4 y
for (let i = 0; i < prefixes.length; i++) {% l1 x! z6 D% R% p3 K
if (requestAnimationFrame && cancelAnimationFrame) { break }
: m Y! d# b/ D, P" x prefix = prefixes
! L0 u9 i& F" D2 i8 w! Q( N requestAnimationFrame = requestAnimationFrame || window[prefix + 'RequestAnimationFrame']7 L. J, E* A, h! l4 t. X" i/ {( J
cancelAnimationFrame = cancelAnimationFrame || window[prefix + 'CancelAnimationFrame'] || window[prefix + 'CancelRequestAnimationFrame']
+ G0 x1 O; G. a( S3 a* T* Y }" `/ c% F5 z+ A+ s7 [9 K
5 {, s, @7 M% j5 n4 U //不支持使用setTimeout方式替换:模拟60帧的效果9 V. z. h- r l( [* }) }: K8 v
// 如果当前浏览器不支持requestAnimationFrame和cancelAnimationFrame,则会退到setTimeout
1 u) x5 V7 O! g" |2 K if (!requestAnimationFrame || !cancelAnimationFrame) {
% x' d0 g0 X4 h' A$ D requestAnimationFrame = function (callback) { X6 ]( B" n% N; V. F
const currTime = new Date().getTime()4 Y+ A) M( @# `9 v! G- c
// 为了使setTimteout的尽可能的接近每秒60帧的效果" M) C) D, t( j4 Y1 e/ R
const timeToCall = Math.max(0, 16 - (currTime - lastTime))
: |. b y1 b7 l5 t; | const id = window.setTimeout(() => {& K% x& F$ h1 @2 b" e) Q
callback(currTime + timeToCall)
2 U) z& v' q% P9 ~" U, ~ }, timeToCall)
2 u3 X* b& ?- X2 a/ A/ C& G lastTime = currTime + timeToCall; ~" O& g; b1 _8 R0 {! @
return id
7 F% [: R! q8 ^3 j }" D/ ]) w* D0 e: ^
% u, p1 Z) g7 o$ X8 N7 P2 w cancelAnimationFrame = function (id) {/ x% m2 ~+ R- X0 R
window.clearTimeout(id)4 S# O6 u5 k; {8 N) u
}1 Q* h9 d4 @0 D4 W5 ?/ A/ [
}8 V8 h+ y1 H: g6 a! F7 _4 k
( p) j" } ?' G: R% [
1
; C/ ~, C* T" p, w! G2' w9 e) r2 W5 m) {5 N3 T
31 A3 O" k) ?; o1 u. z, \0 t( ?
4
' Q+ N" ]7 _( e7 \5
3 l$ ~; d; e2 a( c! l6
: [" N4 |& y% Q" D6 U7
2 h0 W) D% }" H# n8
$ |% |$ h- F' u. O2 f' |9
' `( T* |, X) W1 y& f0 s10, f0 R1 ^6 {5 u; w- v3 j
11% v( m; v# p2 C- o5 W1 j
12# ]/ o) [6 o4 h2 A9 x; t
13
5 v1 P& r" m [14
8 c+ ^( D" \) q c4 X155 y' m$ v2 U7 m& U3 f) _% Q( T
16
3 b. u( {% d0 s9 }* ?! g17
; e: e6 @: l4 G' i0 ]+ D+ H18
( A% H% M3 G O% e! ?# J19
1 ?- O: N) t6 S2 ~; h20
1 o4 c1 T+ @& `4 O' L8 `4 v21% u3 y6 h* e3 S+ w! C
227 M# q& a8 p! |+ n: w6 V' S
23
0 N6 y( D+ L& o242 k9 N- g+ p; L6 d2 B# D
25* p/ r ?0 o1 l. O) c$ \, W6 R
26
! u1 a* ^% V% l* f27
4 e1 M' W! \, I, S) S% s281 Z. \8 B/ c! w/ ~& }& I
29
( q1 Q, r# f8 f' L6 X( L- c( J30
$ L6 g+ m+ c" j* G% }5 `7 R: ~* U31
9 G% p) i$ @% i: D# E. e323 j& V1 V, Q$ x! _
完整代码:
$ n7 S7 A3 _8 ErequestAnimationFrame.js1 O9 J4 S% C. S2 O8 J& A
5 S5 G2 h S3 V! e
let lastTime = 05 j. a5 w7 I. ]1 {& p
const prefixes = 'webkit moz ms o'.split(' ') // 各浏览器前缀8 x7 R$ ^! @' ]) @
/ K. P' a3 w# f7 }, _let requestAnimationFrame
5 W( [: u/ b0 T$ T8 Dlet cancelAnimationFrame7 A7 R- W# k9 r$ ]$ Y
5 q- n7 d$ _) R0 k# J7 c
// 判断是否是服务器环境, j* |+ h3 P2 r
const isServer = typeof window === 'undefined'
( R+ Z$ E9 V/ I, t6 Xif (isServer) {$ ]% W9 {# W. g( H
requestAnimationFrame = function () {
) A5 |& w" v+ A2 Y$ C return4 K# ]9 r) Z/ T% o) }
}, s2 h* f2 ]3 i# i( m. X" A5 n- Z3 a
cancelAnimationFrame = function () {
( x0 W( o# K: b8 q. s return
# {/ G' s- C& E2 d2 t }
) L8 [" ]' C0 N} else {+ w! E: f5 Y9 d
requestAnimationFrame = window.requestAnimationFrame
5 l7 w, j) L) h; R# _3 B) z cancelAnimationFrame = window.cancelAnimationFrame
, }& I) B" X R1 q let prefix# v& V. T- L( e, D
// 通过遍历各浏览器前缀,来得到requestAnimationFrame和cancelAnimationFrame在当前浏览器的实现形式
# k. @4 A) ?; G for (let i = 0; i < prefixes.length; i++) {' @8 \9 J) Q4 E3 y
if (requestAnimationFrame && cancelAnimationFrame) { break }- d* q% S2 k. n- A/ X0 S, _5 H0 h+ G
prefix = prefixes2 {" T9 i$ _6 E0 k
requestAnimationFrame = requestAnimationFrame || window[prefix + 'RequestAnimationFrame']
2 ?/ b3 j7 [: K" S; T cancelAnimationFrame = cancelAnimationFrame || window[prefix + 'CancelAnimationFrame'] || window[prefix + 'CancelRequestAnimationFrame']
* ?" p" ~/ f7 [1 O- } }
" z9 w* T' d* v a! `# z) u1 H" A, Z r1 V
// 如果当前浏览器不支持requestAnimationFrame和cancelAnimationFrame,则会退到setTimeout- O8 h, K7 d3 F. `9 w
if (!requestAnimationFrame || !cancelAnimationFrame) {
- i/ J. r7 e7 P; [* R requestAnimationFrame = function (callback) {
* F A8 F2 X( b2 Q const currTime = new Date().getTime()6 h$ O: S; K' V. w4 T6 k+ R& m# a
// 为了使setTimteout的尽可能的接近每秒60帧的效果8 Y u& v- v6 a+ b3 R
const timeToCall = Math.max(0, 16 - (currTime - lastTime))
% N* b# ^0 g( E9 x) [# R7 _ const id = window.setTimeout(() => {
$ k2 s4 x# v0 E$ m5 }% z callback(currTime + timeToCall)7 I- ~# c( w+ \1 K" j
}, timeToCall)
. r9 M6 Z' Z) @ \ lastTime = currTime + timeToCall+ e' V' Q0 `% }: {
return id
1 j- e/ l- @1 T& f4 y }# Y% _; `4 D( a3 l6 j
0 W! ^7 o5 v; k/ G% i- J) n
cancelAnimationFrame = function (id) {
: L1 B4 M r4 Q7 M) y window.clearTimeout(id)
8 {6 ]& _" X* @! E }
7 s8 A/ v B5 U" f" ~6 Y* r' N }( z& l! n9 K' a2 U
}8 b0 I! b2 e0 `0 t0 v; f2 K% x
! R, e4 s% ]8 u. z1 w9 u) y
export { requestAnimationFrame, cancelAnimationFrame }
. H& X# b- v \
! b1 Q ~+ \9 i; Z
" f1 F) ?; j5 _1 W16 q' @7 K; i, `& T4 y* I! \
2* K. t, |8 ~/ W' I
3
1 \3 k8 g" y6 }- ^4 i( P5 I* b* B4
' M$ ?1 s6 e4 n5
( L. i2 `6 A! X1 ^4 j. J6: w8 ]9 c$ e; S" G9 n ^* C
74 t T1 D& Q% M! `6 X$ _& g
8& f8 C y0 V- A9 A. p4 C" z
98 s9 d) `( L f& Y4 G9 `
10; Y* z; A3 q2 U5 ]5 [2 m3 T n
116 D- q5 P( C' M" M9 u/ v* i
12
- N% P: `, B( p6 f4 T13& G+ f6 k7 z0 ^+ g# ]0 d* \, a
14
+ y% j) }7 G5 c/ a8 I15
+ x; [$ k" n y5 G160 g/ ^% i2 Z' X" r4 w
17" ?; W. u. K9 H2 [
18
7 t$ L! N/ V* Z/ }8 G+ p19- U7 |, B6 f8 |9 Z
20# _9 U: ?% O1 u ~5 v- m
21
3 y8 s2 T5 S9 z1 U% n% }) L+ v22
9 N: t7 I c# l$ h; d2 r) q* \9 U23- {$ K1 R) E: D9 ~- M, M4 \# {6 a
24+ E3 B6 _* G" V7 A4 y5 q5 w
25
' c$ x4 T% g0 A R; H- r26, X! J, u j2 u# H
27
) P: r- j6 c4 j% [28$ n9 `4 c7 x9 o
29
9 \8 V* m8 F* _$ W; [' }1 W4 L3 S; t30
/ q2 }$ W$ d2 a, i# P' q4 G% o31$ y0 C3 x8 W9 M
32
4 m$ @3 |; T& n0 \. H8 J' H; k33
: }; L! \8 ^, }$ g34$ U) \( k$ k& ], U& j6 D9 J6 N
35
, v: w% D$ i' d# I" Q# Y36
4 m' V1 j+ t! t _+ d7 _ D37
, n( p, i1 g% }' d) Z# o8 r, x3 w38
$ B+ {. ]! E( u1 _ r% ~39
/ {( j8 ^2 X- P5 t, O* q40
& c0 {9 ^$ [" F41* C/ c3 \( O: q0 N2 H
42' R! ~/ u, W. E3 d; [/ ~
43
/ j5 l) C2 C+ X7 J44% v) Z- E9 U3 E9 y1 P1 m% i( R8 k7 ~
45
3 \ v0 j) L, [7 p4 t6 |" M46
6 b! d" {9 Q" f47/ z, e; A+ c% W5 C* S p1 L8 B& S1 L
488 S, I r( K/ o/ E1 i. @
CountTo.vue组件思路$ N0 O$ i5 V, H
首先引入requestAnimationFrame.js,使用requestAnimationFrame方法接受count函数,还需要格式化数字,进行正则表达式转换,返回我们想要的数据格式。! b; l. T# d# B3 V7 z, O3 O" ~7 \
, o) B' d8 n% n$ b* o* o1 X/ D! @3 t
引入 import { requestAnimationFrame, cancelAnimationFrame } from './requestAnimationFrame.js') Y+ l/ W4 E5 @8 k. O$ x
1
+ G1 A" d' Y2 k- t7 B2 w9 |需要接受的参数:
( o7 ?- @5 p6 R5 ~
, S' c$ O1 J* S6 n e" cconst props = defineProps({( k9 s+ G# f! L
start: {4 P# j. C: W) X/ n
type: Number,
U/ T9 p: k8 s7 }% ^4 n9 _8 ~) K required: false,( K8 z: v0 `4 \6 a
default: 0. M5 R4 Y3 @5 D2 e. ]! e& i \+ F
},
! O1 m6 V b4 Q; h' o5 ~ end: {6 O: b3 ~6 h+ x% b$ }! z
type: Number,2 l5 Z' _* i D4 e# R4 S% v
required: false,
+ @6 h+ R5 z# U: a6 s, W, Y default: 01 R6 A8 z$ E# X: ?# W& v* Q1 X
},
3 ~5 x- ~* `1 T6 J2 } duration: {# R6 D) w/ @! R
type: Number,
t2 e4 E$ W; L0 }1 D+ g! W1 B required: false,5 q6 s) V8 b1 j. Y+ t
default: 5000
s E; L" B! E3 H# x },
4 I |* p$ @2 q3 H. @% W u4 W autoPlay: {
, y; [( D) L5 E% C' C, c& ? type: Boolean,+ E& u# c$ W* R" d6 I$ ]0 {- R' s
required: false,+ K3 M1 b+ ]4 ]
default: true
# u9 s3 E% Y8 { A },
9 F! ~% ]; o5 N* q: b1 ]+ s: o9 _/ \ decimals: {
3 T% o, C) J# @* }* S9 n z. ] type: Number,5 z1 ?$ z V! a2 ]. s. Z9 O
required: false,' B7 g. ~; `/ G& Z% [
default: 0,
7 y" r3 Y( R3 j6 S validator (value) {
3 c+ O- l& r0 p! L return value >= 0& i9 \+ I4 y$ P) `
}
2 h4 U+ `1 m5 x0 b, N' R },: w K* R5 m1 H/ a
decimal: {
/ O% `* U( J( ^' ]3 _, {- y type: String,) B$ y% x m4 Y" z# M
required: false,
( r! [ S4 Q+ D% X default: '.'
; @ s0 ]- ?( ~: L y$ R },
% M/ ]5 t5 w. C9 N, L& y separator: {
r; g% I0 O ]8 b8 x1 x" I type: String,& A0 U5 \; ]0 d+ \
required: false,
$ w# }, q3 o7 O# `6 l, m default: ','! y" {3 N( r& O. [, R* J/ P; R1 G* ^
},7 ?# H3 b& D3 t8 `8 r, `
prefix: {$ j& o0 J% L. ^! Z+ X/ a- m) h. S
type: String,0 c" ?% I7 t3 c3 d6 G3 E9 R3 ^
required: false,7 b7 d4 H" T+ r+ e$ [- \: x# w
default: ''
+ v3 t% i9 b$ P5 C9 S( F! Z },
8 u$ I; o' H, g( r. k8 I suffix: {
' S+ N6 d* V# E: G" I: { type: String,
3 K! s9 k6 V3 X; A/ H2 d. e. i2 f required: false,
$ O- E, z( ~' O& A) [5 M default: ''" j$ e* B) b K4 h$ C, e
},
6 ]1 {' h) Y+ }5 Y/ v useEasing: {5 |) R6 g4 ?% |; H
type: Boolean,
1 |7 R) j& D$ |9 N: c: F; G required: false,9 m1 t/ r& t: r3 b6 U @' C
default: true. w m, T! v" i* Y
},
$ E$ q2 F8 S% ^- V. V! {3 J easingFn: {
% Z0 s; n. X6 m type: Function,
8 }4 `4 I$ @1 h5 v& F: H% g5 F default(t, b, c, d) {- B w- w; D) f% f R% T t" _
return c * (-Math.pow(2, -10 * t / d) + 1) * 1024 / 1023 + b;( p! W/ y; h/ J3 j* @1 ?; Q
}
+ @8 W/ ~0 t$ Q3 q& X7 f }/ \; j7 O* u# |
})
$ e2 ?) r+ X3 i! r) e; b' n
$ x- V' r0 W n
) y+ M% S1 p% W7 _6 W* B+ a( G1
( Y. E' ?+ m: z3 c! \; x# y2
}* S b4 `) V. L: l% G3 i3
+ u! Q' e3 E8 x4( d1 }! O# i( R) H. J
5
& X( z0 f2 z- `6
, O; R: s9 S% p7
9 b4 J1 \, h4 |( b) u& y: d86 |9 J0 R T0 j! ?, C
9- A) }9 W4 S3 o( C' X, N& e! f! C
10" w0 k' h) L4 t2 O1 x
11
# L) }7 E& [/ ?9 q1 b12' g$ O3 M4 u9 k2 V+ X& `! |$ B
13
Q$ \, r! ^3 i5 [6 c14 t, B8 k. x. z* H. Q! G; v
159 V# D: q0 G& E% P% E+ l
163 r8 j9 b: @0 i: h( B
17
, d) I T4 s) S1 w18
W+ q6 x! [) i+ ]/ f( y* n, T; I, h198 S$ |" R; I+ J; M8 ~
20
( b6 e( W( z" _21
, u% z! h5 F9 c0 y225 i& m( r: ]. B" L' M/ Q! i) `, @; d9 {
23
4 G1 D( T! J& D7 {24
3 N6 z% {, g5 o' P: M25- J1 @* Y" y: U0 f
26
( r8 p2 D( Y) V F H27
2 n, [9 T$ J3 C$ W5 {8 D28
2 y4 c1 {, {$ F [- b29) a# c b3 [4 l7 t7 \+ y
30& L! U2 p' p; }) c
31
1 a* A9 t6 S/ {" P32
$ Y, ?8 h O6 C- A& u- ]& m# t33
. n- o$ E5 B( N% u% q7 G# {34" R# _! z/ S2 M3 s
359 o6 C) L0 `- `5 G
36$ P# {$ K7 ]$ X% A0 p
37
1 s* [( q s) t/ ]6 y/ I+ e38' v9 M' M" I5 H
39
# A9 \8 ^- X( l5 h5 J. q404 [# q7 D: R# ]0 I
41
9 U! \& q$ m; g, y42
, o8 L' ]. l! T0 f h) j43% z% i7 s$ X; A) T: c. I
44
$ S. ~+ L. S% j45
3 y m' Q- k# q+ r( Z- h" `; j46+ j2 x5 K6 }- b1 r
47& }8 x! `* e ?
48
' E4 Z4 N: ?6 P$ r1 C49
& F3 e: y/ D/ S/ M' A% p- U6 u50
5 U& ~+ a0 l2 J3 l/ {3 Z `51- Q8 y3 j$ y* r4 V v
52
; M$ T# V, w& w' ]& l' c" l3 _; S53 }/ @8 d1 I+ @3 P$ B! }* A
54( |2 b; S* {6 J. |
55
7 u+ v; U, v2 C" U3 g, D56
- o2 k5 a6 b' N8 k8 r, h6 k578 X+ W4 t# N! m
58& c7 ?, s/ b/ r. @/ E5 L
59% Q% S; p( x! b( T/ |7 ^ l( e3 k
60
& B+ a8 e/ |7 S& v+ b) y; z611 Z$ B1 M6 f; X ^: H1 p- k" e# D
620 c* W3 f/ |( n
启动数字动效
5 \8 Y) w* J+ [8 H2 g2 _* I
; x" Q/ F/ m) p3 B+ hconst startCount = () => {5 q7 A. V/ q* u' t
state.localStart = props.start' s$ ]8 k- n9 w" S- T X2 |
state.startTime = null4 Y" M. A( {( }
state.localDuration = props.duration4 W1 R9 W+ d/ O6 W
state.paused = false
3 T* h$ A( V4 l# m# G state.rAF = requestAnimationFrame(count)
3 k" L& f f$ Y5 A& s4 Z8 P6 v}
2 x1 N) L2 S* z! g6 D1
/ `; d- a* [5 t5 U7 W; l, m( j& O" k( K27 V/ l9 R7 V& v8 K6 d0 X
3
7 x# i" `; V$ F& E4
) h ]) A3 k G" u8 q. p& @4 i9 C5
" C, ~" M9 ?& m; `% Y* I6 P6 h y: }% d+ I% F! M
7
7 Z+ _4 f( y# L6 W) H' ~核心函数,对数字进行转动
5 N0 Y- w- h. L! {1 E
5 z$ N5 J g" U$ |4 Y if (!state.startTime) state.startTime = timestamp& O; d2 M" }5 k* |8 I- I& U
state.timestamp = timestamp
" m4 A6 M. @& x" Z( ? const progress = timestamp - state.startTime
$ ?) Q. u' o; o+ w state.remaining = state.localDuration - progress( _+ U0 G J$ A5 p
// 是否使用速度变化曲线# m6 n: X# _, x/ o* Y; _
if (props.useEasing) {
+ g: i% H0 F0 z6 n if (stopCount.value) {1 j7 t* L) g' a; v
state.printVal = state.localStart - props.easingFn(progress, 0, state.localStart - props.end, state.localDuration)
+ @- i0 x% F+ ` } else {0 ?% s; j9 Q- \% T' g9 }
state.printVal = props.easingFn(progress, state.localStart, props.end - state.localStart, state.localDuration)
% _0 I z+ a9 _. C3 @! M }4 @& N. x H# K7 |$ g F
} else { E4 m8 z. ~: B( M" q: a
if (stopCount.value) {+ \0 q2 X+ O) L$ W" F9 _0 Z
state.printVal = state.localStart - ((state.localStart - props.end) * (progress / state.localDuration))
0 z4 d# X7 j: g( x } else {0 {: n1 n* g5 k V$ M
state.printVal = state.localStart + (props.end - state.localStart) * (progress / state.localDuration)
, l; o6 w, n9 `& x }
9 ?: M2 }5 i; w. i. r }
1 A9 d, i, F6 X8 w2 W( m if (stopCount.value) {3 Y% o0 [! M9 z- \- ?& Y
state.printVal = state.printVal < props.end ? props.end : state.printVal
8 `% z: {6 ]7 h9 ^) y7 q% r } else {; u& ?1 r5 G2 Q* y8 C, R# p' F
state.printVal = state.printVal > props.end ? props.end : state.printVal
/ U9 S) x+ Y: C& n$ ?8 Q }4 d# _, L& R4 J7 o
' D" f0 e, x/ W# c6 O% b, C) Y state.displayValue = formatNumber(state.printVal): P5 _% Q0 x8 R# g! A7 U( R5 W
if (progress < state.localDuration) {
) H1 o) s# H! I# o( I state.rAF = requestAnimationFrame(count)
4 ~0 q# N0 ^) i$ k- ] } else {2 B" t! A* A$ W) Q9 A* v/ F) [* A
emits('callback')
# J+ v+ [6 U! A @+ f/ w- [4 T }- d k* k3 e' u/ a2 Y. ^) |
}
* F: Q, n6 q6 Q- x2 H+ e! y# x' K, a% b
6 d7 P, \' p" x) j
// 格式化数据,返回想要展示的数据格式
2 B" ^; G' |; f/ Tconst formatNumber = (val) => {
; U' @' a, W& g* V val = val.toFixed(props.default)
7 d5 l( `2 ^! t+ c1 F( R( V val += '' n# o- `) x5 C4 e# ]1 x" a
const x = val.split('.')
1 T" B* @) g4 }( R let x1 = x[0]# W2 S% p" E b7 e
const x2 = x.length > 1 ? props.decimal + x[1] : ''
' `" z% ~- G1 D! O" m: I+ a- W const rgx = /(\d+)(\d{3})/
a* M1 q% N3 W2 G1 Y2 j, \- Q if (props.separator && !isNumber(props.separator)) {
% V. \/ s2 q$ r" U+ s5 s6 a while (rgx.test(x1)) {) f/ T5 }+ ? [
x1 = x1.replace(rgx, '$1' + props.separator + '$2')
6 O% I! ]: z: x! V7 O( z8 i9 h; l3 l# k }
+ S7 e8 h1 L' ]. K, i }, h# e; k+ e- A' z+ e
return props.prefix + x1 + x2 + props.suffix
# ]9 |0 ]) W( l}
: N3 m1 K9 W5 Q1 o Z+ {
+ ?) Y) m/ B: P8 u1
& f, g2 p( n% ?+ K5 I! B$ E27 P6 {/ \2 \4 E/ M4 x4 l+ S
3: s* e) t+ e0 R M# R; y6 n! {
4
' F, ~, G7 @7 J1 @3 @% t5
" U' V: F. k4 d7 f: A3 L" c6
6 S, i7 r) B( ]& V, U7% d! E8 D" E6 G, x) o: p" P
8
3 h. E' Y2 g7 Z9 \6 Q3 \/ [- P" R94 Y% d# \5 {4 z8 V- f, }
10
2 Q/ \( S% R- v1 b* t- }, j11. w v) ^* X$ z% o1 [
12
/ _# U) U* Q5 J: X# ~' s13
5 E' ^% x2 _$ @- r" B) [14 z# p& [) u/ G! y5 l
154 t l& J, ^9 E0 s. p* D, t
16
2 N+ _! n+ T9 W8 o9 A17+ u: D- P7 ~; [; P0 i! y
184 L+ n1 N! @- ]
19- t9 ^* n& P0 ?
208 k, t5 b9 x+ d7 K5 x' N6 z* h$ V( r
216 j* O2 d J, K# b' L# K
22
, X- g# G7 u' H; E4 Q F23: n# s( G' `5 s+ R8 n2 e% |. J
24' Z0 E2 b! v, P {
256 n: b" K5 J4 C" u; C
26
+ T* v+ ]) H7 o- M/ {! t1 G: {27& b$ l+ |8 _" ]
28
. v6 h) m" L' O& R: d8 J0 j29! B6 A! l& s" z& F2 _/ s, j2 f
30( l% @$ j4 D- q1 R% W* G( N( d, c7 `
31
. W1 B1 S5 Q" j7 A" K1 i& t8 @32+ L) b g4 y( C4 o# c
33! c( _) K2 F3 k; x; Z
347 K4 y& V0 m. G$ `0 C/ G- T
35
7 i* t; u0 M8 }1 H3 w36) g0 p& u( @, k7 K: l" s; u
37
! y; [1 J0 M8 q: b38* I$ C* q0 p( O/ y2 J
39
" S4 }8 H8 d' D+ f# |) i409 {8 S1 H5 i7 c9 S; p5 L' h7 o
411 _4 q$ f( F+ U# Q/ Z
42' `+ @5 \# N1 i8 K1 Q* ~& I* t
43/ W0 Z1 F2 m$ O. Z6 v5 H
44! s9 l4 d$ k% w. K! e- R2 O
45+ o+ w3 n% h0 T: v) }' W
46
$ ]) a) p0 T. F- m/ E/ m# i; G47 B. |* I( R2 i+ H8 R: K
48
1 }' G4 P; { T1 T- B6 J3 R取消动效
7 Q9 U6 K* P- G v. W, k" F$ o. ]+ y* x( D* s
// 组件销毁时取消动画0 J: m) ~3 o) v* Y: Y" F
onUnmounted(() => {2 s$ F: f' i/ \! E
cancelAnimationFrame(state.rAF)9 x; [! U* ~/ a: }( X C2 r+ L
}): w8 R2 f5 f7 }7 P7 ~. u( j
1. @& D- \( h+ X- z* a
25 s2 [2 j8 v4 N* P( f) I
37 O. t& n& |1 T% k; c% ]% o+ W
4
$ K% \! P7 G, j完整代码
/ H& v% f- V' s. P
* k( ]3 }* G; R* {, i* K) ]<template>
* L0 a9 S) @; |9 p {{ state.displayValue }}
% I0 x$ V+ C z</template>5 ^& ?. ]1 |% G
9 M( s4 U! ~3 o) u$ {1 g* N
<script setup> // vue3.2新的语法糖, 编写代码更加简洁高效9 S9 p2 v, p" x- d) h7 L
import { onMounted, onUnmounted, reactive } from "@vue/runtime-core";
e: M, P, L: j7 I) himport { watch, computed } from 'vue';
9 B! \+ _0 i9 R& ~import { requestAnimationFrame, cancelAnimationFrame } from './requestAnimationFrame.js'" I# t# E% @. J5 h
// 定义父组件传递的参数
7 T: V$ A a- m9 b* r2 s! @const props = defineProps({% a# `0 r' T) S' O
start: {
/ w$ d5 B- f% K8 N2 @- K type: Number,4 O1 p7 F. a. \# f7 N
required: false,
* ?: i* Y7 M l2 n! N0 Q default: 0
; s( T X) G, V0 X% M% }4 H },' A0 O, ^% t6 p. M
end: {4 |9 a9 z8 M$ s4 x
type: Number,
: Q: v! l6 h% |/ G( b, v i required: false,6 w' R6 d b2 A& k$ d
default: 07 x: l5 Z; t6 G0 M
},
- g4 s/ s, F# s6 C duration: {8 {* ~6 T8 I$ k' c" T$ @, R# r
type: Number,
, B: x* e) ]* l9 w required: false,. X# K& `: r/ r% u+ i9 a# g# {! g
default: 5000
1 \4 r. N( P* l },5 Y- m& e; a8 D4 s
autoPlay: {
5 q" q( v" A, p: o type: Boolean,
0 \) ]3 n( T. M required: false,1 R. [$ M j, ~3 j! e- Z) s
default: true& y- v' F/ Q* b3 T+ M @' Q0 G
},
5 P$ ~) C. b" m6 |: u6 W2 v decimals: {
& `8 u5 b4 i, U$ V4 ~/ C e* w type: Number,
3 K- G: m1 ]6 @& K, U required: false,1 C* @1 w# p# v
default: 0,; S8 J* u/ b2 S$ H* x9 U4 w: u9 f
validator (value) {+ _! K5 y5 `7 y5 V T
return value >= 0
/ ]- U! t8 Q' c4 F. | }
1 B. u0 z- e4 M9 S W$ P },) V4 T: D H/ @# w0 X, Q+ o
decimal: {
' v; _0 s4 T9 m7 ]- y type: String,
/ F! ^1 o" y5 m2 x1 U5 b6 A Z6 l required: false,1 t, g" Q P$ Q' ]3 W. y: m" ~
default: '.'7 }/ x L- y0 r2 K1 F- y
},+ \* `5 f9 W2 _8 ^3 N) ^1 z% O- c
separator: {. Y' A0 X3 X* d' A) V) U* ~! ^
type: String,
" R6 @3 Z! e$ l! {4 H required: false,# G5 Y+ ^# n/ B0 }, ~0 ~3 f7 L
default: ','/ D( E k- \! l5 [6 p- L; T E
},0 Z, A3 ]) f2 r4 J
prefix: {& k" H9 `7 E* C" | U$ H
type: String,- ] O' e6 c1 ^5 g3 z
required: false,
7 W6 ^& [9 _1 }8 D% [4 Y1 I3 G default: ''4 G( G1 T$ ~4 E+ U5 ^
},3 p) G& V. l& P' X) ~5 J* S
suffix: {
- L& t( q$ }* T2 Y h5 X0 f type: String,* S& n* L, n* K3 s, p) `# L4 p
required: false,
, \! \ Q ~$ ~" {* J( I default: ''
5 k' b+ T! E4 K' Q! J },
# ]3 k0 E& i- d# n3 H( b0 [ useEasing: {7 b3 v L, E. ~$ B" a
type: Boolean," u, E h! z* m6 p! x
required: false,
5 M) t$ V8 M# f2 i default: true
% }# b7 N4 }. x4 A }," Q1 t, w+ \6 B' H7 m( S- r) v
easingFn: {2 g( D! T' p7 f
type: Function,8 E7 Y1 r+ H5 L
default(t, b, c, d) {% G/ K7 w, V4 @4 ^: n2 }& L( ?% }
return c * (-Math.pow(2, -10 * t / d) + 1) * 1024 / 1023 + b;
$ Q# ] {. h: n( G4 e }* T$ M) O8 H) H. `. G
}$ X& k4 x+ j+ _
})
) ?1 b( [. t; b) I. x0 v( i
6 H3 H. @5 r+ h2 |4 f) c) R7 Nconst isNumber = (val) => {+ Q3 i% W: Q C6 _6 m( c, W9 `. d
return !isNaN(parseFloat(val))' y7 V ~" X5 ?+ J8 l
}
2 R0 G T {) P p
, V" J" C F( ~3 |. o) _8 R& G' U// 格式化数据,返回想要展示的数据格式) j( U' O" |$ C7 p( `
const formatNumber = (val) => {6 y6 ^2 Q/ N$ D3 n9 u; ? Z
val = val.toFixed(props.default)
# s% a5 t2 N" B! p1 Q, s1 q( s+ j val += ''
) c" h; w1 H8 f! w" k, U const x = val.split('.')1 k/ f6 }$ w4 @4 N% m/ ]' n+ W/ k! k
let x1 = x[0]
, A0 C7 J4 [3 `# o% z' [; o const x2 = x.length > 1 ? props.decimal + x[1] : ''
2 Y) j0 {& p* e4 S const rgx = /(\d+)(\d{3})/7 j# O% _3 D) a! K V3 J. o3 ]8 w
if (props.separator && !isNumber(props.separator)) {. j" S0 S7 \! Q7 E
while (rgx.test(x1)) {
$ O7 P! ^! z: m: S/ r/ [- _# j+ G x1 = x1.replace(rgx, '$1' + props.separator + '$2')3 b2 u. \3 |0 d9 L a
}3 Z' v- Y9 a7 w; j; t
}
; v& x. F. x3 \ return props.prefix + x1 + x2 + props.suffix2 d9 D+ i$ a" R0 j* a) e2 h
}
6 @9 F) p6 }, x4 P7 i& c- @) L a3 p6 M3 E/ ?2 d3 Q5 o: n6 o
// 相当于vue2中的data中所定义的变量部分 r' ]5 L' e' g
const state = reactive({
@( ^4 Y1 [( H9 r: s3 f+ ~7 } localStart: props.start,
, g; z' o9 d. S5 a displayValue: formatNumber(props.start),/ B$ E4 K$ R" |0 I
printVal: null,# n. m9 p6 |+ O. x9 f( K
paused: false,
1 F0 {1 X" }' K1 J B$ g/ n localDuration: props.duration,; B5 T( G8 R0 y P1 r
startTime: null,
! J! t* t' T8 M3 y. L+ K0 k2 L timestamp: null,8 W/ z* t1 r- o7 S
remaining: null,
8 z* B3 F7 N' T! c2 I" G rAF: null
* F) v4 h9 I" a# s8 M% o})
/ H( V3 `$ F+ L! @7 A
- s% K( x6 ~6 D# }: m: {; M// 定义一个计算属性,当开始数字大于结束数字时返回true
8 b3 B3 x T- J8 ^1 ^& `const stopCount = computed(() => {
3 ~- B4 z5 Z/ q+ J: G return props.start > props.end
f) B3 m4 C( Q2 u})7 V) f: _1 E" o9 }$ p+ `6 {) o; ]
// 定义父组件的自定义事件,子组件以触发父组件的自定义事件) E: H/ z. l! _, e( m1 L
const emits = defineEmits(['onMountedcallback', 'callback'])
* D+ i Y* w. D" G# O6 ]8 P
8 F2 s. m2 W) b- q1 [const startCount = () => {
$ ]9 x8 f- j$ o2 F3 [ state.localStart = props.start) G3 G; U8 |' l+ P
state.startTime = null7 ?4 S. u; y' w' A6 P% s
state.localDuration = props.duration- N* H5 G: c9 k' B% L
state.paused = false# u, L+ j% ^: p. ^3 ~9 J# u
state.rAF = requestAnimationFrame(count)4 r' L1 l0 ~5 s4 H% [
}7 t+ Z! q& l/ ?. J% E \, w
5 W) q8 {/ c+ W9 x! ^& m$ j$ M ~watch(() => props.start, () => {5 z9 X( M( i, [
if (props.autoPlay) {
9 Y7 }) i0 W: S0 N/ r" S startCount()
: O2 @8 |- b" r3 }2 _( d }
3 N5 |' ^+ c8 z& Z) v8 O6 A5 n. s})
' U9 _# X4 v9 [4 E
8 y. I3 S7 X" ?. E* Fwatch(() => props.end, () => {
: \" C2 R- [& X+ M. B" s$ n if (props.autoPlay) {( [! U+ o; x \$ z7 {5 F/ g
startCount()7 b2 W( Y3 z" G5 `
}+ ^2 b; ?* g' l9 ~% s0 U; t
})- E# E0 c4 I. I5 ^" Q0 Y
// dom挂在完成后执行一些操作* M$ T# Q( _' |: y; m
onMounted(() => {
/ m! O' @ F; g, y/ ^2 N) h! z if (props.autoPlay) {
# O+ R. X5 |4 s) b2 t startCount()
- y0 S$ c; r* Q. ]8 N }
) ]- Z# P3 R4 Q2 S0 h7 ~( k2 \ emits('onMountedcallback')
$ n- K+ l# \9 M0 ~. U, I: E})- j5 p: _: I9 _! z6 W
// 暂停计数
0 u* Q+ u0 |6 u$ q" iconst pause = () => {
+ Q2 g Z" ^- ]( _" e cancelAnimationFrame(state.rAF)
% j( P6 y: n* |) d} T5 p/ I; t9 {# x. A; {
// 恢复计数
' E1 v' `- |4 zconst resume = () => {
6 R: i% G+ G4 @ state.startTime = null! w5 S4 Z" f% \2 l' k( @
state.localDuration = +state.remaining: P' f8 |% |0 X/ L
state.localStart = +state.printVal
) }- Q4 |: y9 j$ q requestAnimationFrame(count)
& S! J; a$ x8 y7 B: j/ V/ K}
& [/ {3 W7 L" A+ }" K/ M9 o1 M0 T
# r# j6 o8 w$ Nconst pauseResume = () => {% S l2 l1 I6 c7 T9 `
if (state.paused) {
0 a( K% s& w8 U9 c! H resume(): o% j8 h6 J" D3 g3 |0 y
state.paused = false
, X$ T$ E/ [6 R } else {
4 L n, e' p# k pause()
1 ^% ?! l( }+ x A state.paused = true0 k) C& N. t& m0 `: ~4 H- d
}; z# s- D6 x/ l6 T3 q% P8 F
}4 x- y/ K9 L" e* ?4 _3 f9 Q
2 ?; `/ V) j3 t& qconst reset = () => {. q+ z/ l; w! O. Q6 k- y
state.startTime = null- Q6 J, z5 {' f3 m: S" ]1 k
cancelAnimationFrame(state.rAF)0 j' S- O' E% r4 i+ @' H
state.displayValue = formatNumber(props.start)1 A" p( z L. B6 |2 o/ F8 G
}. y, j8 o4 e* x+ k8 W8 T
" D3 {/ l' I, S
const count = (timestamp) => {
; i# m2 o+ a# k% |8 n if (!state.startTime) state.startTime = timestamp: ]3 Z2 }4 m' E/ K
state.timestamp = timestamp! V- c r- n* K3 e9 T. `7 F, u8 A
const progress = timestamp - state.startTime
- B+ @. G% U' U4 v8 r! e& ~ state.remaining = state.localDuration - progress: F' ]& `2 D& g+ e, K' T
// 是否使用速度变化曲线' q- T2 c0 ?. p0 Z" [2 f. p
if (props.useEasing) {5 d( T# N) k5 J: x7 \: b
if (stopCount.value) {" I5 y7 ?: H3 J' U
state.printVal = state.localStart - props.easingFn(progress, 0, state.localStart - props.end, state.localDuration): G1 Y1 X+ A6 `
} else {1 Z$ {, r- h; V/ c( V
state.printVal = props.easingFn(progress, state.localStart, props.end - state.localStart, state.localDuration)2 ]7 e4 r* e1 W
}* g" z% q' K2 J2 Z" a
} else {
; h" Z4 b/ _. `! Z if (stopCount.value) {
: v: l( h& I! }3 U9 L8 B$ J state.printVal = state.localStart - ((state.localStart - props.end) * (progress / state.localDuration))
7 b* v, R; w* u. T# O } else {6 _* q, ]1 [' I$ m
state.printVal = state.localStart + (props.end - state.localStart) * (progress / state.localDuration)2 k, d! r" Y) n% B
}
1 f0 X5 v0 E8 o) B: ]) C }
8 K# L' f U1 u. B" k; e9 T1 y9 G if (stopCount.value) {
K3 S* x$ Y0 S: t- ?/ E1 S state.printVal = state.printVal < props.end ? props.end : state.printVal! u- B& t+ k) D, h) B' r- W0 t0 D
} else {
* K+ t/ }/ u. E! N state.printVal = state.printVal > props.end ? props.end : state.printVal7 ]: p7 ?% e" @; n/ u
}
9 m7 q) k2 R8 j" ~! C+ s
; L3 O, h- b" @0 L6 _, x+ p state.displayValue = formatNumber(state.printVal)" F$ J8 i U5 ~
if (progress < state.localDuration) {! T7 |" q" S' D( A
state.rAF = requestAnimationFrame(count)
: ]5 F3 f9 U* D$ B } else {0 d$ j5 q- V) s# E
emits('callback')
- S0 c; {- T- o8 j; {+ A! _+ H }
. {5 y; G1 F1 R* I: ]" Z7 |}
+ R7 b9 M( e8 Z. C2 @// 组件销毁时取消动画0 c. t+ `0 w% L; `/ k
onUnmounted(() => {
% I4 K( V+ {0 }0 I4 A1 H cancelAnimationFrame(state.rAF)5 D( e( O6 ]( D2 t
})' H/ i* Q W4 D( z( O& p1 W! L
</script>
, P5 |* u# `; w4 o: k% _+ I$ ~: ?* U8 U& u9 J, O
1. x6 o$ r( ^9 {1 S; E' H) L' N$ O
2
3 o) E* w- `+ f! d. t' z" V: g31 X. M- d$ j7 P3 X6 O
43 m: R* ] g2 v: N
5) d0 G6 R0 e# P6 Z j8 a
6 ?- h. u+ i- d
7
. ?- k2 ?+ r" C" n; j5 ?, e8
5 M( m; [. ]+ h2 B w% T3 |9
8 ^* t$ Z g# D( Q10
# L$ f, x4 x6 v5 V7 Q* ?11% l6 H6 _; a9 y# l
12/ E; A* A! R. f8 `/ G A6 I
13; a9 g$ ?' r3 s7 S7 Q0 r+ m* r
14( m4 y1 Q+ ^0 `3 ]
15+ n% k! K/ z/ y& Q* d' ~* _
160 j `2 w, e- X( y8 h7 \
17
9 f C8 S$ y8 k0 }0 A/ n18
8 c+ D" }1 ~) x# Q19# R% g- R# x; ?; z
20- x( t* J9 N9 t4 ]; @2 z2 j
21
4 A+ [$ [- I5 z& X9 L( h5 U223 ]. ^$ b; K/ ]( x
23
/ O7 ^+ a- Q) U' V" j+ `24
3 x \. ^$ r3 M+ h, b25* [' M8 h# t: I* G
26+ f& [7 x1 r9 ^; o6 q6 e6 f5 ?
27+ y5 d# m* f; T% _' Y
28
: S% {0 |7 _% h298 \. @/ a3 q: \# b% i; }! R
30' D2 ^9 M+ t4 L" B/ B! p w/ O
31
2 G6 U$ F+ w0 m3 T$ T' \/ F32
& p' I7 r" `8 V1 F, a33
8 k$ L- B, L6 k$ `6 G0 i- p; w2 E34; v4 E) d0 c+ U' @$ |
35
- e; D4 T: R1 @ k% i36
9 [, f/ U" Y; v37% ~+ ]+ p& R5 G
386 p- k: ^9 J; R0 s. j+ V, @
39; d6 a3 ?; K/ j% U q3 H, F/ S
406 _$ G; f! V9 U y1 p- ]) A0 b+ w
41
" g- g2 z- c8 w& _$ }) T4 s4 ~+ l8 P42* T* H9 }: b( m0 g- K7 g8 s
43% {3 ]" G/ Z" M& S+ e0 `8 {. z4 @
446 w" m t0 T# F) X' @2 x
45
4 {1 p2 |) L. |8 S1 x8 Q465 f$ Q; r7 {7 n6 Q; Y
47
+ W3 v. B2 U6 z6 F/ j48
9 S: }& @& Y8 m* q# u" t; B. P2 E49
" ~- I4 G" @ M50
1 u: e/ d' M9 _: x0 R: \) Z6 q519 C0 ?2 I0 g0 |( t& |
52
( }: B4 {: X9 O. W6 O! f% b53
0 S. L4 J* i9 Y3 e1 ?' O8 ^, }54
" f" z( U" ^5 ]; {3 s+ c( E554 z( A! m$ Q, }+ C0 N
56
& A0 }! ]* o& B3 d; L57
$ C4 h# T* r: U) p7 p58
- I; s9 `9 l" y! `/ R59" D& z8 |2 Y+ ]8 J# q2 x. h P( P
609 W" U( i ^% V" B5 t- Z
619 [/ u2 O; Y L* O* n% J
62
/ G& X8 u: W4 ?3 x63
; A ^! {- q; H+ d4 K64' H# `* g. i2 J3 d x6 L! t" O: Z
65 S' f+ R2 y0 C1 ]$ a3 a2 M! Z$ t+ w
66
5 K8 J A7 [8 T+ e9 d67
' K8 w7 B8 x2 [' X$ Y68
! @9 @; y" W- T* K% ?69
/ J; a* x2 o; v, r6 b) Z706 a- a. D# H9 c, V2 }; p1 ?
71
. s5 @' b. d. K$ V. {72
: z, O j3 t9 [. W73
4 R$ y# [$ v5 q, h5 c- `74# s1 n% K. u* o! E% a$ m( z$ U: f% a. t
75
) C; R- T1 W, n76
8 N1 q# M; \' k6 Y8 G) b77
/ f3 M" E* T- ~. t78
) s/ L3 v7 C4 s7 y# o$ U& b79
. Q1 W2 d' ^& y, P+ `) W80/ Y9 W6 o5 W) E8 x( q* {9 D/ w
81' \" H v8 b1 ^4 c
82
: b" n9 s8 i/ [+ o. w2 w# C83# o2 u7 F8 l4 \5 Q k8 a# l
84
9 {1 B, U# K# v0 y6 S# ^85
4 P$ l. M& M' R9 J$ v2 [0 N C9 b86. P/ P0 ?" u: w! h- n6 ~/ @; g
874 v% `2 g" x6 ~ s y, p: X; U8 d/ ^
88/ ~: j8 e# J" ?$ x. F# A
892 v5 V2 |& A1 f$ H; d! c
90
& T6 H8 Z5 B Y' S+ X% f, }91
. s' L0 |+ O( @- G0 a92* j$ ]5 S, q' l, d( L4 n
936 w+ {, Y# Z1 g* U+ k+ V: T8 I
94
G' n$ Q9 h9 u9 {9 V0 ]- n9 b' U: H95
6 {: ^9 Q0 L7 Q2 e3 M I2 x96( R, r5 T7 n9 S; J1 ^" J. k
97
8 h2 Q, ~& V: r5 S98
* b+ z( j) K E7 t% `99
+ B. i3 e$ a' E3 o# i3 B( {2 }3 w F100
9 o- V$ H3 M0 z U( X: D, }$ o101
/ X8 k9 {/ ~( ]5 i102
! U% \& X: Z! v9 y103
0 @( @& C# v5 ?6 Q104
8 c9 ^9 l* }) E5 Y105
" r, {1 z1 M4 q; P6 c) h5 ^- m1069 {, |+ M6 j( t* s
107- W) ]* n9 x/ p5 t' w7 |3 f0 S/ o
108
. }+ y. u$ V. v. x4 d3 _109
- L! V2 c3 v9 C: C- Y7 O110* b' H, U; E/ ~1 V
1111 H0 a9 W" P; f O
112
6 g2 M) u y0 t113: s$ D* {0 V6 u1 ]& s- t
114
+ Y c+ q9 w) P- e& _9 h1159 s9 F. X& A- a' J: u( c& M
116
7 q8 N B, N& F# w+ m& O117- }2 n9 h Y) l) w: A
1183 ~7 S- _( {9 t- V6 \
119- Y8 G9 B) x7 t; K/ g
120
/ |* _2 v1 H( f' ?! M121
/ ]1 I2 I! ?: ~3 D& E1220 d1 {% \$ U/ \5 x$ C. t
1231 T/ f; J& ?0 S+ o
1248 P4 n5 D- m$ C+ }; a! ]& C
125# R( ?, }( O$ o' u# b( A' g
1263 x" Q+ Q; x3 g* n
1276 N+ w4 A6 t2 P( W i$ j0 I
128
7 L( k' c8 S: N# [! O129, S* X1 {" K' z9 ^2 X1 ]
130
) o) U% z2 e* Z- ^: j131 C2 v4 z, |2 ]1 i
132, I4 k' j6 T* p# n7 D2 n- o3 e
133: h6 x) p/ A- X" a
1349 B. [4 x5 `2 U G- w
135; Y B; \ ^ w
136
' w* [- Y: [6 k; [( x137 \* R) y/ i: @: w) M9 T c
1381 L0 h* \5 V0 \" d
139) H# e$ ]7 T5 H$ I! n# Q
1406 Y! L. K9 O2 A( e0 d3 W
141
- ]& M1 L' @/ @+ t2 g142' I! @9 g) ^0 K4 c
143
4 ~3 }* {' H$ @144
0 o4 S3 C' S4 @4 D1457 `- @& j, a6 |, p
146
0 G$ m& d f% j4 C5 r3 g147
y0 c! m! E( t148
$ B( ~( ~" t; Q$ i149& N7 }; Y! n7 a( I% p H' \- T
150
$ P* ~/ @: h" S1513 ^) |/ V8 t( d1 B: o4 g# ~: W
152
. L% R- n' f* _ I& w L7 P+ H153- X- S# @& M- T
1543 `. V; ]( i1 A9 r H1 u, _
155
$ J' M/ f. V" T& C156
; s! q- L6 M; P) l" I% {5 H L157
' \' h0 P$ f( `& y* f- B! Q. S. x158+ r9 K1 W+ Q) H3 z- m$ e
159; _. N b5 v/ j: K) r
160
& }9 E" Z# m) V8 y161
6 r& R8 b+ n, V% F6 T0 b162
' ?& s& i" j8 m! ]" k: V1633 ?1 B2 w w# o: c, T+ Z/ I
1648 q+ X# J1 d$ X& s1 n
165
% ~* J6 r. \& A- L Z) F166
6 F" p* F$ U. L6 P" m% f& d167
8 y' I" r' y9 X" v" Z1685 m2 _. w" [3 ~* u5 n$ f
1695 R! `) ^+ L- s) e
170
, i& o, W" Q8 |" e5 e' G171
* \/ ]0 ?) ] K0 J1725 @" A; y7 c+ y5 @ \
173
9 T6 [) w4 o* ?" ]5 K7 D& G, d+ o% u174
& n6 a1 U# E# _* O4 t* W5 y1753 f( [! S* R6 l5 _4 Y0 |7 n
176* ~' H% }) k6 _; T
177# S1 \8 D n" y% d
1785 G" u7 z6 q, @& G ^1 i+ w9 M/ B
179
+ D7 ?# `9 O* R( g. R1 L180
8 h2 _* h5 b2 G8 v181
7 ~$ j& B$ y% B! m6 y! ~182
6 F- z% w8 U+ S* u183
5 [" @5 f) F( ^184* v' G6 L2 d" B$ s# l
1855 n! }7 E( M, q3 F
186/ t) ?, p/ z3 j; E) D& ]
187
* ~( E( ~, f8 Z( c, ?, e188
- R. S! F1 Z9 j" S7 e189, ]7 |4 m3 P5 |$ S3 L i0 F
190
- U: c% g: F+ j191
: @, G1 M, w8 p1 H- j. v192) E, k; R8 k+ k7 {+ ^5 f) k @* X
193, p# E+ i2 q: E2 x" v# S% M
194- f; s M$ e5 w# k% g% f8 x
195
, n" a3 x) V9 [/ T m' N196
+ f, I7 N$ g" L1 W( [197
T% N) d2 ]; W# \7 `% n198: Y8 ~! T$ f. B) _5 V- l# `5 ^
199* N+ B ~6 B: W6 `& Q
2006 Q& _# Q* R# K7 b; w L+ e! R
2013 b; C5 f% c) [$ s
202+ _3 O8 U- {( S% ]
总结: f3 n- |, ]+ S' I5 Y
自己封装数字动态效果需要注意各个浏览器直接的差异,手动pollyfill,暴露出去的props参数需要有默认值,数据的格式化可以才有正则表达式的方式,组件的驱动必须是数据变化,根据数据来驱动页面渲染,防止页面出现卡顿,不要强行操作dom,引入的组件可以全局配置,后续组件可以服用,码字不易,请各位看官大佬多多支持,一键三连了~❤️❤️❤️
" j z( e6 ~! l C! F
8 F7 x- k8 ]# N8 Idemo演示
: o7 y1 S' K& g* P后续的线上demo演示会放在2 a0 \* Q9 t' [' x
demo演示& j8 v1 Z4 \3 K4 } s: \" {3 W& \
完整代码会放在$ t, w4 A9 a/ e! H; F7 j2 F3 a% i
个人主页6 B/ |. l6 m( V, w2 i6 Z
; q; ^- l$ u7 _) O希望对vue开发者有所帮助~8 u+ [- S2 v! _
! m0 X: H6 ]1 b( l个人简介:承吾
J% E" E0 f7 N3 p工作年限:5年前端 U9 T4 s( A+ G# [6 Y" v. D8 ~
地区:上海
7 H! z4 @& Z! d B个人宣言:立志出好文,传播我所会的,有好东西就及时与大家共享!
) X [8 |; A4 E% b' h S: g+ g4 T4 B1 q! V. n! Z6 J# e( u
1 ?* f, V: ?) F8 S1 p1 i
2 I, C% z4 L5 V9 n. t
3 P' e) x) j# h/ H$ I' J5 o5 X% N————————————————
4 z0 E, g2 v s) P. Q9 J版权声明:本文为CSDN博主「KinHKin(五年前端)」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。, P. V5 k0 f, O) p0 u+ V! Q
原文链接:https://blog.csdn.net/weixin_42974827/article/details/126831847 n- D ?* G3 \+ S
6 @* Q/ w& O8 Q7 g3 l, a; b9 r( n6 L, G2 g' w/ e" Z6 [9 K
|
zan
|