- 在线时间
- 1630 小时
- 最后登录
- 2024-1-29
- 注册时间
- 2017-5-16
- 听众数
- 82
- 收听数
- 1
- 能力
- 120 分
- 体力
- 564444 点
- 威望
- 12 点
- 阅读权限
- 255
- 积分
- 174556
- 相册
- 1
- 日志
- 0
- 记录
- 0
- 帖子
- 5313
- 主题
- 5273
- 精华
- 3
- 分享
- 0
- 好友
- 163
TA的每日心情 | 开心 2021-8-11 17:59 |
|---|
签到天数: 17 天 [LV.4]偶尔看看III 网络挑战赛参赛者 网络挑战赛参赛者 - 自我介绍
- 本人女,毕业于内蒙古科技大学,担任文职专业,毕业专业英语。
 群组: 2018美赛大象算法课程 群组: 2018美赛护航培训课程 群组: 2019年 数学中国站长建 群组: 2019年数据分析师课程 群组: 2018年大象老师国赛优 |
vue3 | 数据可视化实现数字滚动特效
% C0 e7 c; m3 ` b( l1 `; f |1 l* u$ \( b
前言, i; I4 f4 C$ P+ A3 S _) D
vue3不支持vue-count-to插件,无法使用vue-count-to实现数字动效,数字自动分割,vue-count-to主要针对vue2使用,vue3按照会报错:) y' p! x5 v0 G6 v+ C
TypeError: Cannot read properties of undefined (reading '_c')
* n0 U7 _' u7 }4 j( I* d" f的错误信息。这个时候我们只能自己封装一个CountTo组件实现数字动效。先来看效果图:( R* Q) B" \; J2 a" w' @6 G; }
0 q0 _* L) W- |* Q& @* F8 U. w
' T' G" l! W2 O0 e* @思路
- x7 F) e1 M- h* V+ [使用Vue.component定义公共组件,使用window.requestAnimationFrame(首选,次选setTimeout)来循环数字动画,window.cancelAnimationFrame取消数字动画效果,封装一个requestAnimationFrame.js公共文件,CountTo.vue组件,入口导出文件index.js。- S: y* z! _5 k/ P/ }
* v7 P3 V8 I1 W6 T- s- a( X& P. _! ]文件目录1 O; y1 A: Y$ {5 w* b( Z
' S4 \# z% r2 Y! Y' e9 E
* {' i0 Y, Y; }. N使用示例# r1 r4 E9 s' f
<CountTo
9 _2 u- O) \' W% R2 d* j; U :start="0" // 从数字多少开始7 x( A+ I2 G6 z" T( B
:end="endCount" // 到数字多少结束9 F, j, E9 _& O3 G
:autoPlay="true" // 自动播放
4 w# `' O' y& I' O9 e" J# p7 @" C :duration="3000" // 过渡时间0 ^% c8 Y+ i4 R0 S& \# Q
prefix="¥" // 前缀符号
6 }; z( G; ^3 w* z$ A suffix="rmb" // 后缀符号
# J7 K2 X& g& N7 g$ t />+ l! L- j; S" C2 X. l( j
1
. ^* t, F7 `( A4 N2 {2 I20 E( I4 x9 w6 ]) h+ s; N5 w
3
( S$ G/ a0 G4 l1 X+ ^! r4" G# g" I5 _' z! w, _& d* c
5' d. a8 d8 b0 d( T+ ]. Z+ d
62 M2 T3 t3 u7 |8 T' d1 |9 h( o
7
! t: q- t3 D6 ?4 [( Q; Z. g2 d83 [5 C$ ~# d1 |
入口文件index.js- \' I, _. v' ~( j: z
- t$ E- Z$ n) E: o* H6 h' i
const UILib = {6 e) ~9 T( R! D" c: Z i& c7 P! @" t
install(Vue) {
2 i( o, x) b9 e( U7 T& G Vue.component('CountTo', CountTo)6 Z J Z+ W" E
}; y/ D* E( d+ s
}
+ c! q" e$ l4 \; D* g8 U& d" k2 ]. v% q9 M/ {
export default UILib
6 o5 x- `2 \+ ?- _: Q8 x/ ]2 R/ D
1$ k: k5 a3 d" W4 R+ P$ A
2
' u8 O! H% D$ I36 x% t7 Q( x2 c$ a! a! W
4
' u" L. r, L2 K; B. c5
( S8 j! G; J* c7 K; s1 x& Q6% m0 M0 g6 f% S9 b% y9 d
7
" o1 C( H" k+ J$ ]* A8
4 k/ G5 a& r* j P; b9) g( y, ]3 W; E: ^9 |0 L7 V
main.js使用- g) Y3 h$ |$ L. z# _
import CountTo from './components/count-to/index';) H% D/ v/ I; O. ]
app.use(CountTo)
, Y$ j# l! G6 k' w# T$ a1
# k: k/ S! o6 Y2
! A; X& ?1 W. T: XrequestAnimationFrame.js思路% C9 f* F' _! f6 ^, ?5 Y
先判断是不是浏览器还是其他环境$ e. B+ Y, c1 M6 A8 j
如果是浏览器判断浏览器内核类型" w3 Y* b% k7 \0 M( E7 f( W
如果浏览器不支持requestAnimationFrame,cancelAnimationFrame方法,改写setTimeout定时器) v3 L& x+ R1 ?( K
导出两个方法 requestAnimationFrame, cancelAnimationFrame7 \1 w( `. l- n/ t) Y
各个浏览器前缀:let prefixes = 'webkit moz ms o';9 N* r, ]7 Y! [( g0 L
判断是不是浏览器:let isServe = typeof window == 'undefined';6 }! u2 b; Z1 z) g
增加各个浏览器前缀:
8 C. q. H( P* X" |let prefix;; |+ \" M$ U% o+ H
let requestAnimationFrame;
) w. z# F6 p" f# C9 d/ Plet cancelAnimationFrame;' [& o3 i% O$ z
// 通过遍历各浏览器前缀,来得到requestAnimationFrame和cancelAnimationFrame在当前浏览器的实现形式/ d" M4 L1 O% y' V, I
for (let i = 0; i < prefixes.length; i++) {" c7 L. B/ z( |$ }! F
if (requestAnimationFrame && cancelAnimationFrame) { break }$ L3 }) E/ K2 I: b( U8 b
prefix = prefixes
+ s" |# u' V' k% j7 E8 h# w requestAnimationFrame = requestAnimationFrame || window[prefix + 'RequestAnimationFrame']
! P, G2 c/ F3 I9 J9 P5 f. Q cancelAnimationFrame = cancelAnimationFrame || window[prefix + 'CancelAnimationFrame'] || window[prefix + 'CancelRequestAnimationFrame']$ y" s" k8 P) I X- M- _
}. O, y2 ~. B2 s5 f0 ~
4 D0 G: K. Y+ V/ t( _
//不支持使用setTimeout方式替换:模拟60帧的效果; o; J6 }* o% r7 ~6 C/ O! T
// 如果当前浏览器不支持requestAnimationFrame和cancelAnimationFrame,则会退到setTimeout
7 U( \4 X' y4 @7 ]$ l2 {) F if (!requestAnimationFrame || !cancelAnimationFrame) {5 P$ r. O% p, y! [% F+ w
requestAnimationFrame = function (callback) {( q$ R" I6 j0 z: Z5 y! }3 T6 o9 x
const currTime = new Date().getTime()
$ d# k6 D" s" c. ?' K) ?7 _ // 为了使setTimteout的尽可能的接近每秒60帧的效果
) k3 `0 Q# I& W" @1 D1 e const timeToCall = Math.max(0, 16 - (currTime - lastTime))3 v& p7 b M; g- v! O
const id = window.setTimeout(() => {
7 {0 t; r1 O( J" u callback(currTime + timeToCall)
6 E6 Y" A$ @4 K! y1 ?2 U }, timeToCall)
0 Q2 k! {6 @0 P3 U, t# G lastTime = currTime + timeToCall/ s2 H2 h* {( m( {9 l
return id
% t2 A) w& t4 r }% p; t6 Z, x i' t; |* I
+ @6 @( B7 t% g cancelAnimationFrame = function (id) {
' K8 @7 v2 N; w4 v7 D' P! o window.clearTimeout(id)
! @2 y d { v$ I& R1 ~ }
* ^2 G4 N; E6 M" `: k) E }6 y- ^; `, C# y1 \+ o
) s( J0 Z1 K& s f) J4 Z8 f
1
; }. ]) x! ?4 k; N23 u- y/ K% I8 E) Q# _" M& C
3
; f4 q+ \& X8 Z J; V0 R6 c8 H4
/ A8 h/ D) D) f" w5
" s; i+ V8 @6 Q* T) n" J3 w& K6
- u& I, q7 t9 a0 N; D% o1 G7# L _: R1 k: B1 J, h+ @# }, ]/ B
8
, a/ |! Z& \9 y$ O, ~9 l' W% D9
" Q/ c) A% q: y. ?/ P10! f/ {% |7 f0 j7 X. ^2 @ [+ b/ _
11
# B- f; }& B6 x$ m+ I124 ~ r* x( X5 e: G& ?
13
* Q# X: ?. G/ @# H/ j/ n( o$ u* z! R142 x. t" @$ Z# z0 R/ Y
15
1 e" H" h, g; L$ e' w' z$ R4 ~16
& u& S9 i4 i( O: o8 @6 b179 y8 n2 g( W5 ]& G; s
18# ^! o, ]# b' Y/ [/ j* Y
19' o' b. X# I0 \$ y/ [2 ~
209 A% ^6 x; n) u/ r! b: j
211 S3 X7 }' W# F2 I) m2 d, b
22
5 A" | ~7 T/ G& ~) A; `23
5 h: O5 E& {6 a; G24
. E8 ?' t- r& |7 h' `0 R3 d259 M5 s2 t5 P5 J4 `) G6 T! ^% M
26. G: E5 \5 ?7 L( @ \
27
6 n# D. @9 D/ U* e% {282 H6 W1 l/ a$ w7 u9 P) N* [& R
29/ w& D0 V$ K3 X9 K# b
30
: p1 X/ O3 m t* C31( X( r$ y! D& a. n! t+ {4 }
32
4 C/ X3 I2 @# A: K' j完整代码:
% A) F Q: ~ m( arequestAnimationFrame.js/ L( m0 o; o; P6 p
2 B5 ]' n7 `( ~9 N7 Alet lastTime = 0& {* i2 j% c& ?+ x
const prefixes = 'webkit moz ms o'.split(' ') // 各浏览器前缀- [' G+ W% _' Z8 W
7 {7 K2 v' A# _let requestAnimationFrame
2 u7 S0 R1 E/ @' l" [3 H/ \* U1 Ulet cancelAnimationFrame1 M" ?, i0 m4 u" P: O4 c
9 ]/ ~- i; V0 l' a- u) v// 判断是否是服务器环境6 _: t& G8 z. y
const isServer = typeof window === 'undefined'
; T: M, e, p) C2 t+ Iif (isServer) {
& L+ P# m$ g- A requestAnimationFrame = function () {% r9 B( u/ F. }0 Q
return+ J5 d$ @& t( o; f J
}
( l0 J! ~2 U1 v J4 x9 Z5 v @ cancelAnimationFrame = function () {
# x/ l7 ~2 R" \0 U4 s: y return2 W* ~. _, X1 N- s v8 |
}% S) y# {- S& r$ c4 p1 R
} else {1 v, P! U/ Z" K" w
requestAnimationFrame = window.requestAnimationFrame
- i$ I. c; Z2 m7 O4 I cancelAnimationFrame = window.cancelAnimationFrame. F1 ^1 K2 L { W0 `) Q9 k, H4 f
let prefix* G1 H% i. |7 a+ W& i
// 通过遍历各浏览器前缀,来得到requestAnimationFrame和cancelAnimationFrame在当前浏览器的实现形式
# h/ k4 N, W! F6 Y9 ]2 e' b for (let i = 0; i < prefixes.length; i++) {
2 {/ B, a3 Y# h, Z% r if (requestAnimationFrame && cancelAnimationFrame) { break }/ ^5 r# v" g5 d+ a. x! t2 h9 z
prefix = prefixes- W( f& i" J$ R6 t
requestAnimationFrame = requestAnimationFrame || window[prefix + 'RequestAnimationFrame']
& g6 ~' U1 e7 p( r cancelAnimationFrame = cancelAnimationFrame || window[prefix + 'CancelAnimationFrame'] || window[prefix + 'CancelRequestAnimationFrame']
' s% S4 [/ t+ p4 v# r7 l% ?+ E } l4 q9 m% f5 `9 u9 F# i
' [7 h$ q# i0 _) |2 |) F1 r( n% I" ` // 如果当前浏览器不支持requestAnimationFrame和cancelAnimationFrame,则会退到setTimeout
( S( @+ D* [+ R if (!requestAnimationFrame || !cancelAnimationFrame) {* n1 c" a1 c3 t! ^$ W* z
requestAnimationFrame = function (callback) {
8 L6 y" f! F5 x: E- T/ D2 T" _0 [ const currTime = new Date().getTime()* D" B$ ?4 l+ i4 Z9 m3 v
// 为了使setTimteout的尽可能的接近每秒60帧的效果1 M3 N# B( A- G
const timeToCall = Math.max(0, 16 - (currTime - lastTime)) m) W. q7 v! d
const id = window.setTimeout(() => {* S. c% @8 A6 z _
callback(currTime + timeToCall)
- C8 y$ c7 {" p" i' X8 ] }, timeToCall)
# T8 I4 ~. p1 Y( \3 V lastTime = currTime + timeToCall* B& E. L! D1 |7 P. T6 n9 r
return id
+ a7 Y% m2 C& G# m) \ }* T" u% c U" I
0 D. f8 |* k7 y0 t- p1 f' S" O7 R
cancelAnimationFrame = function (id) {
! D# ]1 B" k! S1 c9 y; o) o window.clearTimeout(id)
2 z* f6 x4 D0 w! s- @ }6 x' z$ G& y ?( z0 b3 ]3 L
}
( Q K2 K$ r( n4 \}
; r, b5 @9 b6 Q
5 }# y7 ~( j/ m6 G1 j4 R+ N/ W4 K5 Rexport { requestAnimationFrame, cancelAnimationFrame }
% ?& o5 B8 a c' t: r2 L
3 t/ H9 x# C2 p6 k3 j1 j- J5 N }( S7 T+ ]' d
1
1 B( b" l% ^! W) ?9 u! a( T# x1 O2
+ i" Z( [! G5 m6 k7 S3
6 X' m9 N& C$ ]! v. v4
* a# a5 s; J4 A5
" F1 \# y4 d0 ]2 c6 e. i6
: Q% U$ a1 b2 N: G5 z# p3 u7 o- p4 V& M1 B; v4 G
8
6 s* f$ d/ v: ~( y( B& ]6 g/ t9
7 U% ]4 ~- E* B5 t# k$ @10
1 e2 D# [& Z2 X5 p: F11( y# f6 `" D- k; v+ `5 e
128 p$ W; V5 X* ]5 R- L; L w
131 p/ [3 R- q, w/ `. Z9 M5 X c
14* p$ V u" _3 ^# C, w' A! A# K$ b: @
15% c9 `2 f- v. C0 z
16, U" F' `/ ~: W; h% r
17- i7 D9 t$ L# ?6 h& T! s
18
& ~8 J! m9 z4 S: F, x19# S+ j' l1 |$ K# E6 Y/ U- o
20
! R# Q1 Q. r( C3 b! @+ f/ t21
% n! r: o T2 \7 U* t4 K22
. V7 E7 l2 A1 R: l/ F23& ?. G* X6 q8 C \, I3 ?7 V
24$ B4 N( v! Z2 e. N
25) W. `. [6 c9 f8 E/ W
268 m% \) A& }1 n6 Q0 M
27
; Z! k& ?' q1 k2 `" W0 t. a7 J* q28
6 S. K5 W/ H6 i7 Y29) I X3 T4 `: Q' T$ I+ ~( }' A2 s
30* y0 f0 v7 _: h$ G
31
+ M. K6 i2 k, ^- g7 @/ Y32' b9 n8 |6 j9 O/ I, C! N0 h- q8 K+ j
337 F/ R2 x7 D" \% c8 D
34
* P h+ l$ v' l5 Q6 U354 z4 d2 l' T; O4 I4 D
36
/ r; _( g9 \$ i. V2 D4 F' [: X370 M% N9 J. Y% ~
38% S f+ T" W' u. j% N
393 @" [& g7 u2 L* k. N
40
" o2 c' Y7 d* T7 C# }! n3 t413 @# r! i w) u) r; D. C1 @& `% @" y
420 Q `$ |& v- Q8 i; r
43; A5 L, |2 L! ?5 m
44
0 U1 ?, y$ [6 [45
# `/ s4 P2 g! l/ J# R$ T" L465 J% \2 [: e5 L) C% `# g9 t" F. I
479 e4 C. }; B/ y- b; u& p! c; [
48) l" E$ m) N5 h; ]9 J
CountTo.vue组件思路! z+ \' n' _6 K: s
首先引入requestAnimationFrame.js,使用requestAnimationFrame方法接受count函数,还需要格式化数字,进行正则表达式转换,返回我们想要的数据格式。
+ C4 g/ D& n& q; M/ ]7 P6 W' e: }' T8 K. q0 z& V
引入 import { requestAnimationFrame, cancelAnimationFrame } from './requestAnimationFrame.js'
: c+ R) }) p- h5 m1
4 y) l! p6 J n/ W5 w: m3 P5 A& d需要接受的参数:2 D: Y, [ c7 m5 ^6 H; {: F
Y8 B+ C' B+ u/ |
const props = defineProps({" \* \) d, H3 H8 z
start: {7 o8 E$ \/ M4 z! V
type: Number, E) _5 E. Z. e& @) B" [. S+ M: m
required: false,
5 |* e5 E2 r3 @( } @ default: 0
( F& O1 ?3 P' x# J; A0 j8 } },
) \. V+ t- ~/ l! Q F8 ^9 i end: {5 ^: L# G8 t3 n' j7 h! }) B1 `' B# o
type: Number,
1 b4 K% ^6 d0 K( ^* [- r; j required: false,6 o }% j8 B: J$ D6 _4 k5 \+ x! l
default: 02 J* [+ E& e0 m2 {& r
},
+ |, X* j* [1 e duration: {! O4 C6 ^, s( }) ]& D0 X' J( t
type: Number,
0 R1 P& U' n( l7 Z/ {, I# S required: false,1 q6 _) V p1 E5 o
default: 5000
$ z. o8 \9 @3 ~. J& p },0 |8 ]. l6 y3 k |5 b6 s( K6 F$ b
autoPlay: {; [' e" ?1 n1 C* |/ d4 O
type: Boolean,4 n2 b @2 j7 C) \
required: false,1 A9 r, H p; H$ I3 R. {: V5 }
default: true
e. M- E2 g: D },
) h6 i* p1 y( s; X decimals: {5 Z- r" ]/ k7 S! ~5 ?1 R
type: Number,
0 X& G9 [$ M' Q3 g9 _. H: R: F required: false,
6 M$ }+ h+ N; m: o* y% \ default: 0,
. Q% h* e3 x! [+ J% y validator (value) {# f6 D. a9 o( v/ W% O/ U
return value >= 06 T6 D2 ^# F5 c' l! H5 z9 G+ P
}# T6 N" V3 f" j
},
- x& b8 G5 l' a decimal: {
' ~7 Q# z" O! P3 ` type: String,
( I3 D" J7 Z% m$ h$ m required: false,6 L0 s. h6 S4 O" \* j' C$ e
default: '.'' T/ s, z( c4 K' @: ?3 m
},
0 E9 G3 @& U- [* N& K* \( y# ^7 ] separator: {
- X9 t2 t. `0 w$ s4 y# S9 o type: String,
& @3 r) `/ ?0 R7 a required: false,- K9 Q* X7 ?9 z: @( p% B4 H) {; [7 i
default: ','
% J3 K& C) p4 x+ I+ A. \' T },
' w. f9 L. r3 t) X! h+ v: {8 g prefix: {
* K, S" Q# s) S+ X: b type: String,* y, H `* ?0 S0 U* S9 B
required: false,
( C: N0 V( ~! W# u0 ]2 u6 F default: ''' f. R% G* A1 z7 ]+ o: c
},$ Z) B5 H* t( ~3 L- {
suffix: {
* s+ ~, q; Z+ M: Z) L type: String,6 f5 Y- E x) X
required: false,# Z/ N& Y5 s0 r: o# H! K4 K% z* H$ s
default: ''
3 z6 L; N1 q& u. N },. T" I: w) a- f3 q0 r% I$ U
useEasing: {
( U$ r @$ M; ?6 m" ^9 G; }9 b type: Boolean,8 G; e, Y4 ?; L- M4 Q# L
required: false,, k- Y$ T7 O! I' M
default: true
0 A. ]' `0 {6 H% K' ] b },
8 {9 v7 _2 c% _7 r( ] easingFn: {
( {: x% E) t4 d( k; V7 M. W3 f type: Function,
b( f: O" Y7 D5 T; r default(t, b, c, d) {
# e# D1 k- q. b; U: M$ K return c * (-Math.pow(2, -10 * t / d) + 1) * 1024 / 1023 + b;6 h5 N# o2 B' \) I/ m# G
}
( L/ |, S' F( V- O/ M. X }
* f9 y x* b3 E" h/ ~+ H2 J})
* t4 T1 O \% O6 H* K3 i8 ~' k2 c# C0 c7 p, U
- u! ?; r/ {, o" `7 K' i/ i1( K+ ~# U' @" M# q
2) q Z3 S& S2 l' K6 @1 t* L; R
3% K" n. H/ m6 ?' u5 l/ l. f
4" `1 g6 D: Y6 l) g) \
5
; z9 C# i0 M4 \$ U8 J: B5 O1 u0 U6
5 |: B, r2 f9 L/ {# P7# q- Z8 Q4 [( U2 g
8
" d2 [; @7 K& T9
% M: \+ S7 ?7 f1 O4 ]. _10
2 J" ?& W: h; G5 p" q114 [2 I( ? B, H7 Y
126 b2 r- _; m7 n4 h G7 t; e8 F
13
$ h, L) {' H# T; m14
+ y: m: J: S9 n1 p9 \& Q, E15/ q* m2 ]/ L! V
16
3 c' p' V! t% Z/ K17/ n* C% O7 k; Y. s0 i0 W
18
9 k. s3 C& O# ~" T( c19
$ `1 ?4 u+ Y4 K0 c/ K3 t4 o20) F! L' S( ?* L6 i3 [ M
21+ p3 ^; z. V0 m4 ?) p
22- k9 u5 m: X0 o M+ ^+ ] x5 v2 w
23
0 f+ ?; x# H+ l9 v6 f; j# {- B241 k/ }6 h8 k" L. a8 c c
25
5 ~& L& @/ R) c! ?2 D26
s* n& c4 {* a. e8 Y+ @; b' Q" m( `27
e# x' e( j+ j' ^. P28
# w ]- ?, W/ Y/ |29
+ u6 {; H* {) u! [30
+ t. f c: D# `5 h2 \. }0 G! f31
' T$ s# c/ L7 J: l0 o6 V0 H' r; E. }8 S32% O0 Z( N4 I- v3 P
33" X# }: K& T. N% F: H+ D1 w
34( ]$ I' s4 U! N- q
354 j1 h: P! V f9 s* @* |* o& a
367 M, s8 X; `1 y. p; i/ ~
37+ B( |( K* h% r% E* p; r* v
38
7 ^. ]4 W. [. i6 h% a3 x- ^39: S0 {' Y2 n# U! |
40
3 e# c* E* |( v) T9 {5 A2 `419 p1 O7 h+ _; P: H& ^4 ]. [
42
& G' G$ k; g$ u4 W4 }43+ J! x: x1 I! P
44; Y2 @9 ~/ y+ [* E( D- O1 r$ v
45
: G' N4 Z1 X# {/ u, ^46! Z$ L5 i# t" E0 f3 |* s7 C
475 p+ D5 j3 @ A0 T2 Y
48
3 U1 Q+ F; t4 x/ E49
% M9 l# k+ v L. s0 l50+ h7 B7 W! q; k4 l; t8 _# X
51& z) M' ~+ ]4 `1 M! l0 o# x
52
: `7 k& o5 u& }& _; c536 l9 B$ x' Z1 O) w* ?5 h1 x
54
/ q5 e8 z, y1 s559 w! L1 a# Q! l. r) V1 Q
56
4 h9 u7 t' j1 b( O# P# C57
2 B( s- _+ O: a* c U" g. H( b58, j+ x8 [7 l- T, `# W
59) Y! @2 t2 I! I) g, ~5 V
604 u- P! D9 Z7 x' X" F
61. v- d+ j" C+ D7 W+ l
62
; t+ ~ A" J0 o启动数字动效: N1 q1 g# Z# y3 B. t8 x8 q/ w
, ^- _' b% P- Aconst startCount = () => {
4 E, G/ n' j2 d; k% M- D* _ state.localStart = props.start
7 C6 x' k0 F" ~6 T9 n1 ^9 J$ B state.startTime = null' R% s0 r. M0 ~ _
state.localDuration = props.duration A, O* N1 _& m7 S
state.paused = false
7 d2 b I+ u4 C6 h state.rAF = requestAnimationFrame(count)
9 K' q; @7 C0 C t1 p- L}
1 x" q* `; M" L- V5 D1
1 P) y( e$ V: _0 o$ ]& M& y26 [4 V$ K* K, h) U) i0 x
3
0 C: m I. p" f3 r4& ^" a$ e- |; Q' d1 `
51 l/ O6 I( b [' L3 r) H
6
1 F- s1 k- s" n8 S K7* ~4 U7 W$ j5 x$ H4 m1 f2 E/ E( f
核心函数,对数字进行转动* j' h+ }$ ]; d$ O7 K2 c5 a
$ k9 Y' q. J# e& x1 I5 F
if (!state.startTime) state.startTime = timestamp+ w; F8 C9 Y+ O8 j1 x3 B
state.timestamp = timestamp
& e$ }8 _7 k5 ^( K) {* w0 A const progress = timestamp - state.startTime: z- }+ Z9 q' I3 r0 T5 w
state.remaining = state.localDuration - progress
- r$ b1 x/ k$ z4 x* b // 是否使用速度变化曲线
8 n) J7 c8 N8 X9 Z) t$ b if (props.useEasing) {9 m. b, U1 h! o1 e( G, a
if (stopCount.value) {
8 N, k7 G9 U" a& Z2 n state.printVal = state.localStart - props.easingFn(progress, 0, state.localStart - props.end, state.localDuration)6 p% Z# T: S! w8 U# d3 R
} else {' T. ?( |3 t, E4 \% z0 |
state.printVal = props.easingFn(progress, state.localStart, props.end - state.localStart, state.localDuration)
9 A4 M' ]5 k q6 s2 d& G }
: L6 @3 C8 ?, ^: h* V4 @! e9 i0 E4 R } else {. j% l' |1 U* w* I+ p
if (stopCount.value) {
) A8 c$ ?# f( W. ~0 d; v+ M state.printVal = state.localStart - ((state.localStart - props.end) * (progress / state.localDuration))) j t5 A( F9 b ~
} else {! g. d' j+ n( c# {, |5 R
state.printVal = state.localStart + (props.end - state.localStart) * (progress / state.localDuration)
6 Q0 L3 J' J7 w' b8 s }1 x3 u, P6 o/ [+ ~' ^# z' U
}, ]8 @& e9 _- v4 B
if (stopCount.value) {
& m+ Q5 v* o; w3 N! a! l$ v3 X state.printVal = state.printVal < props.end ? props.end : state.printVal; A M; G' |: a' K- d
} else {- @/ d; M4 a N( r! s9 f: Y
state.printVal = state.printVal > props.end ? props.end : state.printVal p2 e( @' f7 @2 B. Y* H' [
}
( |# K f) g C5 I
$ w. }& _4 B- v( `, u# t state.displayValue = formatNumber(state.printVal) p5 a s/ q1 v* {, ?, c
if (progress < state.localDuration) {1 c! Y T$ E7 h5 k* N* G, O
state.rAF = requestAnimationFrame(count)
, ] n. `) K) v5 @: d } else {& z2 E1 K4 k/ Q, [5 k. }
emits('callback')# C+ E; f; h A% {
}7 }; [) v9 Z1 u' V
}2 ~& r' N0 x5 B2 ~* U
. E* r0 F) s6 C* p2 H n4 }& ^! L S# z9 R9 M7 G' y
// 格式化数据,返回想要展示的数据格式: Q$ U- ?, T5 C+ o1 m
const formatNumber = (val) => {0 u4 k" k! o g# [! q* a4 l
val = val.toFixed(props.default)
- v8 h( y( j4 L) B2 x val += ''
% z1 w. y* R5 v5 q0 ]* H* ?% ~ const x = val.split('.'): x% {8 n: t+ P6 k- r6 n' {
let x1 = x[0]
% X% b& g/ P3 Y! i3 V const x2 = x.length > 1 ? props.decimal + x[1] : ''
( N5 z- s6 w' U& t const rgx = /(\d+)(\d{3})/
2 ^8 o7 w, }" X/ p0 L& F' _ if (props.separator && !isNumber(props.separator)) {. u( @# S# {& j3 J3 d6 k
while (rgx.test(x1)) {
' s# r, v7 g. A: M9 N x1 = x1.replace(rgx, '$1' + props.separator + '$2')& R% ^) |! l* l4 `' P8 o
}2 ]- f$ F% F5 y( z2 x( g
}
# t3 A; b" O' O1 i+ O return props.prefix + x1 + x2 + props.suffix
# r! o4 r0 k6 U6 i8 d}
( ?$ O+ |( H; Y: R# U* v7 w+ J) U, B% }. K
1
: v1 L: y6 q+ c* c0 a23 ]3 H. w# h. Z& a) Z2 j+ a* L
3
' A% s7 D/ J0 Y4& S* D2 w3 Q: H, Q# w7 y- H, q
5" w& |5 M7 [, ~
6
# }# y# `/ w4 ?7! p t) b8 }* {) ~
84 E5 B" {6 a5 ?: e2 x
9
: F" ~% ~* _6 Q9 c R10: h2 V2 M+ N% Z* ^
11" ~; G8 m; V& N2 k! d
12# e1 Y; d3 a0 B- U4 K$ I, x
13
6 b) L X' q0 p2 E: U4 P# y14
/ d x4 x1 ]8 q) A8 R15( o/ S; d' ~& S2 Q* I1 f3 N! d
16
: Y" j+ n8 d4 J% A% T17
8 v. K3 b) A1 ?# k18. R) C3 s6 d9 D$ a0 k
19
, W& h8 b0 ~2 F# g7 U20# r4 Y4 `5 a& Q5 I) Z* t6 Z
21
, n6 i" u* R h- D- |3 V2 Z226 j: ~. \- |. t) j( O# I
23
; \ F5 M. y3 x24
0 G6 [- ?6 z8 K$ ?25# J* P x( d, m5 |- O
26
& N% i. K# a8 o! d27
% X0 L* K5 M) ~; \28& i; j: A, G0 _
29
X) x1 J' @' ]* B30% e- V" G. |, l7 n8 o
31
1 I- B0 n+ y5 A, O1 [& N3 c% D32
: @ m* C# f J6 p1 q7 v33
/ L! q/ L% I9 Y5 N1 |8 G) L34
8 U8 E( ]% A/ _35
1 V0 M0 X+ |5 `/ j3 ~36
, H5 ~7 c6 [# o. \4 S( ?4 s. o37$ ?; W0 {" P6 W1 l" ?
38
3 L# u" V; u1 H" J: X O39
, l! _) ~8 p, ?! ] K40
; ~) U [0 U. [. Y- T c& C41
' e/ R2 Q% |5 W4 m( M( c2 B+ G1 e42: U8 a O3 u1 M% m
43# `) g( |' Q2 X
44/ s$ Y! A6 M4 L( b1 D4 A
45
6 i0 T. E b' M3 q& t46) r1 U, G/ k) g, s$ f: u
479 [1 Y. N* [: E& Z; x: L
48/ |; J) I6 z) @: V+ l, a' F
取消动效
# z) Z8 k7 j" L1 w; o# O/ O1 e' c. s7 x+ O r* n% Z
// 组件销毁时取消动画
4 X9 S6 P3 X, N9 n3 P/ [onUnmounted(() => {
/ K. z, P! \9 L V5 S* W9 g! B cancelAnimationFrame(state.rAF)+ L5 C4 y& L, m6 m" V
})# J1 R* P9 R3 B
1
4 ^, j+ x0 V9 h, i$ n0 d! e! ^( }: i2 y2
, a4 Q2 B/ D" T, {3 e3 a! Y0 R1 ~3, D. d- O. m& J- |: E4 O* o
47 d5 P" \; B; P- D. }4 O+ ~
完整代码
; j7 Z' h& R: g H7 L
8 T$ d6 t3 @( P( ?) c" n<template>5 F8 |+ P4 P. U Q2 u
{{ state.displayValue }}% `9 p& H4 m/ l& W2 l/ ]$ f
</template>
5 ]$ T9 F) c+ h4 [ j5 U6 C% g- e a1 F4 D0 E
<script setup> // vue3.2新的语法糖, 编写代码更加简洁高效6 \5 P. e" }# ^3 @2 O& \
import { onMounted, onUnmounted, reactive } from "@vue/runtime-core";
8 M# z7 T5 Q; Q; a* O1 \import { watch, computed } from 'vue';! u" j: x3 k6 h, ^
import { requestAnimationFrame, cancelAnimationFrame } from './requestAnimationFrame.js'
L0 R; R) H7 v4 q// 定义父组件传递的参数% X$ c. e5 z+ p5 Q( P# F4 h
const props = defineProps({' H3 f3 n* f B1 U1 m& D
start: {7 H# \/ K9 Y% a# `6 r5 S
type: Number,. a' A7 S. S3 N; Y6 o0 ?* Y
required: false,
; P l8 H q1 D* G( q. [% V3 P default: 0
: ]5 `, S- L2 z! P },
, d, _/ ^5 M7 ^ end: {
8 }/ M, J0 ]2 W, ? type: Number,
, m: C; V9 i8 Q, Q3 p; z4 b0 X required: false,
" g0 n. f+ _) D# x& w default: 0
7 b1 o4 ?) ~. m1 B' J+ Z2 @- T5 X },
$ _: w6 m+ o, ]# j duration: { X/ T# G5 I/ n8 Q6 e3 d
type: Number,
! m7 Y. S' X2 B& G, [ required: false,
1 p- W1 {, x' {/ k0 R) ]3 F default: 5000
$ g. o& W# a' M' d' C* S },- }# e/ Y% J) k! r! G. |
autoPlay: {
j1 D! H6 a+ }& Z$ K type: Boolean,& x Y+ J: t! `* l% c( }) Z
required: false,+ Y) l0 A% F' W+ R/ O
default: true3 x, g2 b7 q" r; y8 Z1 M. o
},
Y) G1 }8 F6 V' _ decimals: {
8 x5 q' R; p+ e3 r8 C( h type: Number,
|7 U5 U! [5 D* a required: false,( R( e' b2 c5 A" Z* ^2 b, O, B
default: 0,
: D1 F5 I- X6 d0 t* @ validator (value) {" s2 M: ?; O% Q: l2 S2 A
return value >= 0, k9 m+ `9 l+ K# q- q3 a
}
' t/ {! a- A7 v+ b# H N },
: }/ x2 n3 S* _* u0 }& w decimal: {
0 y( l1 }5 Q& r H; Z; x) z$ _ type: String,
0 b6 }- m ?5 s* W8 F+ ^. m required: false,
2 ^$ A: F# W& d6 U% Y: w default: '.'
) e# u) x" f" D; l5 w },
7 }8 l1 D2 t$ l9 U* M3 L# r' y separator: {1 g* G8 S/ c8 q& X
type: String,/ A( u/ ` x; d6 h; U+ N
required: false,( a; T% u$ ^% o7 x5 v3 _
default: ','
2 ^3 n F) V5 z; p! G },6 n1 |% o Y3 x8 m+ B
prefix: {
# ^0 p0 H, b4 h( f type: String,: H* f4 l' _7 O* ~2 s$ d8 s- i/ y
required: false,
: F0 \# o5 A; l) \ default: ''3 ]( ^* H% Q; N3 a$ [5 H
},
8 `+ \; `( B2 e8 @% c! V suffix: {' E9 K; R- `. ^1 Q. [8 V' h
type: String,
- t$ U5 ?5 |% Y1 n required: false,
( f, O+ x3 ?. c# j. k; A% f default: ''
: J, x/ U5 Q- H1 g7 C+ ]* Z },
3 J9 n% }+ a9 V4 U2 M# \( ]' l useEasing: {
' g' B; T4 W) J) \9 N type: Boolean,
) C7 Y9 ]# x) A/ P5 o z required: false,2 x' u& l0 _* @
default: true8 y F7 B4 `2 ]- M3 G5 B4 B
},# Y) \' U4 }2 b0 ?$ {% L5 }
easingFn: {5 J' {! s, o W; n1 |
type: Function,
: E" Y2 }% I( ~( p: ?$ y4 D; F default(t, b, c, d) {8 J8 b+ |' ^1 f$ j( G
return c * (-Math.pow(2, -10 * t / d) + 1) * 1024 / 1023 + b;
( l7 E$ ~( Q# H# d+ y5 ` }
3 V" ^0 k' B( r6 h F }
. r6 m5 Z# {5 g7 V})
5 |0 y8 U* h8 T, w% ~$ \
. q e! L% g$ f- \const isNumber = (val) => {' g8 ?! r# j" A% A
return !isNaN(parseFloat(val))9 ]3 A) e9 w& z- D& A
}
; F# @9 y: q2 C# q2 s3 |( D2 `# v0 q; W) W* k% t" u
// 格式化数据,返回想要展示的数据格式( i5 q# t; P. ?
const formatNumber = (val) => {: `' i% `7 D/ R# m- P3 E% z$ I: n
val = val.toFixed(props.default)
# A2 }& h, H" M val += ''
9 _8 ?# Z. A. X const x = val.split('.')
7 M3 b$ Y/ }- \; G( h let x1 = x[0]- d+ m, ^0 v7 G" m7 p
const x2 = x.length > 1 ? props.decimal + x[1] : ''5 M. v( t F, n6 L
const rgx = /(\d+)(\d{3})/
6 K" e0 C2 M5 m, e* l6 G+ T if (props.separator && !isNumber(props.separator)) {
' X/ M- N0 V: { while (rgx.test(x1)) {" S! M* T v7 c8 G$ z
x1 = x1.replace(rgx, '$1' + props.separator + '$2')% n Q! J; A% B# y0 e/ \! I3 V
}
" g) t x5 C* p# `8 i; v }/ C9 i% y; x& Z6 |# ^. \; q8 d+ Q
return props.prefix + x1 + x2 + props.suffix
2 p+ ?3 \* l8 O- S' V5 N% n; j}
) |% h5 q9 K. g' @# H$ G9 }+ \2 r3 N' e& M) n
// 相当于vue2中的data中所定义的变量部分
& E7 y3 a0 t2 v( e, V% Iconst state = reactive({ h3 s+ T, `# X0 j6 K0 n
localStart: props.start,, Y& Q% d; s8 Y
displayValue: formatNumber(props.start),
: }2 X$ C9 {3 N p3 y' V printVal: null,
& q3 U! f. j5 o paused: false,
" \$ T1 D$ M& O# r localDuration: props.duration,; ]0 i: I8 y2 p8 B# s9 \. R5 K
startTime: null,. o9 P5 A* N. v3 n1 w1 L3 n
timestamp: null,1 m2 ~8 \7 [6 `3 H' r
remaining: null,6 e* l2 V( `4 O3 T% U, y) k3 |
rAF: null
8 {" D% \( n+ q+ v: T})
! {3 `. X! [, t/ i* | ^2 K& ~2 q1 V, @3 Y3 B
// 定义一个计算属性,当开始数字大于结束数字时返回true+ V9 G8 P/ h" s+ _9 N
const stopCount = computed(() => {# w, Q7 n7 e3 e6 Q$ ?. S$ f( w
return props.start > props.end
. e6 i$ ^. b5 G6 X* y})
. b2 Y8 n, \1 C( [9 H// 定义父组件的自定义事件,子组件以触发父组件的自定义事件+ A3 P/ q* M5 N6 m
const emits = defineEmits(['onMountedcallback', 'callback'])
0 Q8 {3 Z3 y0 p' l4 c- ^0 D
4 N% n( V& L5 }+ X2 uconst startCount = () => { e& d1 \& O& i9 v, l
state.localStart = props.start
2 F# W8 i) T; y) \1 |( [# {3 @ state.startTime = null# x p! d. s7 c3 |" ~- [& N/ k6 h
state.localDuration = props.duration
/ z+ t. W' J5 b state.paused = false
6 {, Y" n% e& F state.rAF = requestAnimationFrame(count)5 ?: G7 ~: D9 y
}
9 B! c( W/ `% B( |# a2 J" H0 c* s
. W6 T: ~$ a! t0 D* pwatch(() => props.start, () => {
2 A3 l9 R! q7 u" Q6 l, X if (props.autoPlay) {
! H. u: }5 ~1 z* J3 n startCount()
3 @; K% ~& T/ U- l( K4 u+ d }
; D- ~% `# v) |6 a$ U& c% P})) o# X5 s# I7 M; I
6 F5 ?) H/ n( L; P+ n
watch(() => props.end, () => {
! O5 T9 q& S6 @; Y9 Q if (props.autoPlay) {
# j/ T3 m8 z: T0 q; \' e, Y startCount()/ G8 Q( K) P5 @$ |0 A) U+ H+ C
}; d! |* R' l: d
})$ @' a" n0 x$ w2 z" ]# C( l
// dom挂在完成后执行一些操作- \8 @* f9 ] ^. ^9 R" Z2 }
onMounted(() => {5 H) [7 {$ [$ A7 i( I9 U
if (props.autoPlay) {
' s- s; `5 ?7 l startCount()
( W1 z' U: {, L5 `" X }- W! p6 S2 b R' B% [& g* l3 Q
emits('onMountedcallback')
' |+ G3 i/ {% c" A; M- x- K})
. W! x: `' z4 t// 暂停计数( j. _. G( t- m z
const pause = () => {( d; Y5 M9 h% n/ @5 X/ c* `
cancelAnimationFrame(state.rAF)
$ g- Q# m* K {# A1 \( ~}2 ]5 A, o8 s6 n( j) \4 A6 n
// 恢复计数3 {. z6 \8 b' W
const resume = () => {* M" _% Q1 [ p
state.startTime = null
' G7 v0 `4 d! u$ Y+ \ state.localDuration = +state.remaining# D6 Y' }0 W7 B
state.localStart = +state.printVal8 q' _; b: x5 V, q& k
requestAnimationFrame(count)4 E# h' F. M1 K' f
}; z# K: M7 g; A2 E" a3 W2 | o) X
* `8 x# _! f* D# n
const pauseResume = () => {7 z& `( ?5 D2 O2 B
if (state.paused) {
7 J( \/ y; e9 g, p1 `8 I+ d; a7 \ resume()
; A; D5 g# O5 ]$ Y1 ]/ C+ Q4 y state.paused = false1 C! q7 f; `4 _8 u
} else {+ O* \3 o9 T4 Q0 ?
pause()
2 x: `: @9 P9 ]4 C) o state.paused = true% j3 q9 ^5 V* m9 Q
}/ z/ M9 V: j, y" r7 S
} L3 {: Q3 O6 u7 j" J' q' I
+ f. T, W! a+ d* F$ ]const reset = () => {3 k! _1 q! ]7 ?6 Q" @$ d
state.startTime = null
& f g' k3 E ?1 Y- } cancelAnimationFrame(state.rAF)
; [ c. g' H3 f- g state.displayValue = formatNumber(props.start)/ e' u5 C& l5 ]! K8 A, ~1 X
}4 ^0 v2 v! o0 ?% _- C' O
# i* o8 K% p/ c: Sconst count = (timestamp) => {
B* x! q; Y$ N) z: @. n! P9 x% X& q if (!state.startTime) state.startTime = timestamp
- g( S8 U: a1 d5 r) ~$ f state.timestamp = timestamp/ W' p6 W4 K& w7 w! r; ?
const progress = timestamp - state.startTime% L7 t1 R9 v% G& {" C8 ^
state.remaining = state.localDuration - progress; @$ q; s5 c- A- a5 i0 z. m& @% C
// 是否使用速度变化曲线
3 [; }) ]) Y* T6 d0 P$ r if (props.useEasing) {) R7 ~1 ?5 P" Z
if (stopCount.value) {
) |/ o0 f# n9 {8 Z2 e9 C state.printVal = state.localStart - props.easingFn(progress, 0, state.localStart - props.end, state.localDuration)+ c, a6 Q% w8 d
} else {( R2 w; S: Y, F' p& w& d# D3 p
state.printVal = props.easingFn(progress, state.localStart, props.end - state.localStart, state.localDuration)
9 f2 u% A$ |9 s4 w5 w }5 w6 t+ S ^& i0 O: j |
} else {
8 s! h. Y4 F1 @9 C if (stopCount.value) {
1 y: {( X# j* R state.printVal = state.localStart - ((state.localStart - props.end) * (progress / state.localDuration))
. l t8 i6 a% P K% y E2 h9 o/ P } else {4 ?& Y5 p% F) D( J0 G
state.printVal = state.localStart + (props.end - state.localStart) * (progress / state.localDuration)
. Z; b Z$ N: T3 q8 t& B }
- {4 U8 m( [9 d( V# e% | }
6 Q; J1 X, X& S! Q. D8 T- I$ g if (stopCount.value) {
; D% b, h, p6 V1 I1 X i& N2 K state.printVal = state.printVal < props.end ? props.end : state.printVal1 {- N4 k! S8 V y8 ?
} else {
* H: J/ p1 @) {2 X3 q5 l5 K) m state.printVal = state.printVal > props.end ? props.end : state.printVal N$ w4 G `/ I" q9 |
}! f' |1 F1 C5 {$ h1 t
8 E( {# o7 P! r) f0 i) O9 K" D' d state.displayValue = formatNumber(state.printVal)
$ G2 a( q! \% I& Z6 B if (progress < state.localDuration) {3 u" _& [4 s% \0 Y
state.rAF = requestAnimationFrame(count)( ]7 r$ _6 J- E! R' v3 v7 |1 X
} else {
. A E4 t" N/ ]6 P emits('callback'). |7 `, s" ]1 l7 R- r ^
}
' w- ~! F( H3 z3 T7 d. I}: k7 O% G, p# @: N0 L# a0 _" a7 d
// 组件销毁时取消动画 w, q8 K: a# ^3 B. k
onUnmounted(() => {. K7 r0 _) `) J& f( ?7 p
cancelAnimationFrame(state.rAF)
7 L/ ]( s$ p6 p. j8 J/ S! T})
9 G) B1 g S! c</script>6 A# k4 J" u0 b
0 e! J4 v& O3 {6 D5 U# c
1. ]1 K. }) U; F; h7 j# a
2
8 O* }) K8 D; S& {* g7 ^33 r- H3 o% ^) Z# v
4
1 \( Z; _' I Y8 ~5
) O s$ q( ~6 n1 j, K& f$ w0 b4 s2 L68 ?' L% g5 A7 u& F. o+ S+ D5 h1 ]
7) {6 X* K$ Z# w& I K# }( q
8
! ?% m% y, h7 h7 z/ h y9 l0 g# j6 ]6 {1 r" F1 m$ H* n+ l
10' H1 Y+ \4 d# B, _
11
/ h& d( \* w! c12
/ ^, d3 I* T! i G& _7 x13. i" c9 P7 H$ {# Y2 [) Z/ \. E
14 @8 p% d) t' F2 ~
156 G& N9 u7 w6 ]1 w. U$ R# w( X8 G
16" }/ ~1 p/ [! o$ i% q; N
17+ E( @ R( L3 J5 y/ w7 f7 s
18
D* d& T R. o5 g199 {& n) I6 Z% {: p! K! b) Y& r5 n
209 r. Z) o1 m# M
212 d f! [6 b m6 F6 g+ F6 _# r/ S
22& F( Z9 j$ N$ `- b5 b8 r/ \
23, A' O7 p5 ^( I* w' `2 M! x
24
* |4 \6 _% O- \" _6 s x1 ]( B( t25
/ F% T2 y9 j1 H$ t26
( q4 R( t" H' s6 {# E274 Q3 Y6 U2 J* I6 ?0 w
28' Y: ?) Q/ @+ c) L% F& c
29: e3 j$ T0 `6 r* F$ l
30
( L+ q6 n# w5 \) Y4 t& H31
9 ~+ h/ K) i0 u$ u- A3 y/ H32
x5 d9 b" u2 v9 X% d1 ?) J33 M5 o/ _6 I, D; z
349 M6 R, ?' _% R, T! s
35: x4 O' Q, M" Q6 ]1 k" r- {3 `
36, r$ s( T: `; F! H& H
373 `' k0 h. g3 N6 T
389 `! } b7 [0 d! c* d
39 K5 d( E/ v$ C8 s
40/ d1 q# _) d3 f4 [( l! i9 F. r
41" G2 w5 l' ^/ ]( t% L: z9 z8 h, l
427 K8 }7 ~1 W0 I& M9 e. M
43
: G0 J ^: @; P/ G44
# p# a* a2 x8 S! D45
3 L: l9 y% Y. m. z/ R. B46' W1 O! S4 m, L+ y1 _ d" d
47, `' {' x! a# N5 l
481 |8 y* Z1 y! }) v. {
49
8 R2 R2 _; v Y50. w- e2 Y$ }) Z- U
51, o0 q2 }% i! @3 N+ e3 X
52
% {- V: K1 f: F" K1 J6 }# m532 r' W& l W2 X3 e
54
2 p. |8 O, j/ ^ D. K9 o55+ Q7 Y2 G8 u; F, n' g
56
7 b8 o9 _. B D! }571 i- t" i. M; \; D
58
6 O" E: n1 I* n5 V9 A4 T6 z# _591 c2 m% _8 f4 g
60+ M3 l& R! o8 u5 k
61
$ L- _( u* ^2 Q% q. K62. b" y S1 y. a7 r) K B- q) C
63: [/ \4 `8 d; E0 r
64& n* M4 D$ H) X3 s7 @$ M" j9 |
65! A4 S9 E: L% ^4 X
66
1 t* Y3 g5 v2 T' j, Q3 e8 W) }675 `* _1 p7 F1 B% u
68
# _# J5 E( k; m# k! w! q( W3 `69, Q/ F! |) Z T* A
70
% J3 p1 ~# M( I1 k ^; {710 i. }0 |0 J, E
72
) w0 b" _$ `5 j$ T73
$ |+ S ~9 U% }" Z) B74
; \( w4 d: r4 A" H J750 U- Y# M# w/ P8 O- |7 z/ Z: d
760 G8 U* ~ G; l Y! P7 G0 G
779 s, K+ R8 f8 U
78
# `+ h" ]* x* E' l$ n79
/ W; r( J+ y' q5 h# P4 n: z80
" ~3 S) _) M: g81
7 v5 t5 V& f: Y& F9 f8 n82
: T' S& _7 F! c- M2 u834 q# X: @. G- Z3 \/ p
84
; i9 |) v; P i) ^) }85
6 x( C5 Z: o( z3 F0 i9 D7 D- x865 F# V7 k( c3 e2 x% \2 m
87# Y8 R( ]6 D- L; T3 w8 V
88
+ }) C7 @* S9 ?- d0 |89, Q W" ^) ?* H& [% I! O2 {
90
2 T1 W& S, z; ~4 J9 }6 D5 R91
) e% y$ [8 ]0 E) o9 I4 x92
2 w/ p4 F% y+ x) D; z9 Z9 h93' A( g( P5 S# l/ W* g* C
94
7 I, y+ g& d' K95
" k. r% b" R0 A/ ?) N- S966 ]: c/ N1 z% y# G! ^8 \2 m0 q
970 N3 A2 G/ c& Q& Q9 k) N4 t
984 y( i2 m- V, ]& O- o4 r. m% p4 F
99
4 S$ Y3 u" W8 A4 G# ~2 q9 ~100
3 o0 w3 F1 t: G ^/ o5 @1015 ~9 Y( b$ _8 t+ e6 Y% {
102. Z. p$ w C" E
1030 y' v* E% F5 r5 f' f2 k0 ^* v6 p
104" B) |) j8 ?; _9 @- n! c2 l
105+ u- A# T7 n( h, {
106
$ g3 { w, Y ~* d6 ^107
5 O) d/ H; O: `- s6 V$ M108
+ D: V% m& u* p" p! T) ^109
: Q% n- h) Z% N! e' K4 d8 S& I110
5 \* B' i1 h: q6 ?111
4 Y9 W' B! {9 y6 b112
+ s; P! l% M# |& P6 F" M# U113, Z' `& `! O# m5 s
114
_1 A, Z6 g1 E' `3 x115
% H( c- v& `* Y& o1165 f3 l. O+ a* B4 [0 ~7 h
117- {! r- q# g7 o5 C% r
118
% U" v" [. W- v1197 J/ y+ i+ O8 o) X Z
120& g6 V' h$ ?& ?' z
121
3 M G* `4 ?4 u7 l6 H3 h122
2 Z5 f' g/ f4 o" k: {123
: o. _; j" M: F$ C$ @1 `124, e" h8 H( h* q& I- Y) r7 k" v
125
- {+ _- g, l+ b# g5 `126
/ l2 ]5 W7 i# h6 T127* m, n' L" N6 F% i2 M
128* d, z- p$ ^; F5 U9 ?
129
7 t% t% R0 q0 ? i( J. s' u130) Z# X* ?- a2 h; B. i
131& J* x2 z8 c6 ^3 [' i
132
, E* a. h3 q7 A: L. c: ?+ s. {133
8 w. F, Y3 W6 U- X7 L3 F7 n134
3 D y8 h3 ^+ h, n2 l! O5 f1 H1356 d+ n0 W1 M, s. Y4 @" j& q
136
! p5 o3 K* b% V' \! E2 W0 f+ T i137$ A2 T5 c- ?5 x* [
138! i0 R& F) n, Z' X
139
& V$ a* u/ P9 X1 [; }: x140
: ^, M1 i7 P- k5 D2 h141: n# U5 r" x" T7 r
142
+ {. s! ^, s$ w9 m( R" l143: P0 x* ^8 ^ k" u! M) \; x
144! p2 J% j$ H; @3 k& y3 t! i8 h
145
5 F6 R$ F' \6 ~' o& S146
5 S- z- }( f+ x% N7 N1 o147
`1 r' L0 W# c, d7 ]6 M148
9 J( p, ~+ h2 J" r1 C149' ^6 [- g5 I q* A
1505 t/ v+ K3 u; F; g, T
1510 M" A5 }# S& ^ Y) ^! @" D5 u
1523 {) B1 n2 m% |1 Y! g
153
8 y# W) P! P1 N; j6 Y4 ]( E0 M- k# K1541 Q* m8 \3 Z8 L
155) F0 f9 C. n# u+ a
156# I' ~' }) E7 b1 x" i+ L
157
/ O; s4 o0 V, i& ~3 \' w$ J( z158
# k7 h8 @' P8 S4 b159+ w( p. C$ m# z: I$ ~7 A
160
, P0 P- w1 S% v3 X161% B8 L3 I: d2 g
162
) D/ ^ Z8 N+ N2 p: A* R& r163
4 ?8 y, c9 x2 N: |1643 F7 }3 D# C0 Y
165
! p: G5 s+ D' x- ]2 q9 p166
+ @+ O$ h# P! c% A7 [167
* ]' ]0 P/ c! U* T! ?* }168- C5 i% O o+ s% T- N3 O1 o1 G @
169
, [0 G3 N$ a) _170- m) C2 D* t$ ?* Y+ T! `
171
: U! }. a9 r' d* n- Z) E172
( q, `+ r2 E0 I9 t5 H) Q2 A' L0 v173
+ c/ Z, c2 W3 e5 z% X# h174
* O8 A U0 x1 O- {3 T, S175
" D& h0 c1 |, @" T1 r F4 E; Y9 \$ U176
* o- g6 E+ O/ x& f% `2 w7 \. K177
) D k4 g: M' {7 t9 D7 l! C178
) M) C. b% I( ~2 g* \$ {179
9 H4 n6 m/ ?) D4 j; \& A: v180
! C% i/ h) H5 b* x0 t3 |2 h8 B181
0 C2 Q/ B- G( z m" b0 f1828 W% w& j4 \+ I' Y0 Z$ X. |
1833 j; A, `7 c- q1 F9 ?( k ]3 X
184$ Z8 ] o$ Q, N; L
185) a! ~, x7 O& r, T& @" U6 B u
1869 j6 w" s0 _3 M" w
187- u6 X$ t$ { a4 i* d) _5 b
188
/ D" }+ R1 D0 r/ Y; ~189- l% f% M% w+ M
190
+ F6 _4 e2 G6 C! O$ a6 b( x191! N; f; A. z% E7 z& L' v" |
192
8 X: W4 s$ R1 P- f: w7 w8 E' T+ B193- j: q ]+ `6 C
194( J; S+ D/ P2 G5 t0 S9 m
195
( M7 d5 V/ K/ D0 H196% f! r. k' Q# @0 W: K
197
4 D8 b' }" x, x( J% V2 A198
y& D+ `7 S' ]0 i4 K( ~ m199
5 L+ ^, U, I% f3 O200
0 Y6 d6 Y( N: I) g# O f, r' N$ u201
o* b5 o( w# l202$ x5 \* ]* A) }. G- ~* D! v) c
总结7 x$ a& @9 F$ k1 c, ?
自己封装数字动态效果需要注意各个浏览器直接的差异,手动pollyfill,暴露出去的props参数需要有默认值,数据的格式化可以才有正则表达式的方式,组件的驱动必须是数据变化,根据数据来驱动页面渲染,防止页面出现卡顿,不要强行操作dom,引入的组件可以全局配置,后续组件可以服用,码字不易,请各位看官大佬多多支持,一键三连了~❤️❤️❤️
) ?1 M- \, P/ t w: ]# \! P: x2 H
6 v# T4 g9 Y0 U. ^. ddemo演示/ H) s2 t2 Q. i) {+ p9 A C
后续的线上demo演示会放在
+ C: x4 f2 l$ `( qdemo演示5 s* k" u, V+ N
完整代码会放在2 E0 [' X$ w" A+ u
个人主页
- {& L/ ]% `! ^, l I. W8 B' O6 }3 H. i) y
希望对vue开发者有所帮助~
3 C& q( }6 j, l% g# R- f0 @& a2 t Z% P( g4 o" p
个人简介:承吾
! R# n4 I! Y+ @% x工作年限:5年前端. c# n6 b' `6 S8 B/ g4 v
地区:上海
* s9 h- U1 Y" N7 \. }个人宣言:立志出好文,传播我所会的,有好东西就及时与大家共享!
; ~# D. `) F, Y& U, D/ W$ [/ R- z8 t+ z+ d$ ^
5 @, t# t- |1 c
4 t! \8 t7 F/ h' E$ }9 G8 ^- u
. X' D# U% t2 @+ k0 [————————————————
/ g! L( U0 `: N版权声明:本文为CSDN博主「KinHKin(五年前端)」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。: Q9 P7 Y2 {1 S+ l \5 f
原文链接:https://blog.csdn.net/weixin_42974827/article/details/126831847* ~# p' n: E' d) w. |' C s
+ T1 Q/ h& f& W6 \; Z/ D8 C( G
2 K1 J0 ]5 U, T! m& ^ |
zan
|