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