数学建模社区-数学中国
标题:
vue3 | 数据可视化实现数字滚动特效
[打印本页]
作者:
杨利霞
时间:
2022-9-14 17:02
标题:
vue3 | 数据可视化实现数字滚动特效
vue3 | 数据可视化实现数字滚动特效
* O, |1 _: b' r. e
& N1 {1 _# q6 z- {
前言
1 G4 e7 k G7 I" ?! C
vue3不支持vue-count-to插件,无法使用vue-count-to实现数字动效,数字自动分割,vue-count-to主要针对vue2使用,vue3按照会报错:
* N% _( F/ S; J, E
TypeError: Cannot read properties of undefined (reading '_c')
0 ?, y" o% m9 s( f0 @# ^8 h' u
的错误信息。这个时候我们只能自己封装一个CountTo组件实现数字动效。先来看效果图:
! @0 G" ^( P/ B k: k
. q) Z( U D5 J4 `) U( Q3 h3 J2 [
- v4 V; l/ c0 C% o* `
思路
0 Z$ E. i9 u% z! m6 \/ [
使用Vue.component定义公共组件,使用window.requestAnimationFrame(首选,次选setTimeout)来循环数字动画,window.cancelAnimationFrame取消数字动画效果,封装一个requestAnimationFrame.js公共文件,CountTo.vue组件,入口导出文件index.js。
$ n) S5 o) n% F* |
* q# `0 u1 G9 {1 K, e
文件目录
8 y( \/ u- }; e G, B/ _
! c3 e+ X' }5 k
9 G+ X! _8 d& n( S( `% X
使用示例
1 i- [% F( L' P3 D- Y' g2 c* b
<CountTo
' O2 R! e" m0 R' B
:start="0" // 从数字多少开始
" L2 U2 @8 @# ?# ^4 b; s5 [$ L
:end="endCount" // 到数字多少结束
& @) J0 I0 i1 _1 F* U( s
:autoPlay="true" // 自动播放
4 U- l; a# c& f. R! U' d/ F0 t
:duration="3000" // 过渡时间
- F1 W- \$ D# v) D. p
prefix="¥" // 前缀符号
: W2 v( u4 ]- h( j, l- ?1 C5 u
suffix="rmb" // 后缀符号
: k# k5 b8 |8 [2 i2 y9 F2 K& a& M
/>
8 u4 V" K9 N8 d. X- X
1
, D- S# U2 P4 g' N
2
7 r- z! j$ l1 f6 t6 q+ ~1 L
3
, u0 `; x+ Y3 \
4
2 p7 L% Y- A7 U( H$ ~# z6 O
5
: S8 |) k/ r+ q( F8 D4 L/ ~' D
6
5 L, @; r8 l3 S( y
7
4 h$ e5 ?/ I+ W5 L
8
+ u1 }$ p0 X% M0 ]
入口文件index.js
; o/ t. A. Y$ q. M% I6 v7 w
# B! c2 O) @+ N8 P! y6 T
const UILib = {
m- v$ I$ v/ q" D" ^
install(Vue) {
0 o% m3 V7 H* ?: O
Vue.component('CountTo', CountTo)
" F' W% f8 G, j( \+ C! c
}
4 a, w$ h& x) p) O" N' x
}
1 k; c) w6 M' O8 i& v$ n
3 E9 m1 y0 t& M
export default UILib
6 n& ]; w% y7 l/ A
8 l# [ a9 @" u6 L
1
1 E* J# R: \" X: n7 c& C4 w: f3 w
2
+ ^/ W9 J3 I6 F
3
. P ~7 G/ R0 u( A& p1 D/ e
4
, E& C4 M" n/ I
5
; w2 J9 u0 T' \
6
^ ^1 \) |0 R# ?1 Y. u+ j
7
6 |3 _0 t0 a9 r8 \$ Q F
8
% d T" `; r8 j+ y$ ]- V
9
/ @, f; q; V* [ `# q4 S
main.js使用
- q/ d; J1 v2 _% d* K+ d. K
import CountTo from './components/count-to/index';
! {- z3 D+ H% W4 }: \
app.use(CountTo)
3 K6 M0 M3 C3 p4 p0 I5 x
1
, N" c/ T4 z9 a( ~$ V4 ]
2
: W( b! a3 c; d5 j! E4 q
requestAnimationFrame.js思路
|3 G& l' |% j: p% N0 x- W. \4 s
先判断是不是浏览器还是其他环境
9 w+ j# e! {3 J
如果是浏览器判断浏览器内核类型
; Z3 N1 R+ [/ K5 H
如果浏览器不支持requestAnimationFrame,cancelAnimationFrame方法,改写setTimeout定时器
* x8 k$ v9 u2 R; J
导出两个方法 requestAnimationFrame, cancelAnimationFrame
: ]% G2 r7 A& B+ Q. L
各个浏览器前缀:let prefixes = 'webkit moz ms o';
Y& K, i! ?6 Q/ c7 D( p" i
判断是不是浏览器:let isServe = typeof window == 'undefined';
9 [5 i/ s8 N* _; X
增加各个浏览器前缀:
4 p* `/ C% a+ `+ N. I8 @1 ~
let prefix;
3 U# ^2 P. Q6 Q. Q7 g
let requestAnimationFrame;
3 u0 r. S! B! Q( \+ q& l6 E9 a
let cancelAnimationFrame;
3 J3 G, t4 r3 e0 v* ~7 q+ d9 v
// 通过遍历各浏览器前缀,来得到requestAnimationFrame和cancelAnimationFrame在当前浏览器的实现形式
/ v: ?! d* Y+ l0 q
for (let i = 0; i < prefixes.length; i++) {
% T% x: v2 v& Z' s0 N
if (requestAnimationFrame && cancelAnimationFrame) { break }
( R" N; W" h3 T, V
prefix = prefixes
7 T2 j! Y7 {, _) @6 A3 |, h! G
requestAnimationFrame = requestAnimationFrame || window[prefix + 'RequestAnimationFrame']
# K9 C! j- p3 s! Q& I
cancelAnimationFrame = cancelAnimationFrame || window[prefix + 'CancelAnimationFrame'] || window[prefix + 'CancelRequestAnimationFrame']
0 ~1 x3 ~3 Z5 A+ E
}
" t p2 B4 r% H3 N* V$ ?5 {
6 i. \- y9 R. e- O) O' R
//不支持使用setTimeout方式替换:模拟60帧的效果
( P% H3 K3 s7 `- `
// 如果当前浏览器不支持requestAnimationFrame和cancelAnimationFrame,则会退到setTimeout
# \, B$ x) b8 B5 ~
if (!requestAnimationFrame || !cancelAnimationFrame) {
# q/ P& d) V, K+ w5 v: q3 b% k
requestAnimationFrame = function (callback) {
Z' B! a2 o! R% m# S/ L& I; l7 K
const currTime = new Date().getTime()
# g$ v' | C+ R/ S
// 为了使setTimteout的尽可能的接近每秒60帧的效果
# {' e7 F9 W1 g! D# Z# b
const timeToCall = Math.max(0, 16 - (currTime - lastTime))
6 u9 P( g: l# m$ M2 L- o, w" M
const id = window.setTimeout(() => {
0 t' `$ i% R" f3 a+ {
callback(currTime + timeToCall)
& H- {' N( `/ k, j$ U
}, timeToCall)
5 n; T0 D& O. n7 z/ N9 k8 Y R7 a
lastTime = currTime + timeToCall
w6 [" N9 N+ U# X! d+ ?% \' D/ V( k7 H
return id
9 N l/ F: L+ w1 h
}
# e1 r: u& Z7 F
% u c. q, N$ M, n7 b
cancelAnimationFrame = function (id) {
) |3 a+ {; R. F4 F, S9 K" X! G* e
window.clearTimeout(id)
. n6 d5 w* z# m9 M
}
% ]4 R' E$ W! t+ h# V
}
1 M' w: x Y5 I
6 W9 M \; n# ]8 c& G. V* K# {
1
9 `7 z: \2 N0 s% D( P
2
9 B' ?* O& R. G0 I6 i+ D, L) g
3
, G- V4 A" X, R- Z' W, L1 F
4
; u4 ~$ h; h% v" F6 G
5
& h& M" _8 B+ w+ O
6
* n, o5 s2 j7 s2 w
7
+ t$ L. X+ @/ @: k* q; [6 x
8
+ V) i# G! y, R9 i3 f0 s9 ]* _- |8 J% O
9
$ [+ l0 n2 j( ~( O
10
/ F- E- V0 U9 _9 U2 Q* K5 g M7 ]
11
5 m! I% W& ]6 v
12
. C) z6 P" J, J8 s. M
13
; j; a# v5 [6 @& `; i6 X, ]
14
4 g5 ?- c7 X3 M( M& j$ m
15
: u4 `; Y/ D' {! W& |
16
2 v" j6 `8 z7 l s% E0 A
17
. [' g W4 y6 N: j! n
18
/ E; P* V' Y& I2 F& e
19
2 W1 e- u) r8 Z- |* Y# m0 Q! G
20
, Z2 Q) e. m3 ]" c# h
21
" J1 A. q# [$ \& e$ l9 e- V
22
p1 `2 p, R( b. O H q- b5 V [3 S4 S
23
8 b! L% G' m D; A) l: k
24
% ^* b6 @+ d( J: G9 L& i. T
25
0 X* L' `' ~" q/ i" o. f3 Z9 Z
26
/ B/ v/ k5 S9 }0 c
27
# r" G. D, O" v" G V* f5 m
28
( ?$ L* a9 [/ }2 h8 f* B) O
29
3 |5 j3 n; U! f0 ~/ Z
30
. U$ U* u2 q) B( i4 T& J! {7 {
31
1 S& ]' n3 c9 x( e
32
) A' e& N2 u# ? Q
完整代码:
" e j8 y. D% v
requestAnimationFrame.js
% L. k o. ]% f
: N) y+ v" N" M c
let lastTime = 0
% }, k; P4 i1 o: i N6 k) m) m! V
const prefixes = 'webkit moz ms o'.split(' ') // 各浏览器前缀
* V& \( S( v5 E
- z% E0 ]* \. d% X; t5 ~4 Y
let requestAnimationFrame
. P( A* ~$ f2 E# `$ x
let cancelAnimationFrame
( k+ \- i, A0 u1 ^
0 m3 @3 t+ x0 R- S, y
// 判断是否是服务器环境
( K8 A+ r8 F: B% g
const isServer = typeof window === 'undefined'
/ t% W' W' }$ s4 w; t3 D
if (isServer) {
- a) z5 P, X y% g+ \: |$ [/ ~
requestAnimationFrame = function () {
4 I0 h+ M* P& f5 S2 r6 L1 J1 ]# M
return
! E/ n( ?- _ n' B! ]- H! d
}
0 J; W0 C9 Z- D, u! R% g* _* l
cancelAnimationFrame = function () {
# H3 h6 W3 T3 v* S2 f
return
; v; K! x, y' \+ ?6 P
}
5 r8 N3 | }) \" C& s6 f
} else {
' H4 D- Y' F; G
requestAnimationFrame = window.requestAnimationFrame
1 U3 b1 w3 e) Q |8 k5 F- H5 }: K
cancelAnimationFrame = window.cancelAnimationFrame
$ d/ X/ v* h6 C# V& }: M
let prefix
: w& h' `5 `3 G) A
// 通过遍历各浏览器前缀,来得到requestAnimationFrame和cancelAnimationFrame在当前浏览器的实现形式
1 M1 c( n L6 S% `
for (let i = 0; i < prefixes.length; i++) {
5 W0 a3 x9 V) ~# {+ I! l
if (requestAnimationFrame && cancelAnimationFrame) { break }
! a) A2 x' ~$ y) p u- c, H
prefix = prefixes
2 R) r C6 }. z+ A' g
requestAnimationFrame = requestAnimationFrame || window[prefix + 'RequestAnimationFrame']
8 v' I. V2 o9 g; F$ f- C) l
cancelAnimationFrame = cancelAnimationFrame || window[prefix + 'CancelAnimationFrame'] || window[prefix + 'CancelRequestAnimationFrame']
5 H" G4 G9 m4 X. Y/ Q( ~
}
" B* }9 W2 H; _: X$ j
7 J9 T3 F6 r# X) J& |8 L
// 如果当前浏览器不支持requestAnimationFrame和cancelAnimationFrame,则会退到setTimeout
* y& c8 k" R% F% q: w: J4 j8 K% J
if (!requestAnimationFrame || !cancelAnimationFrame) {
- r& ^) V, H, X3 n1 P! c
requestAnimationFrame = function (callback) {
: S3 R7 n: B6 }% R$ F
const currTime = new Date().getTime()
: k; ^: b7 L. ?" S! o% k: g
// 为了使setTimteout的尽可能的接近每秒60帧的效果
. P i; S1 n5 h6 V$ D4 n1 f
const timeToCall = Math.max(0, 16 - (currTime - lastTime))
+ a! K. S( s$ N3 Y
const id = window.setTimeout(() => {
( {/ R- }& @" T
callback(currTime + timeToCall)
$ k& ^4 F% f* g1 z& w( V
}, timeToCall)
: B4 O6 | w+ U `' E( }
lastTime = currTime + timeToCall
d9 `! [/ M" l! [5 R
return id
8 o) u0 q/ N7 o# l
}
' P8 D1 F A+ U1 Z
' X6 X: k6 M! \; W, r
cancelAnimationFrame = function (id) {
- ^1 U' w) l' _3 V
window.clearTimeout(id)
8 P: Q9 k) F3 L4 m
}
) H7 a" T7 ?5 r4 O3 {3 t
}
) K* A2 A% o [: m' ~1 ], R2 d
}
8 n0 a3 \3 p& t4 _3 C. \
0 K* Q4 P. X) J) h- G
export { requestAnimationFrame, cancelAnimationFrame }
- I' C' l0 e9 ]) X* P$ t; B: `" h' {
, B; ]7 j" j9 c! A2 f! f6 A
/ |. d1 T) h9 j2 i
1
% o- {* \$ V6 r, I
2
% y/ a, o8 ~6 l$ V8 A+ |5 N$ |, D
3
8 B7 h$ V- U# V: Z- p
4
. v6 \; }, |) ^2 _7 R" h- n
5
/ w5 f U, @( M' T- ?
6
. k+ A: |9 o, a& Y7 n1 `
7
! G! D( c* @. g! Y
8
8 y4 h! x0 m+ g# \. |' J V6 Z
9
C9 v) L9 T# T8 w# q; u- t
10
2 R& b7 _) l; n N( b( ^! A1 H
11
+ ~+ c- M4 B* p- |% L. Z2 Y
12
5 ]/ y" @# q# \9 r
13
( H# T! T H. ]; ?
14
- N! x8 {; f3 S8 Z+ y _+ S
15
2 m6 R8 L' n7 a1 |! T
16
. A3 |- l+ a$ l) @
17
8 h: [: C& b' o7 V0 `- ~* k. f+ q
18
% B: ]5 ~/ Y7 X8 ^6 _9 j* `2 D3 C" _2 Q
19
" l+ d0 ]% k9 t' M0 [: I5 ?
20
# D& q' L4 p; k% Y3 J: e/ t
21
* o4 T3 h7 e- w. Q
22
% Z) G U7 Y& L' M
23
: y! _) m5 T. C5 A
24
5 I$ ]/ O) C% K. T' B6 z
25
+ ?* }7 M$ S0 _9 Z: P* ?
26
9 V0 s" r- r/ J
27
2 k0 o) r5 @" {! L
28
! G) ?' n) U j: W; z/ u
29
. j* b0 P. _1 C+ p- A2 \
30
4 k6 w: y5 ^0 l
31
# v! J! Y1 a1 d2 D' _& s
32
) e8 r5 r5 a: O
33
& n3 Y& k2 v r0 B5 t
34
4 u! a( Z! p8 B# S) ?
35
* a5 i+ B& W+ G. l9 c5 d
36
& _" V$ {4 Q! \" t U4 |5 X: ^
37
) ~5 H2 t8 y" O4 f1 t( U+ B
38
& H# x5 v9 S& i8 q0 _4 X$ L
39
) f Z. @( X \) O9 Y
40
6 B# G* m- a" j! D( Z* @
41
( x: ]* z7 f) F
42
" v4 k5 \' M9 D# E" V( U7 x1 H- r6 B
43
6 C3 u% T6 p, d+ A1 P$ R9 _8 J
44
% j( s- c P0 M& A+ t6 D
45
/ _9 S* b" X" V, n" \
46
9 k0 i ]% t: M6 s
47
$ f* }6 f% y- k8 x5 A6 H
48
% |1 _' v$ {8 V$ @
CountTo.vue组件思路
^ B* q: I9 T6 E( Q- \8 i% d3 g
首先引入requestAnimationFrame.js,使用requestAnimationFrame方法接受count函数,还需要格式化数字,进行正则表达式转换,返回我们想要的数据格式。
$ y, S: M) J& e6 d- ~# d# v- |# G
5 o+ R+ S) c" Q8 y9 Z& H
引入 import { requestAnimationFrame, cancelAnimationFrame } from './requestAnimationFrame.js'
9 _6 s$ X# B6 P( s5 a }( R
1
# i9 e6 U- i& z) @' _, p( m
需要接受的参数:
4 }( @; W3 P2 J$ Y
( }. Q! u$ m0 F: l" Z+ q
const props = defineProps({
+ e4 c; S6 S, z+ _3 l( B7 ?
start: {
3 W- p7 p8 F1 G6 f; U4 U& H
type: Number,
/ f, ^( R0 q" k
required: false,
0 j8 B2 N$ ^/ U2 G4 t9 A' `
default: 0
& X* x. N. x, q$ R1 m
},
- x, j. H. o" Z' E1 ~. z/ y. O
end: {
# u" S8 p3 |2 R" Y; i
type: Number,
* ?2 ?8 H# i3 j1 }$ S8 z) j
required: false,
4 f" G3 j+ V0 H+ X" x
default: 0
3 o+ w% K( v# T$ j
},
. l1 N) r v5 f' u0 C$ u
duration: {
- R8 J- U; g- q3 N$ g4 Q
type: Number,
- g" V+ u1 f9 u/ ?' n# r& Y
required: false,
0 t0 x% @0 i0 S1 M- {8 b+ G0 F1 X
default: 5000
: r0 K/ K7 E9 p
},
- U/ M# W: l9 R s+ o
autoPlay: {
" y8 ]+ z1 `$ x1 R
type: Boolean,
) R8 `+ N0 k+ o
required: false,
: {8 l; D# m3 i! u: _. \; I0 X
default: true
* }6 G3 ]. z: A* _; m+ C9 V I1 u
},
6 q8 o5 Q4 t3 z9 O
decimals: {
! E: K1 r, M. z6 L% V1 V" m5 v
type: Number,
% f0 a7 l; I& R/ ]( O; T. J* X" W
required: false,
5 a3 G5 B- Q' I! f& y* I- ^
default: 0,
3 |! M, X9 z7 |9 ^- H: N
validator (value) {
' H4 W0 ]+ ?6 `3 Y
return value >= 0
: m2 p5 J7 p1 h; ^. h8 G/ B
}
6 a1 G& T+ Y2 M! o: H$ C, ~
},
9 t8 P; \4 s7 ~: f, {; M0 N3 l
decimal: {
+ ]4 A1 F1 L& [# { a9 j) O
type: String,
$ k# a8 Y9 o: Z2 a! b2 a' f" m& m
required: false,
2 M* E! K2 W# b. G- J
default: '.'
! c! u6 g2 a: _3 m# \
},
# }# t; ^5 N& {1 W _1 ^' D
separator: {
% g2 L7 c/ P) i" V9 k
type: String,
. o& [; R4 `' `, d _
required: false,
9 a9 c! E6 @0 [, |* v3 X' {+ [: i
default: ','
6 n) X1 N. |' p ^( ^# _% R' h8 l
},
# m1 i2 y& x( }! k* A
prefix: {
! T" c+ r$ e/ B3 h0 A
type: String,
$ n K7 V( C/ E% n& o0 \2 i( U
required: false,
1 V. x, X+ ~: |& h5 I3 N' R( `) @3 Y1 T
default: ''
% y' [+ i+ X/ n* C1 r- x# y- u
},
# n+ k7 n, T4 B# N% r& o' E
suffix: {
1 J7 l% V6 c0 ?) p g
type: String,
; L9 Z' S* m. l
required: false,
3 A! R2 w, k) [1 g' d
default: ''
6 r/ ^) b$ y7 t: H; A
},
l6 }3 V( m; _
useEasing: {
4 A( G: [( E1 b
type: Boolean,
+ }; S2 y) T5 ]. P+ X9 _$ X+ m
required: false,
% {1 Q' c/ u: S; z d1 j+ H
default: true
0 n) y5 h% j' L& C0 P
},
7 M# T+ J. ?3 h+ n6 D8 D: T
easingFn: {
0 K F# w1 m; o
type: Function,
2 r J4 `5 @: o0 k
default(t, b, c, d) {
7 y* `3 l" a& \7 P, H6 @
return c * (-Math.pow(2, -10 * t / d) + 1) * 1024 / 1023 + b;
6 J7 ?2 j# p. }( W( x
}
+ [5 E, b$ P0 j. Q! I
}
* K1 `2 O2 {9 @: ]/ e( b( ~4 v
})
8 @9 u* }# j* [, b! w
! y1 A( k; c e
. c$ B( q% |' {5 t' ^9 m
1
1 E y' V8 S" n4 r2 X6 F
2
+ _3 Q( K2 \& M6 N& [
3
' ^0 c" \& k8 `% z* h6 J
4
. p! y: C4 E7 M' ~8 _
5
1 M/ S9 o! W) ]. Z6 s
6
: ^! p$ v* [) N4 \' Z. f
7
6 h8 g5 E5 z5 Y' V: E4 G
8
) w( o# v5 M/ d6 q, h. X2 P, ~) F
9
; s: z9 O# h0 ^
10
) q# V a. p# ^1 n$ }0 Z
11
8 h7 ]; w" @4 N9 j/ u
12
2 y% u6 I+ V8 [
13
5 {5 p, L. ~1 s% r0 P+ D# u# e
14
- h8 {$ l$ S6 }" I
15
2 _6 ], Z# H. O& W! Y' c
16
9 w3 T5 @ c5 l3 N. [( }
17
8 x; v9 c' p7 Q8 P, T8 E" L M3 o
18
: @( I9 p* \1 P' c
19
3 x& z4 F) z7 |3 N! C3 F
20
: J: r5 f$ d0 J4 H* [
21
( c, u. ~6 s( i4 S
22
9 D5 @: D8 g: h/ [; R
23
1 p- B+ K# l$ l
24
# D, W" ~. P t
25
' D( Y4 h4 }1 s0 R5 t% d% J3 U) I
26
; i0 O6 a& H! ^4 [! z3 K) u5 F2 a9 Q6 s
27
# k1 v+ z1 c9 p! n0 M
28
9 w. Z4 E3 z1 u! C% |
29
3 Q$ x( I& D/ L2 }
30
J" i* a6 g3 \; p2 h8 ^
31
6 i4 O _5 Z3 C7 [( K( g0 R
32
5 L' t% r7 x& l. X |5 ^
33
" o" W, Y' ]( h% |1 x4 `+ F+ T
34
8 [/ z: l& t3 t M
35
$ |+ S7 A u# S; k3 G; |. V
36
9 b- x5 o; ~5 ]2 ^1 V
37
7 U& G) ^( i6 r$ s
38
& K9 K) ~+ V$ K4 \. |
39
& a1 V$ E9 Z. i0 J. e
40
. e' ?- M9 L- Z' [
41
5 d9 {) l8 U% ? j$ _. j7 [
42
- u6 P; o2 B/ x. l9 O
43
" t7 n! ?4 A m0 `1 q1 X" K
44
4 ~) J6 ~9 Y3 K$ X% l/ ?* L# }
45
6 O4 v: f* B7 B0 `% E6 g
46
; p, m9 Y) X+ Q/ w# P d
47
& [' c1 @7 F! H7 B) h7 R j+ x
48
, z" v" y: l- V ?; B- q+ a
49
9 e5 u, x# d Y( G7 I* x
50
4 |2 @5 M; o+ w8 D* k% Z
51
# R+ Z0 T; Z$ @0 I4 W( ]. X! w: m
52
' v% m9 t& a' }; }5 _) ?+ b
53
/ U7 ]! [5 ~& `0 q4 F. A
54
6 G( M( `/ ? `! ~ V
55
, F" ~% ?9 S4 H( {
56
' P1 w# }3 s0 j$ ^" i y, A' N
57
i( O! @8 B i3 _
58
( ~% h E& r# N e5 Z6 q |
59
$ A' j9 F' i5 s" L' z: ^# m! r
60
- i0 P$ g9 \$ |3 A
61
& N! n7 a) n. Y J6 U& K* F$ O
62
0 x$ n# V4 N e, S
启动数字动效
6 L( k5 }$ k: E0 o% d7 o9 a
! B, P# @' Z" o( {$ l
const startCount = () => {
% I, S. h4 y9 j* L
state.localStart = props.start
" x% G' O, a& Q1 p5 {
state.startTime = null
4 \2 Z: i, Q) b b. w! ~1 [
state.localDuration = props.duration
/ I6 f* J$ G" ~+ j
state.paused = false
! U$ e) q* W2 D8 C/ _
state.rAF = requestAnimationFrame(count)
1 z7 G# K3 q% h7 O, s7 `+ T
}
0 D) [& j: A1 ?6 j
1
' u4 N9 I7 @9 j. `
2
& K# o' d9 a% T2 Z' g: r5 y& Y
3
! H5 g0 }4 n* L: e' [& O
4
6 |& w$ [4 g2 F1 M! m: H$ f
5
' _& @6 Y9 Q; _( R3 q; ^% k C: i
6
e/ }+ F5 C& k; n: V
7
% ]- H' e1 u1 v1 w4 P
核心函数,对数字进行转动
+ T) ?7 [9 A* l! K
% l8 u0 R3 K: @
if (!state.startTime) state.startTime = timestamp
4 ^4 j3 C5 |* [3 n6 }* C: B; Y
state.timestamp = timestamp
0 y/ h) f7 f6 j8 c3 h
const progress = timestamp - state.startTime
! w4 Q* [1 Q: x, Q& M+ \" v, i: X; X
state.remaining = state.localDuration - progress
; X2 U8 _1 {$ D$ X2 s
// 是否使用速度变化曲线
n9 X( J6 R6 n0 t
if (props.useEasing) {
+ L/ b% g& r+ ]# O5 `7 M" |
if (stopCount.value) {
+ r7 |# V, d$ C
state.printVal = state.localStart - props.easingFn(progress, 0, state.localStart - props.end, state.localDuration)
' y- M0 o. Q7 X0 `, J) y' v- E
} else {
. D2 |1 d; C9 J. G! R
state.printVal = props.easingFn(progress, state.localStart, props.end - state.localStart, state.localDuration)
0 u9 P) s8 W) p& a% C
}
1 Y$ Y, G Z- P% J. Q+ x' e$ O
} else {
% @ u( p, d) E7 D0 P, M9 P
if (stopCount.value) {
' w- {6 A. `+ k" T
state.printVal = state.localStart - ((state.localStart - props.end) * (progress / state.localDuration))
J0 v4 e, T! A7 a5 x6 s9 H" U
} else {
: j6 a1 @8 Z% Q$ A5 L0 H# Q
state.printVal = state.localStart + (props.end - state.localStart) * (progress / state.localDuration)
: w7 R/ ]$ A8 b- z
}
) ? Q; ~( }: S+ b. B |+ h; Z
}
; L/ l' j# B$ y9 V
if (stopCount.value) {
+ Y/ V9 j, o* M% C% n: b
state.printVal = state.printVal < props.end ? props.end : state.printVal
' T- f. u x5 q D6 [
} else {
9 b3 q7 o g- q7 a
state.printVal = state.printVal > props.end ? props.end : state.printVal
* y. h2 v; q& Z F
}
$ A/ c7 z* G# m( f
# a4 h& N9 z; W+ |! _: Y N
state.displayValue = formatNumber(state.printVal)
/ e2 |, I& N/ @% c8 y+ }7 Q
if (progress < state.localDuration) {
1 v) J u- _) k/ |5 q) @2 Z
state.rAF = requestAnimationFrame(count)
' X1 |# V" G6 ?3 O
} else {
3 w; K! X* N, C3 L6 T0 A0 o4 j
emits('callback')
6 `% D/ a1 V. _
}
7 x+ x2 l2 b; c2 \+ U7 {
}
* H5 }4 L# d. [8 I- {
5 K: b1 D) m( D8 _
1 Z- X' I1 ]! e( l f, H
// 格式化数据,返回想要展示的数据格式
; ~& h" L, b! W0 q; ^7 L
const formatNumber = (val) => {
0 D5 f) H3 Q, }6 v# B* W( c$ ]% g
val = val.toFixed(props.default)
/ x! j, X( G3 L ^
val += ''
, T# @$ `" J$ l
const x = val.split('.')
4 |% `1 Q" ?- B1 x% W5 f' y
let x1 = x[0]
# v% }! Y& e Z
const x2 = x.length > 1 ? props.decimal + x[1] : ''
+ n" ^' `+ A; J( z) P7 q
const rgx = /(\d+)(\d{3})/
2 ]; A3 K8 Z. [9 ~! a
if (props.separator && !isNumber(props.separator)) {
% v+ F" Z( n% j; P: Y7 _
while (rgx.test(x1)) {
& w0 U/ c& ~9 Z4 z$ S4 j
x1 = x1.replace(rgx, '$1' + props.separator + '$2')
% |7 \5 T9 @3 J& u7 w+ w( P& T
}
5 N. v" H# O+ b8 [/ o
}
+ w. t7 f$ D- \
return props.prefix + x1 + x2 + props.suffix
6 Q; s0 @; c3 m+ t
}
' D }8 ~: q H" |7 q4 q' q1 v- \) P# @
4 C% F, y$ R; l; x$ v1 x) ]
1
1 h! P( _6 y# s# D. S$ L* M: P& i
2
) n7 o' N7 P8 f6 u0 z+ k$ l& Y$ y
3
2 \4 Q* x# J. w1 s$ C
4
1 [$ e L% P( y* ^+ T) k. F
5
8 s) n4 {! X/ p+ a9 n3 I% p6 V
6
+ f. B5 \) r1 e, G9 Z$ n7 P) D
7
6 x* i k0 N: g
8
3 X: I! I+ z+ |" k$ r" d
9
! H8 q5 \- }! U: J4 H6 I3 @) A
10
: a9 B& U: a, y8 ?6 e
11
3 C. j! b0 l8 t" \0 x
12
6 ?# t& K& O6 G$ \) b: Z3 W' |+ t
13
+ T* @& _8 J6 W
14
5 G k, |$ {$ T
15
. C) u+ h# i3 b. T! j" r/ p+ Z8 g
16
9 J2 o" _# T5 m' L: p f8 o
17
. L# [' B( M. ?* f4 [
18
0 z4 d# S9 O( x% O$ B0 I1 H+ T
19
4 G% A, r; n- ~% m2 T
20
5 W& K. q9 c9 c" K- @, W1 Y
21
9 `, e1 Z9 X, H/ n3 D
22
* o1 J0 Y. {- }2 a' d
23
: _% b& @ V" T2 W$ t5 }: A- r) K+ W
24
+ S: k0 W8 e5 N( i3 {: C
25
- ]& `) s1 J* n3 B$ E( D/ l
26
2 B0 T3 r) V( Z
27
6 _! }9 b. A- x8 k9 b) E9 g
28
" j- D* U2 k8 W$ d. B4 f" N( {# Z
29
6 x& e9 O% H9 a+ d( u0 U% }- U
30
+ W; P% [5 ~" Q% A7 j4 G
31
) f4 O6 _3 e" @- c/ L7 P# L1 r
32
1 b( U; v% C% D. y6 T8 V3 D
33
) b0 |2 j% v j1 Q/ r) ^2 t
34
E- x- h) h: |- `3 J: n& @& `
35
f: u" u* m$ {( z% _5 J
36
R2 E+ {. Z2 c0 F& ]: p
37
; }' H0 {# F$ G! N3 P/ B
38
9 N: e# D, y7 U* U# z' I1 P9 _
39
; g! T3 }+ W1 t+ T- W, o
40
! @6 J) n" s& s3 ^( u/ I2 O
41
0 t! ?. W2 O+ X) d7 U' P; P+ C
42
# E2 s: b! t9 ]0 M8 Z
43
% l( F! Y. `$ N: ]7 j
44
% X" t) }" v) l$ [% s: {/ h
45
$ a! l/ j3 n' h
46
7 @! O8 u S0 u, E) e+ ]
47
" Z+ U" p) c9 f
48
: k5 `5 S* g% ~1 f* }
取消动效
9 c0 |. o$ v1 c/ `0 c
2 x1 [# v y" m5 V l+ L
// 组件销毁时取消动画
9 a! j' k9 v5 d4 t7 x1 z- U7 Z
onUnmounted(() => {
s* T5 T5 K+ z0 v
cancelAnimationFrame(state.rAF)
; ]% m C8 ?% N7 r
})
- j7 Z4 m+ z; ?+ K9 o, a
1
- J. v9 ]2 b6 o4 E, R0 E5 m
2
. R/ D6 |, Y8 a
3
$ ~- G* {$ h( u3 X& H" x
4
/ c3 D. d# N' m6 Q
完整代码
' W: z5 N' y8 E! u" g7 k+ C
- u& n1 i+ U p$ `
<template>
8 \# w' ]& z% R6 F# R. ]2 O6 l
{{ state.displayValue }}
; ?- Z. K5 ^ w* q1 \
</template>
- N# m' t' L- q$ V: m
4 q7 p- j: r, F9 q" e, F
<script setup> // vue3.2新的语法糖, 编写代码更加简洁高效
3 a2 o) x p/ p! L2 E9 |
import { onMounted, onUnmounted, reactive } from "@vue/runtime-core";
( c9 k& N8 v4 h. ]
import { watch, computed } from 'vue';
: L% E* T) s' y7 x0 B0 |
import { requestAnimationFrame, cancelAnimationFrame } from './requestAnimationFrame.js'
8 Y+ M( _- u9 {! h8 h, n; C, t
// 定义父组件传递的参数
2 O' W$ d% Z* J+ V9 ]( Z+ [0 c$ x0 B
const props = defineProps({
$ W: Q5 m1 {2 L# R
start: {
. v' g( K* g1 m* N8 c- F
type: Number,
8 I% p/ h' C9 x, ^
required: false,
# C/ t, I8 N1 D% [
default: 0
" T) g# E- _6 P* Y# O
},
" i% |7 L; T. A4 G* n' q
end: {
7 n' g2 H2 [9 e# @6 S% Q
type: Number,
* |2 m$ }( {" W' K# ? ]
required: false,
# n% }9 y6 i' y; F- J8 `9 M) I
default: 0
: ]8 J+ Y+ C6 F9 _* K% i' N0 A
},
5 \" X3 y) k6 |) @/ u" }
duration: {
4 Y, }% ` H6 q/ \; _8 p6 W
type: Number,
6 ~5 X7 K8 W- s& L
required: false,
' S, N& o; D7 h7 Y9 u
default: 5000
) C, D$ P) ], H) e
},
9 R2 v1 A7 Q5 y) @0 \$ m
autoPlay: {
% c# U! Z9 A: c. a! d: d
type: Boolean,
+ O7 a& V( B! O7 P. [/ z
required: false,
2 {/ w$ w5 P; |) K9 e
default: true
% z6 z4 o* W* f" i j
},
O# w/ q8 e) x- \ m
decimals: {
4 h! T0 b G F+ C, s
type: Number,
, @" b6 I% k: Y
required: false,
6 ^: X, [4 `, e0 \/ A3 I8 _
default: 0,
* h: I* [4 [; V' e& i, R- Y* r
validator (value) {
" m0 x6 R; c: o
return value >= 0
! d, O% s* J4 {! w$ E* F8 R( @& }
}
4 G/ h5 O+ s$ D: w0 O8 \. v3 I
},
3 X, g( ~: U; n0 n, N, q
decimal: {
6 J- Y+ o# G9 W( z: V
type: String,
4 ~! B' U8 A$ ?9 |7 ^7 N# F( a
required: false,
+ n' }. o6 h9 s$ @+ {
default: '.'
. W3 j/ \( n3 G
},
7 @% {: D: l3 _% [3 o! l# b `1 G
separator: {
! Z4 U) A( u( {
type: String,
9 K# J3 t, r6 U$ D6 Z- ~# d. G" D
required: false,
p8 F7 K- x8 V: c1 i* f) a
default: ','
* S$ \$ Z0 T3 X3 o
},
% O, T' f/ J7 y* f& P' V
prefix: {
* F+ T- D- f- J( r4 |! }6 _
type: String,
: i& B* x8 { C% v) `9 B
required: false,
: o/ J. o6 l+ v3 X0 h/ ^
default: ''
% x7 a) |! ]) w) q: W/ Z/ M
},
0 [: H( D) R3 T$ l. t" @5 c3 @
suffix: {
1 s: n _: \" \
type: String,
" ^# n" _& \! Y9 A
required: false,
, W, C( l0 k) S. M
default: ''
6 M1 {2 d" I3 ?; z- `. ]
},
S5 ~3 e) U& [+ F7 k9 u8 i
useEasing: {
: I b3 B% s! P, ^' ^
type: Boolean,
' L7 D% m! v& J: o6 t
required: false,
4 ^' Y, z% L2 ~: {* ^& {& n, o1 j( y
default: true
1 z D6 Z& Y& p# @) i/ x9 n. u; z7 Z
},
, k9 [ I1 D* H% z) c2 j7 j
easingFn: {
. u# o- l; O. Z1 r$ D1 T6 A. Z# Y
type: Function,
, B3 e. o/ k- X7 q- j8 T; ~
default(t, b, c, d) {
% V6 Q/ m9 E8 c, m# M) P+ z7 C) k
return c * (-Math.pow(2, -10 * t / d) + 1) * 1024 / 1023 + b;
' r. ]6 [7 O; w' l" g
}
% K' ~. P9 N1 n3 V0 g- I" E- {7 Q
}
* h- ]' m" O" |9 ]
})
4 A% @7 ]/ O4 C
( L; `! V5 s3 {# E& J: y5 @& D
const isNumber = (val) => {
2 }1 d3 d% o' q8 K! m* _
return !isNaN(parseFloat(val))
0 f5 w' o, l* k7 g
}
+ R; m7 h$ B* s. d& S
) h, |3 `, h, q' `% S. ~( t6 M0 M! J
// 格式化数据,返回想要展示的数据格式
) p! p: |" z7 b
const formatNumber = (val) => {
/ A, r r$ Z+ R, }" P
val = val.toFixed(props.default)
8 x' `6 z, H2 h" S
val += ''
1 h9 l3 h! \( v4 J3 t
const x = val.split('.')
, J% z) l" ?8 S! q# n5 h7 T
let x1 = x[0]
: O8 O, Q+ |: `6 h5 L9 x
const x2 = x.length > 1 ? props.decimal + x[1] : ''
* {( }) Z# x0 V: k5 D
const rgx = /(\d+)(\d{3})/
5 v& P+ h- T( q+ W7 F4 r
if (props.separator && !isNumber(props.separator)) {
) Y, h/ R6 z7 b, j _) ~% h
while (rgx.test(x1)) {
8 s+ L3 t7 A$ J9 @
x1 = x1.replace(rgx, '$1' + props.separator + '$2')
" I \+ f2 j/ Z9 r* a: B% a6 U
}
% C4 [* X; L6 J2 m6 ^! Q: g. y
}
! d, W1 @. ?/ }4 g$ s4 N' l
return props.prefix + x1 + x2 + props.suffix
4 x: `) T# ^2 n$ p* a2 g
}
' u- k8 T# g) i2 y& J8 Q
3 g N; m& J3 M2 B
// 相当于vue2中的data中所定义的变量部分
$ W$ H' d2 O7 V* Q5 D. G) p) j
const state = reactive({
$ k$ I3 f5 b; X0 }
localStart: props.start,
2 ?& E; @1 }! r& e' O% P2 A8 B
displayValue: formatNumber(props.start),
$ p0 G! e; {3 E- r- K5 C, r
printVal: null,
. R/ K6 M7 C) b0 \' o
paused: false,
$ w6 g0 U. c6 e0 h, ^! F v
localDuration: props.duration,
/ u. h1 O& `0 P3 E0 a3 j5 E
startTime: null,
$ h l1 {6 z I6 L- J) m
timestamp: null,
1 M/ b, O! b D
remaining: null,
/ l" P. g6 n) I. `1 J
rAF: null
l8 E" q7 r+ C# j; w# g# F
})
+ S- x5 ~( k7 v4 v5 d
/ N' t7 ]1 z1 R6 F/ J' q4 c% s
// 定义一个计算属性,当开始数字大于结束数字时返回true
9 C7 T6 @( o5 F
const stopCount = computed(() => {
1 F' S0 @8 R! |6 U9 u0 m
return props.start > props.end
# H2 Q, f1 n/ |9 n+ X+ u* d
})
# r( \5 N( K; |" L
// 定义父组件的自定义事件,子组件以触发父组件的自定义事件
) q( e* _5 y& H7 H& G* R
const emits = defineEmits(['onMountedcallback', 'callback'])
q; n3 `; V4 ?& F% T8 o$ B
7 v) @% }, B% X8 {0 j% U
const startCount = () => {
- s/ H) L4 ? Q
state.localStart = props.start
* O* G/ {0 s2 C% N+ I
state.startTime = null
# `; \: E& N: r9 }- Q/ j
state.localDuration = props.duration
8 L% s. M$ C/ }. b/ x
state.paused = false
7 V2 z0 a. K. n. a- @$ L) b7 j0 A
state.rAF = requestAnimationFrame(count)
. k. s. [& a, Q1 J3 {1 w! v
}
* M6 Q4 }* c4 D. d9 L6 r4 P
+ s, L/ _( }6 C1 y; k
watch(() => props.start, () => {
, n; n* j" l* u$ b
if (props.autoPlay) {
6 W% F, {+ x% y! [; ^
startCount()
7 Q1 B9 V9 a' R' ~
}
6 d; X- S' q n; f0 E0 w% a
})
5 J# K% X. T7 S) ]' v
, u$ I% L- A" }; s* Z
watch(() => props.end, () => {
' j7 F/ N Z; c9 f
if (props.autoPlay) {
8 q; l8 C6 ?1 }; D
startCount()
# p7 B0 r }$ g
}
* e: Y; F6 }1 r
})
" v% Y9 p. O: q! j5 S- f
// dom挂在完成后执行一些操作
" {# D; s: K: R# R
onMounted(() => {
; r& ]$ r2 u+ G6 w3 `9 A
if (props.autoPlay) {
" ^4 S$ e* u6 R; P7 V' s0 @
startCount()
' X* o5 _: D- }5 o* m) i: D
}
$ `1 i N) B" E! V# K% r/ r
emits('onMountedcallback')
% R; V1 O4 p" W/ \7 p0 O8 T9 @' M
})
5 K$ W2 W0 j# `- z! x* H! O
// 暂停计数
" C0 g5 p4 n. T
const pause = () => {
4 W' k" W* U: c' P
cancelAnimationFrame(state.rAF)
5 l" d7 \- C- J5 y5 x
}
( z1 i# v; O1 t( p
// 恢复计数
1 B4 b9 L" h# C8 S- R
const resume = () => {
0 @& M/ E4 O k2 D8 Y
state.startTime = null
7 ]5 ?$ g7 ^4 O, p* k& Y/ H
state.localDuration = +state.remaining
y8 r$ w$ @4 q5 b v" J+ M e" v
state.localStart = +state.printVal
" K2 T4 j V9 `9 P+ N' h
requestAnimationFrame(count)
# {5 v( H) `. ^/ P9 c; x Q
}
8 i7 t, W% a6 j9 Y" V d8 A
' J; S4 d7 X: L* f. `: _) ~# `
const pauseResume = () => {
2 H( y, R0 e# l
if (state.paused) {
! e* e+ a7 \: {- d4 H
resume()
# `) ~0 J8 ^. e* x ~/ K7 z
state.paused = false
" V9 V+ O4 g0 O( o
} else {
$ t F7 j5 P, H4 R& u
pause()
5 N- h: D; z/ N& T1 N9 A3 W+ S
state.paused = true
& t g% y9 K4 |6 ] G9 `
}
8 Z/ h. z# h- P3 K) ?
}
6 \& |" }: w P/ H1 i
4 s" v3 V$ Y/ C! Y1 k
const reset = () => {
- p3 u$ L J. c7 U
state.startTime = null
0 i: e7 j: e$ h/ F
cancelAnimationFrame(state.rAF)
i7 T' I0 C( w& Z- B, b
state.displayValue = formatNumber(props.start)
& `9 }1 @: O1 o3 N9 k
}
6 f$ e' |6 @6 [2 }4 y
3 Y- r6 l7 ]( h# Z9 M/ o
const count = (timestamp) => {
" f/ j0 H3 F/ h% r- i+ [: g
if (!state.startTime) state.startTime = timestamp
9 E; f# W- w: H2 ^7 E3 i& _
state.timestamp = timestamp
, C3 k6 [0 Q( V: x2 Z
const progress = timestamp - state.startTime
, R+ }2 A1 H, ^
state.remaining = state.localDuration - progress
7 r( z: ~: E M6 F, z7 _2 U4 D8 K
// 是否使用速度变化曲线
$ Q6 a! _! b3 O h
if (props.useEasing) {
$ A X! I1 Z5 @4 g
if (stopCount.value) {
: H8 Z$ `; Y. D; }* l
state.printVal = state.localStart - props.easingFn(progress, 0, state.localStart - props.end, state.localDuration)
2 ^; E* l1 g, x! U' g, I
} else {
5 \5 T" j1 _0 h9 ^ K
state.printVal = props.easingFn(progress, state.localStart, props.end - state.localStart, state.localDuration)
; k# e. l) |5 P7 Z& |! z
}
6 A/ B, s. \2 I- s) g
} else {
2 R4 R0 s$ }: U( k8 A( I3 s& E
if (stopCount.value) {
2 X8 F/ v/ b3 H) K) J) |
state.printVal = state.localStart - ((state.localStart - props.end) * (progress / state.localDuration))
# n# z1 Q, W. q+ D* ?
} else {
' N G7 x# R; Y& x
state.printVal = state.localStart + (props.end - state.localStart) * (progress / state.localDuration)
0 x) N$ j% W: E3 m( n
}
0 `% b# m1 t* M7 F: R. l4 |# g
}
0 `; [* k/ c7 b9 `4 c h9 C
if (stopCount.value) {
$ @2 B; E0 x- O
state.printVal = state.printVal < props.end ? props.end : state.printVal
' F8 J8 H! k7 }, H; ^ ^
} else {
2 n& L# {7 t2 Q8 N
state.printVal = state.printVal > props.end ? props.end : state.printVal
" V& f9 Z0 i S: B2 v# r
}
0 W2 S" k1 x0 C# Q0 L5 \; _- ]9 e6 ]+ R
" M) n! y6 Q& h# Q& j: k$ L3 x
state.displayValue = formatNumber(state.printVal)
" Z R8 C; G- W
if (progress < state.localDuration) {
) `, o7 M0 y3 {% V F5 z
state.rAF = requestAnimationFrame(count)
# `! ~0 D+ q' c
} else {
. M" }3 t+ z' T2 r2 Q
emits('callback')
9 A8 k0 o' n5 b8 {' V
}
, |+ \7 j. T" y1 U# G
}
( n$ a9 p* k% ]) m3 [2 y2 Q9 Y
// 组件销毁时取消动画
$ p; b$ o# e% k8 m% x- `
onUnmounted(() => {
. x# ?8 l2 w3 V N5 i
cancelAnimationFrame(state.rAF)
4 K9 p6 q8 P" P2 T: E
})
. M( h0 p. ]$ W% ~1 h4 q$ r
</script>
5 f4 X. \* i+ a# q. B
. `( T$ t3 B2 P m5 r+ m
1
. Q+ x$ P; z7 c- Q
2
0 G6 [+ G2 q* T/ r0 b
3
0 c3 } i8 ~, E' o8 q
4
" c3 ?% N) q; a; V0 X6 m s* \
5
2 Z* k/ N/ i1 \+ Z
6
7 a' U+ H7 t N4 M( N6 l4 [
7
$ ~$ B* _) \# n) P
8
% v1 X5 k3 h9 ?3 [ B' }) }
9
; `4 E) x U, R8 P) m
10
6 o( Z+ d8 O- o' R
11
0 q" f6 Z" d6 L% P% Y9 f0 x
12
1 m8 H2 s, A! ?' T7 C2 P* g
13
, q" \2 `9 u% K8 l1 A9 `4 S) ~
14
9 s5 A9 M4 C7 D9 B( w
15
2 K: d! g3 [4 k, p$ g2 A* m0 j! |
16
( B+ g0 ~' q! t9 `
17
N+ `# b: }1 F
18
$ R# Z: [! n3 R5 O; _! @+ P
19
; ~4 N3 I5 y! @. K4 P
20
2 t r! Q2 X# q( g# u- f
21
& T* E- j: ]' g: T! X7 {1 U
22
7 U- g6 G9 L$ o: n
23
% p4 V6 O: a5 L/ y$ u
24
" C( C! g2 M" A* H
25
6 p7 T+ {1 M1 X! t4 V, ]- b3 _# v
26
8 z! h: W w3 o% v- ^
27
/ d% n0 D! I7 z
28
% n7 y) D+ G) j& q0 i. e
29
f# x4 P5 S, s8 }$ P3 J
30
w0 y8 X4 v7 }5 A5 K
31
8 w$ m+ y# ]3 p; Y, g
32
1 B9 G, z7 R* ~9 K5 H
33
8 M4 |+ Z- ?+ N$ D/ e$ \
34
4 D& g1 Z% _& t" k
35
# W L Z4 B, @* x0 i1 n
36
* X) H& j2 o) Y1 C- C' T4 H- w. _3 p2 \; m
37
) {4 A6 H3 i+ ^
38
. C# T' r3 c7 v+ v% Z8 ~
39
6 b$ K/ D- I. ?- x
40
# P( R; g9 U0 i! p/ x
41
% x3 g" c. _! }5 R. D, o
42
/ u# n* s; U1 |/ X. p
43
- u. h7 C( x4 Q0 o
44
: e x6 |9 A/ D! x, S6 k
45
% x& e: w, @$ f! C
46
6 u3 g& Q2 m$ \$ N' A- H
47
/ c) `; k% X- X3 R, L
48
, |8 a6 \( u, U5 k1 |
49
" W% Q- Q7 g0 i+ l% O
50
4 U- G1 A" z5 n1 e
51
* y2 M! ?! o8 `% I
52
8 j2 u, w, [3 J) U- F/ J3 \$ a
53
! R/ l/ q* L. B! n p3 r: a c
54
, v/ N/ }' ^/ a2 t1 ?- ^- ]- F
55
) x6 I' a" ~) r/ h; W, _* C4 l( S: D
56
/ I# ^/ r. V/ R, `, V
57
# n2 M, f4 G& D4 G
58
1 w0 Y2 U5 p/ H# ?$ T7 U1 S; C, N
59
) ]8 O3 C* }: z
60
5 x+ j! K y+ n+ T8 h% F" B
61
- e- @0 }7 U6 }! A
62
8 {$ w& c! N; z- y" T7 l" E
63
/ o6 V6 W* N% N: N
64
% Y& {9 V8 ]. i
65
7 f* D; } Y9 i' m& X/ a
66
. `! j7 j0 `' V/ m0 a
67
6 h: } U. h Q. Z7 n$ m
68
0 W' \: p# x1 f, C
69
5 u3 k, A0 t4 i7 }# ?$ y
70
5 A! L- ]7 e* D. e# \* q
71
+ |, h2 @) w s$ Y9 r
72
# u' A+ z) x: e7 H
73
& h, K5 o0 Q4 O! s5 Q
74
3 l7 N6 h; e6 Y9 U
75
6 I+ t1 q! F8 E. ~7 ~! I, u
76
h3 s5 n t/ o9 v& q- R1 E
77
( x( T6 H- I8 g. D( p. a, N
78
- l. |2 `) ~+ M6 X( w
79
# Y: F% A4 b5 B1 t6 ~/ s8 B! m7 I
80
& H. n6 ]) h1 [/ Z/ E* w
81
. D9 ^- D/ V& ?8 ~& N/ `
82
$ D) z. q' e' R3 v" b- A
83
- Q. k, ~8 }! [# R( J
84
; h- t l: x, F0 i ^! a6 Q
85
0 e7 @) h3 S' I7 N1 P5 q
86
+ n. L7 x! b. A% ~# Q
87
; ^7 K5 N( Z# }, n
88
4 P3 [/ u: @+ F% o: b$ {- {
89
& k. `4 A% F" M' O, r$ W) d$ R
90
( e6 r( p" U6 @
91
2 c& E X, r% y7 T5 H9 X0 H0 u
92
3 H% V7 \. x9 `4 d7 ]& l; E5 G
93
9 O* p& X- s0 W$ m4 d
94
" c" o6 l+ }- i! Y
95
* q8 K. p4 X0 E9 R0 [( E! W" w+ b
96
# b4 ]! n v! j. @; v
97
" l/ m; d z6 O! `% h$ P
98
) S7 U/ |4 N: m8 |) j5 n
99
4 s! s' I* d2 o: E
100
% s! _3 }: x8 a, E3 d
101
6 p; Y+ k" s' J* T( g$ S
102
3 h( \* M! c- L' S$ k0 s0 q5 R
103
+ [3 k- F( X( }& N: z; y
104
" e' P( M1 O- ?0 Q: ~" a/ }/ G
105
% ?. n8 T. h8 [. j
106
1 @2 d7 q6 k" k& q. p, J" ]
107
8 n1 ~6 e8 x+ g0 C0 n
108
( k- b9 o$ d2 g# B# B2 v' T
109
5 E' a3 ^6 |! K
110
, x. g! c- \ _2 b( \
111
' a ]' d& g2 |4 s# ^! X2 q
112
l4 K; K `1 i) | P R0 R
113
% N- A: [+ z7 }
114
) v7 c/ [8 B8 U- X5 }3 ~
115
+ H/ ~ \ `1 A* z1 D8 L K5 d
116
. g p" P1 f! j' q* |: h
117
1 v, \# R2 A: s1 Y% _% y3 j
118
) B3 U3 k i) P* r# M
119
( }( J4 Z2 i+ f+ { D9 v
120
9 M% i4 _9 l2 \7 R4 v' q
121
3 u( Y; }; a+ h3 X Z1 `; r
122
% X% ], I, N& `2 V0 ~
123
, F; i. K- h( ~# f5 E: e8 m. H
124
: ~0 n) j0 p2 k" a& N
125
1 i/ h) e5 R) o" ~- u
126
% m4 G C) o+ {; e% B
127
6 Z. P* h- {7 }8 s L) a2 L
128
& u% ?% p# W8 t+ R3 V
129
' m, E( f! Z$ R7 B' j/ g! y
130
' S( h" @' C1 V( Z# w
131
( q8 F7 w$ R( J h; U
132
# v; P% V+ q- d* U
133
% r- o& |0 k/ F6 X* ]) j
134
t/ X5 M! ~5 |& B
135
1 x% T* i/ P' i1 |$ ^0 w
136
" `2 i# @ j" V6 y: S
137
% s: ?$ ?( u* `5 C
138
% N/ s8 ~* X' I! s
139
% T4 X* O8 H8 J1 v1 O1 v' z; ^
140
& Q0 F0 K& ]' W
141
0 Y/ E8 B* m3 Z( j0 _" @
142
/ f* S2 A4 p; ?4 e
143
8 x2 z" [% o; _5 \0 _9 V
144
4 j7 B; |% J3 W
145
7 D' f4 J0 j u* v, u
146
3 O# q' [. A! l7 n: {
147
* ^7 ~# z& ?$ }( t0 _& I
148
3 N6 F" w* W1 p
149
; q) i$ I0 D- n" ~! N; L! }
150
7 Y4 s/ D" ?$ B, h# a! o( ~
151
0 X/ R& I4 A! M
152
) f8 l4 ^+ W! f/ P. d+ z- M1 U s8 g
153
! ]( }) }1 g/ R- o
154
: h @' d% T; f6 z7 b9 W& U
155
% P! k+ P- ?5 {7 y" ^9 i5 \
156
- y& k9 N$ c* y5 Z3 B
157
, S* d6 r* w0 I9 ~7 D
158
$ b/ f) M3 F% K$ C
159
7 f$ A1 C# j" w) m* g7 v
160
. R- t. E }, R$ m/ Z; ]! C) c
161
, t# b8 E% {' j2 g- B, Y
162
! S& U( d; N2 d/ _4 L& C3 g5 O* D
163
- W* M6 u; \* u5 Q& a. d/ s
164
% @5 y; Z. B/ ~
165
: u/ p' r7 B z- A8 T
166
8 w; e. G4 O% p$ @
167
3 g& x. @: |1 H# o' z" t
168
9 b% W/ o# v+ V0 n% c# Q
169
2 ]% J% R4 [' I$ G3 e! E8 k8 Q/ y t% |
170
% [$ ~& Q: f2 s
171
3 I, y' p. }- u+ |
172
# n' L- R; k* P" G3 i
173
" r% q- l) m. W6 H. g
174
' k6 J+ b6 n; E4 ~% e+ S \
175
/ _/ C7 r. x6 Q9 W
176
. e" \; j9 g3 {
177
4 t0 J" ?- o5 j, A) ~9 {
178
3 M! y/ ^: t3 G' E9 z
179
: a+ @# n" [) F
180
1 E' H" N3 J0 A3 |( O/ d( \
181
9 p' k( [0 `- s1 }. ~
182
' m0 y5 q1 t! `& Q
183
4 F+ O/ M9 n1 B# F5 A4 Z+ p& Z
184
$ C6 w4 Q1 s* w( z! P4 V
185
; Y" m: \; F* f* k" F4 a. S- c
186
7 \$ ]' e1 o5 l0 M. w! ~. B$ \
187
0 u m5 z0 t7 A( O
188
5 W/ e- w8 G; U: T# {4 O/ V6 w
189
( [, R& p* Y A- ]7 S. x( }2 ?
190
& g$ a) w. ]" D- H# t" N5 M* l d
191
. _; s+ h5 z* |' F3 o( }" E9 k3 g
192
2 \: |% W3 Q7 E; P8 n$ ^, r, h, u( Y
193
\+ c1 N% v) z% {
194
4 K+ E0 _ B: G* E
195
8 ]$ h- {9 @. D; r4 Z [6 q' b, ~
196
. h+ W2 R5 O3 k7 F+ h8 H
197
a' m$ V' Y9 k% V7 @
198
q( u; z, v8 q( e8 L5 b
199
b, z5 R) t/ P$ ^1 X0 F8 R
200
: ^6 R9 I. s3 Z; r9 A
201
2 s; [4 g4 G' X7 j& R3 X
202
! I' z6 M* o* Y& y! d
总结
4 a2 W: ?' y$ r/ Q/ B- `8 {
自己封装数字动态效果需要注意各个浏览器直接的差异,手动pollyfill,暴露出去的props参数需要有默认值,数据的格式化可以才有正则表达式的方式,组件的驱动必须是数据变化,根据数据来驱动页面渲染,防止页面出现卡顿,不要强行操作dom,引入的组件可以全局配置,后续组件可以服用,码字不易,请各位看官大佬多多支持,一键三连了~❤️❤️❤️
7 P2 ^9 v) ]- a& K
! e0 f1 t4 x* `' [5 x
demo演示
' B$ U) X8 j) P
后续的线上demo演示会放在
& o* R d7 t" f) M+ N+ F6 T
demo演示
& `1 s4 Y: E1 G P6 \+ x
完整代码会放在
/ c. S" L$ l! x' z9 S
个人主页
' r5 F/ c0 ~2 _! w" C- T
- @8 y& e. a- F" ^) ?7 s
希望对vue开发者有所帮助~
Y& r' \( g& H' e
8 F9 s* G6 ^+ r& z" D
个人简介:承吾
! ]& \9 p/ ^, o
工作年限:5年前端
7 F! Q! F6 e& o0 F" a; v! g- n
地区:上海
: a# Q$ ]' R; K4 g7 X/ C( z
个人宣言:立志出好文,传播我所会的,有好东西就及时与大家共享!
) o6 w# z. s+ Z+ d# S
6 M6 \' n, y7 Y; M- T4 b
1 N0 x' x, v& ]5 {" _
! t3 a0 P) d5 `
" P2 a* n$ i; {5 M( A3 _; m
————————————————
7 l2 }! O( Y' J& K; K, }8 X; [
版权声明:本文为CSDN博主「KinHKin(五年前端)」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
' l( V( n& x& @9 m
原文链接:https://blog.csdn.net/weixin_42974827/article/details/126831847
: k+ R& V$ b5 B
3 k N$ E7 h a B3 T# k; E
y3 {* c5 V3 R- R6 {
欢迎光临 数学建模社区-数学中国 (http://www.madio.net/)
Powered by Discuz! X2.5