- 在线时间
- 1630 小时
- 最后登录
- 2024-1-29
- 注册时间
- 2017-5-16
- 听众数
- 82
- 收听数
- 1
- 能力
- 120 分
- 体力
- 562837 点
- 威望
- 12 点
- 阅读权限
- 255
- 积分
- 174224
- 相册
- 1
- 日志
- 0
- 记录
- 0
- 帖子
- 5313
- 主题
- 5273
- 精华
- 18
- 分享
- 0
- 好友
- 163
TA的每日心情 | 开心 2021-8-11 17:59 |
|---|
签到天数: 17 天 [LV.4]偶尔看看III 网络挑战赛参赛者 网络挑战赛参赛者 - 自我介绍
- 本人女,毕业于内蒙古科技大学,担任文职专业,毕业专业英语。
 群组: 2018美赛大象算法课程 群组: 2018美赛护航培训课程 群组: 2019年 数学中国站长建 群组: 2019年数据分析师课程 群组: 2018年大象老师国赛优 |
vue3 | 数据可视化实现数字滚动特效) x+ e8 j5 B" D: W8 M* z
( ?3 L8 X" s: f2 \1 N
前言
/ S$ A( y8 w L3 [2 A( bvue3不支持vue-count-to插件,无法使用vue-count-to实现数字动效,数字自动分割,vue-count-to主要针对vue2使用,vue3按照会报错:
) h% T' X. I0 a2 B/ R$ c1 N0 }TypeError: Cannot read properties of undefined (reading '_c')
. K) O8 u1 q8 U* o/ V+ k' R的错误信息。这个时候我们只能自己封装一个CountTo组件实现数字动效。先来看效果图:. l& s5 E' k7 ]) v7 S/ x
' U$ G; m) g3 j$ w) r- ~7 P' M( c+ K& ]: g& A
思路# [# D: ]/ Q! M2 g9 `0 k+ m% W+ W
使用Vue.component定义公共组件,使用window.requestAnimationFrame(首选,次选setTimeout)来循环数字动画,window.cancelAnimationFrame取消数字动画效果,封装一个requestAnimationFrame.js公共文件,CountTo.vue组件,入口导出文件index.js。1 ^2 b9 Z+ v( g# C
/ M1 S1 F& f1 t
文件目录8 s+ a- j' c" q2 V, ^; a$ o8 t
5 I8 ?8 S7 B- T. \/ U
$ l, K* \3 E8 r# G2 v) m$ t使用示例- L$ i$ C' U: M3 N* U' {$ t
<CountTo- J) i, g+ U& r/ ?6 i
:start="0" // 从数字多少开始* u0 O+ p z' b& `' ~& l5 k5 d1 g
:end="endCount" // 到数字多少结束, y; J' x8 I$ `5 h! d5 S' w
:autoPlay="true" // 自动播放
8 N7 Q1 B5 p& g3 M$ q( O :duration="3000" // 过渡时间
9 O) q8 y. j& l* Q Z' D q0 P prefix="¥" // 前缀符号
* b/ U4 ?! H$ Z: W7 C5 F& k suffix="rmb" // 后缀符号 _' I# `) Y0 M- J
/>. d$ O! ^+ \5 _1 G' S- }- r
1" {- j! j' V; @( N0 N) [: ~9 u7 D
2
- ]) g! Z* H |1 N' m3; ], ~: L$ a2 f w& J3 y
4" U2 }) }9 d1 I7 R2 W
5
6 Z0 y& b" Y" o4 b6: q! A1 l( _, J: ?" K$ O
7
, b9 E( T( [3 z; K/ Z0 o. \8' D' }$ I- K) {0 W5 ^( d' T4 S
入口文件index.js
! ?+ q: O; b- C
" d2 c, f: Z% l, l$ Cconst UILib = {
1 `2 X$ q# Z m9 t# }$ b# E# }! A install(Vue) {
/ `4 P2 Z& F4 e6 A. |2 k7 F Vue.component('CountTo', CountTo)
& ?- y4 d8 ]' Q! F }0 @2 c" e2 V# Q' w; e3 k
}
. u' m! E" n7 Y8 v4 Q
6 x' E& N+ o b3 h, ^ Rexport default UILib6 a7 P8 E! X0 {* N, B' |
A+ S( p7 F l: p14 [' C. _* u. @7 j
2 `1 v& @1 I' O" f
3
9 {. i! N4 F; j- g" U46 e6 z- }2 X |5 B5 L" D" ^
5
3 \9 A% c% }. H0 M7 G, y! Y6
$ ~. R! ~& }8 s7
% E) J/ X5 ?+ h$ L/ i8 L! I8
0 P% h. j r. r' u8 N5 [0 F0 [+ `9
( S6 i5 ?( U, A( Wmain.js使用
# M/ r8 S' V" d. `import CountTo from './components/count-to/index';: W0 j! K4 T" E6 m' B
app.use(CountTo)+ b6 [" z$ `0 m0 z. T1 m
1
7 M! }- I7 v* H6 N- [* y, @- t2" ~6 f/ L5 D. z9 x/ \( p
requestAnimationFrame.js思路
; U: d+ p J% h& m; n* I5 T8 C先判断是不是浏览器还是其他环境4 s& t+ h( f. W7 `! I' |0 a
如果是浏览器判断浏览器内核类型
) L3 `8 O z' h- c$ i" n" I! i如果浏览器不支持requestAnimationFrame,cancelAnimationFrame方法,改写setTimeout定时器
8 ~9 p+ T4 Q) ]9 y导出两个方法 requestAnimationFrame, cancelAnimationFrame
- f- D7 H1 z' U+ a各个浏览器前缀:let prefixes = 'webkit moz ms o';( t: l& y1 i6 ^9 j e
判断是不是浏览器:let isServe = typeof window == 'undefined';
: y' i6 K: S# Q: j$ C1 Q增加各个浏览器前缀: , p) V& t9 d4 _- R4 n; K. c
let prefix;9 ^ z1 N& @0 \) x% l9 o3 C' \
let requestAnimationFrame;) y: q8 t! \; U @$ d! m0 V
let cancelAnimationFrame;
5 N. R# p) f a; w ?7 p9 {5 t4 p// 通过遍历各浏览器前缀,来得到requestAnimationFrame和cancelAnimationFrame在当前浏览器的实现形式* q8 I' ^9 u- ]( b
for (let i = 0; i < prefixes.length; i++) {! X" s, \! L% x( p% _$ G
if (requestAnimationFrame && cancelAnimationFrame) { break }3 ~* l* w! ]* A
prefix = prefixes
7 P6 U$ F$ \2 O4 T& f9 O requestAnimationFrame = requestAnimationFrame || window[prefix + 'RequestAnimationFrame']
5 e9 M0 M2 f; a* D. u& A cancelAnimationFrame = cancelAnimationFrame || window[prefix + 'CancelAnimationFrame'] || window[prefix + 'CancelRequestAnimationFrame']( x' G' V7 `" U: O& I0 Z
}
: @( d6 ]+ f4 S# [' c0 X
) [2 H! y" _; _+ T$ Q( t! m2 O //不支持使用setTimeout方式替换:模拟60帧的效果- }/ h& W8 e8 @% O& J/ m( A
// 如果当前浏览器不支持requestAnimationFrame和cancelAnimationFrame,则会退到setTimeout
# D$ i5 Y: {7 I( L) Q- L if (!requestAnimationFrame || !cancelAnimationFrame) {# C2 a9 y3 \. ^% f% e* b1 N' F. b2 M
requestAnimationFrame = function (callback) {
( S( k6 Q6 k% I1 g/ i" Y const currTime = new Date().getTime()
$ R) z3 F5 h( b // 为了使setTimteout的尽可能的接近每秒60帧的效果9 ]0 n* R, o' b2 {$ Y& n
const timeToCall = Math.max(0, 16 - (currTime - lastTime)) n% _6 D# c: y5 |" v# p! K
const id = window.setTimeout(() => {! c# z: Q' F1 [7 q- u( ]
callback(currTime + timeToCall)2 ^" r9 {5 m/ V; f' n8 D
}, timeToCall)
" L, T I$ C9 v" X lastTime = currTime + timeToCall. U2 [3 ]7 W6 N8 e
return id3 b0 V2 D2 n5 W
}. s t. X! O* i
7 Z9 {) m# E; m* r
cancelAnimationFrame = function (id) {
' w1 x& Z5 C/ U: f3 W1 b* J3 y window.clearTimeout(id)( T, ^- s7 O! Z. X2 i$ u# b
}7 {# \7 ]. E/ u3 F9 ~7 N
}% L4 b0 Q1 y( ^+ J, i
2 }! \4 A4 s V" p8 E
1, D5 H7 O; a/ R- V7 B6 t' ^
2
' E( J/ O8 O% w% o5 |3" }$ J) B" O, e; x: x
4! J- P1 [. L' f% J4 Y- g* l
5
l. p" `& ?. w61 o5 Q' G2 i$ _, o5 ^% p
7
1 S7 q+ @' @! ~8 u b; R8
$ t2 J) b5 E; o% r9
* y9 y' g* J( m( Q% h$ H. r10% ?8 I2 I0 V# j( b
11
( J$ ^& F+ l0 t3 z12
4 ?# _% X% }& r/ o- i" ~% T137 k2 I' S6 s! O- B
14
' P; i( L2 O7 K1 ?. U% q$ K' w( O15
. a0 e# Q2 H1 H. _0 x16
% l5 O0 X Z& N& B' J' X17
( U. M5 M1 n( w180 i! O$ U5 S1 J, k% I: |
196 \) s4 A" j2 R
20
* u2 w+ Q Q: A+ W% n21) y3 E7 T# k, U5 T
22# d. k/ m- G9 l% Y4 k
23
3 {0 p8 h4 G3 c& r% y24
* o3 F& Y3 t% F# K25- ^/ |) z6 m& Y9 ?
26
7 j n: i/ p% k8 o# x" L0 I276 U# a' R. d5 G6 }, ~% B1 e: I/ W/ e
28. m" v" h0 b7 O: k T. w- j. x
293 _, K2 B- s5 \3 z) d* @
30$ |1 A% B* X+ ?
313 N4 r* R7 V4 q1 l9 G; x" ^4 [: I
323 i$ k! @+ y. T
完整代码:
* H/ z8 K6 V1 g E0 ZrequestAnimationFrame.js
4 e: I0 k: Z' J5 z8 E% X% y- Q& g
let lastTime = 0
) j; T4 C; M6 e& {% h& s6 vconst prefixes = 'webkit moz ms o'.split(' ') // 各浏览器前缀
/ P, X! O$ L( }. U, g$ C5 [6 H/ s* y, r
let requestAnimationFrame
7 ]. g3 L9 Y V2 n+ clet cancelAnimationFrame
* Q, M4 s' I0 L
+ H8 S0 R' `& b5 r, D. j/ h// 判断是否是服务器环境8 w. W5 M( _9 j4 L1 {
const isServer = typeof window === 'undefined'5 N3 N* _- E; N
if (isServer) {
( b5 w! [: b' T1 R1 Z* `! B" Q requestAnimationFrame = function () {- \' P' Y1 b, F6 ]
return4 ]. A3 n F7 K9 T1 l
}
- u. L* ~( [( u cancelAnimationFrame = function () {
, d2 F7 l r4 h, S+ z return7 M- t! x& b+ V( P8 q1 v
}1 N6 W6 ]: t a7 G3 P1 j
} else {
; U8 \$ u: E% ~& \( [# P7 @ requestAnimationFrame = window.requestAnimationFrame: ]" h8 Z, h _# w9 [% {! ?
cancelAnimationFrame = window.cancelAnimationFrame
: B& F k& `+ E) ^3 x2 m' O- E! Q3 R3 ] let prefix
_8 Y2 p: k$ |* v+ b* _ // 通过遍历各浏览器前缀,来得到requestAnimationFrame和cancelAnimationFrame在当前浏览器的实现形式
; l9 z/ M8 q' I$ ^ for (let i = 0; i < prefixes.length; i++) {
& n5 k9 q; t- I+ m p if (requestAnimationFrame && cancelAnimationFrame) { break }9 P' d* H" R9 m; n
prefix = prefixes
# g* D" ]" j. V- x5 C4 B requestAnimationFrame = requestAnimationFrame || window[prefix + 'RequestAnimationFrame']2 Y. f5 Q2 V: ]4 N5 E& ~
cancelAnimationFrame = cancelAnimationFrame || window[prefix + 'CancelAnimationFrame'] || window[prefix + 'CancelRequestAnimationFrame'] O1 u4 [* [6 Q. ^0 o- B/ n
}
8 ~& ?8 ~- G, O9 x9 x# i) d t
9 G& D+ u! y: ^1 | // 如果当前浏览器不支持requestAnimationFrame和cancelAnimationFrame,则会退到setTimeout
# I' [% C. G" C% c0 F" X if (!requestAnimationFrame || !cancelAnimationFrame) {
3 Q, S$ Q: i, D- Z1 I# t( A, r requestAnimationFrame = function (callback) {2 H! ?1 }1 v; O- U! j
const currTime = new Date().getTime()
* m, ?1 M7 q0 Z3 s1 L: F // 为了使setTimteout的尽可能的接近每秒60帧的效果
; P/ W% Q# A U* \, [ const timeToCall = Math.max(0, 16 - (currTime - lastTime)). j* l' E7 W2 c6 E
const id = window.setTimeout(() => {
7 o9 m2 l3 Y! O5 J callback(currTime + timeToCall)' w6 k( |) l* Y! Q m! `, ^5 ~
}, timeToCall)
5 Y f+ f5 c( u2 A8 F3 E. R lastTime = currTime + timeToCall
! p4 m$ r- F2 g% Z9 z return id
9 I# h+ n/ I! |* R# t0 Y( w }
* w0 G0 I) x) U1 y; r1 K+ F
# M* z/ j' P8 i; |. m+ r cancelAnimationFrame = function (id) {
- F. S; J( J% |8 Z window.clearTimeout(id)
: ^0 g( k6 n: G6 | }
: {" C& z7 ~: d8 f, h+ g$ e/ X }
, T! ]# h6 d j* x}
8 n8 L! _4 i( P' Z+ a* n$ |6 ?* L: @. w4 u/ M |7 B
export { requestAnimationFrame, cancelAnimationFrame }4 s$ m- |2 w- } a* M; X
% a3 f# l* K: j" d5 n) g3 v' T# @* l* b8 g$ ^1 j
16 _$ f6 w' e4 N, l1 G
2
+ H, H9 x4 s4 _$ Q o9 F0 m9 l3% ]! l( y$ W% P6 q* Z
4% M7 b: d! w3 c8 G5 h4 l
5# R8 p( e5 r0 R& F
6
, e0 s' }6 ?( H) `, Z* j" h7" D$ |2 ^* ?, Z: L
8* w6 I7 d; e( O/ I6 ]& G* k
9
" ~; s! t6 _: _1 i- l( |10! @( q; t5 Q" g7 ~# {
11! ]$ \2 }/ c+ t5 V2 w$ Q1 Z
124 N1 B6 Z. [/ _2 v# c5 ?/ `
13
& N+ U$ @# u8 |14
; t( B* k m9 i/ y. O: i15; w& ]- O) Q$ B9 ?0 F
16) W. B: S: p q8 F" N! t6 Z# T
170 l. {3 E. c$ I( h8 s Q8 y f
18
: E' H$ q2 v( n+ A+ h19
( Y z- {9 x; {& k! _20! a# F4 I7 i9 Y1 S+ L$ t
21) D$ ~' S, K# L3 m- Z; L9 @
22* o9 V$ Z8 J/ `
23- s9 t* z% ]- j2 @; a9 ~3 t
24
1 b9 \( u: K" F0 P G+ q- E25# v( c; T+ _! c* ^9 x
26. p" l' A% V/ i5 b& B
279 j V) G% ~# [8 u2 Q! i' W, I6 L v
28/ t2 o2 N- {: D4 u
293 c* ~9 k' Z1 z
30
4 H& |$ N. w7 T8 \31! ?( }, i1 b3 c# ^) o0 y8 O2 ?
325 f# E0 k$ _7 P& i! g0 _1 z
33
- g5 N1 M) P/ q) ~34+ D; E1 ^! ]4 `) Y5 P* ]# m% s
35! J( @1 P% `$ I+ [( g. @8 L+ C7 s
365 i& g' _$ s+ T! q3 |
37
2 w1 {8 D4 _6 p8 ]* s% F( M38
0 |/ W) t |( y" Z5 I3 e% U39" A. w: R% R' e/ T! S+ K% X% T
40
% x& Q; h& U" V$ w6 w7 W% k$ L41* w' n, h8 t; o! b" m) u/ y
42& f6 d( `8 Z+ b' U' ~. H+ T9 Q
43, Q2 S* J; m: P. h
44
! `, D7 a1 w9 i# J# Y# h5 G7 C45
# g! V6 l# U7 V; F46
+ b- p# C! O1 e% l) n47
: S/ A/ D. u6 \; V3 k% S' h H3 r489 A- d( n; Y# d! v* g
CountTo.vue组件思路: E9 F' C4 b, A7 s' x5 f0 f# d" M
首先引入requestAnimationFrame.js,使用requestAnimationFrame方法接受count函数,还需要格式化数字,进行正则表达式转换,返回我们想要的数据格式。% `* M4 }3 Q0 P/ M" j, [2 N
! c3 y/ O4 F/ k0 L' w6 H
引入 import { requestAnimationFrame, cancelAnimationFrame } from './requestAnimationFrame.js'
! M' q8 L/ u( i3 G19 R3 [$ B8 l+ Y1 M4 }! M3 e; F
需要接受的参数:0 _0 q: J% T: c& a+ P6 q& n
1 b( i+ [8 R+ p& ~# y9 t% W6 `const props = defineProps({; I% k8 _# m# ~$ B7 s" E2 ~! y+ T
start: {, J7 U6 |3 e/ C- q! v' J: b9 V# C
type: Number,
2 ~7 ~" I- p2 t2 L- ` required: false,
) J! p: [% `8 O: e default: 0& ?6 M0 D2 l* J+ _8 i
},2 [) S6 {6 x0 N
end: {
& x+ Y* f1 m6 |* q0 b( D8 F type: Number,% e! G2 n& d' w& N' T% V
required: false,- c0 U9 d6 m/ Z2 o0 g
default: 01 x D! Y( u" y3 e) D* s: C
},
3 s: t- t* Q6 B2 h ^, t9 f$ p4 r" ]( N duration: {
1 ?5 i+ c" ^8 L1 g! d( g, \ type: Number,: [" x- z. I& q1 S- i1 r: l& B
required: false," R1 Z% {6 B2 v
default: 5000, d: P( ], ^1 x* k k: p: g
},2 w% k o" [( V: I" U
autoPlay: {
0 B" t! z$ z& q; D' e type: Boolean,' h. L# h3 o, n* l- c* a
required: false,
: v8 r3 v, p5 k! ~4 ]7 m default: true
F6 Z9 m L7 x6 W( L& A },: \3 V$ ?. e# Z: O8 w4 u \
decimals: {
- a2 o7 m. P5 t* W) O, v& d type: Number,! _' h9 O. J, ~" p: D& [
required: false,7 b. a0 ]: B9 [9 W
default: 0,
5 i" b" ~0 @5 @9 D( E* t7 c: [* Q g( e validator (value) {
9 L% ?1 C5 @$ s' P. Y" W0 y& @/ f# ? return value >= 02 e& q r6 R+ ~( M& q
}0 i/ o; h8 d. i% N2 v. o1 |
},
+ C! ]7 u8 j" n5 | b decimal: {
2 ~9 G9 ^4 `' `! B% o$ L6 I type: String,
3 o$ p" X9 r$ e8 C) h7 V5 Q6 U required: false,# }: h8 |: ?! |7 n7 j7 \4 o c
default: '.'
3 g4 A; N. W! V* G; D },
7 A; {: x$ G' K separator: {4 B/ z+ R. @5 f! I' f
type: String,- Z8 J; `) ]5 J' C: l
required: false,
* Y8 r: ?1 q: L. { default: ','
0 z* G2 N* n& i7 [5 @! k },. ^9 n- i+ L' J6 p9 Y1 n+ Q
prefix: {% `: m) C. ~4 P+ Z( h9 H! Q
type: String,; h% x# f5 ]& o7 _6 D2 b
required: false," P+ o) s+ P: [. _
default: ''0 t. s3 H- [4 T$ k
},
j+ @# g- i+ d6 [ suffix: {
q' k; V$ L) Y1 | type: String,
2 X1 N- E$ j5 W7 I& m) w3 k required: false,
7 W- a* }* P. [: S$ J; A default: ''
( z7 m: [7 k! Y0 L' [3 a7 F },9 [/ }. A( [! c% C) m
useEasing: {1 z$ e/ V; P7 K2 |3 n
type: Boolean,
* }: V/ ^ N, ~6 O+ ~; c required: false,' e2 O1 O* t" X
default: true& F# M. r" a3 k, K( M* y. \
},7 d; T2 @- U5 y
easingFn: {
u4 J" M& `) ?+ ~ a) n type: Function,# Y8 U4 _8 b* G! S% ~8 ]) i
default(t, b, c, d) {
$ _( _# c3 k5 K5 B1 O% N5 v return c * (-Math.pow(2, -10 * t / d) + 1) * 1024 / 1023 + b;" t4 W6 A2 b( z; O. m2 F, ~1 x0 {: [
}( u, n/ m2 @( Y; M/ @0 C
}9 z1 s+ ^' o" {2 e3 p2 S) L
})9 _+ ?# z7 T# X _- i
) A4 o( ^4 ^- h. D
# P E, r) T" ]- r, c5 f+ V
1
/ i/ ^& o$ U. p( g2
! L+ D( C# s$ P+ G$ p3
7 K# ]! w( U+ ]) j; z8 F4. V& r8 }1 T+ u
50 _3 r0 Y; g! ?7 \* Y
6
: x0 y/ r: E4 N6 d# ^3 U0 a7
4 R6 g j! T [9 |8 j87 i, O6 h3 z: S* \
9
" h* K4 Y, U6 E4 a9 ~5 m4 Z10% t# I! _3 k+ a! `+ h% N% H
117 j7 h/ b ~6 e4 ?) e0 g: R
121 X' r' J& Z/ L/ e
13 E3 y7 | ~, `. r" _3 v
143 Y! x( _! s- }+ f+ ^5 ^. T. y
15
8 V& M* u2 L! e+ w$ w/ s/ z% k16
4 n1 j# w+ q$ f" N) d$ l, u0 I17
2 @$ \$ g; q# H! ?18
9 u* g$ N) E1 ]2 k; l/ F: r193 h3 H8 V, v9 ]
20
5 h$ W& n- j* |( {7 ]4 u! ]21: b' V1 O: H3 q* F7 o2 c
22* _" e/ P* ^6 c* e
23
) ?- ?- C* I+ |. L1 m: |24% j1 p2 Z4 V+ G. o/ c9 {
254 }$ K# ?, _* Y, |7 f/ v6 i
266 D+ l! ?! M8 |
27' _+ D9 E- ]6 v; `- p! J
28/ A- B$ F& J7 l- L
29' l7 L6 C/ D7 Q* U
30
1 |2 {, F9 _# N! D' J31 h6 Q5 _% `1 z1 e
32
: D, [. W) N* G6 w6 X* o" N& H33' h* U" z/ I1 }
34 }" G: U1 f u X1 f8 c. S, v" c
35( T3 Q; c* l# y; G4 A$ d, V* R7 Y
36
. s8 g9 J% R0 Z- S) ?. [4 v37 H. h: h. p4 R2 K+ m0 v' s) {2 O- y4 X
38
4 b z7 l3 U8 s* Y, a! I4 y% l39
8 v) g; F. n5 }& C8 ?) S0 t( m401 z, ]1 n. Y9 f2 Y% n* c
413 a$ c8 f" C& k: I9 B0 D9 L
42
8 `6 A; Y0 k! S0 p43* w& |: `4 B! h( f; b: g* Q. u! p7 |
44
* D" O; z* {$ D0 @: L45
/ I$ @9 Y" C; O" ^5 `2 U46
' k8 F" z% U3 R47
. n7 ]- B! E9 v% d& v48
* \5 _4 Q: N. G9 C# S+ G49/ k' N6 `" u7 x) b* A" }! M" t
508 r" C' n! h/ S
51+ {2 k$ w8 w" D( x+ b- T* y+ w' I
526 d- ~$ B4 Y* G- C1 K {) G: ?
53
. l2 ]" O) y& }& d54
6 R( A" u+ ?0 L8 \* D. W55
0 r. R! X( {4 o0 Z# n56
9 D: B6 B6 D ~: I# d) a- ^57
* b& X. ^- J' a9 ^58
, ^, W! r0 i* |59
' N/ R8 }- a; ~* g! N( } u60. C& G" H4 m/ J' A
61
& k ?' p. b# ]0 s0 J621 w9 o; k% Q9 z/ X; Z' s0 S- S' H
启动数字动效
9 B- D8 m) ?# \% `6 d. f; E9 l' O: u: [
const startCount = () => {8 I+ ~6 h% {# W% d( J9 j! \
state.localStart = props.start
' n5 L$ r, d7 t$ L) { state.startTime = null/ s- g5 q, D m9 [5 T3 P
state.localDuration = props.duration9 }4 ]7 z- e) G6 ]
state.paused = false6 ^% p0 w! c2 M$ _
state.rAF = requestAnimationFrame(count)
: V. ^( M/ G6 d6 W}. I- S' d. z. }' ?
1
I4 n5 N0 O+ C- C: C* f* n2' e8 @% j; P* h8 z4 ~% \
3
& J% d6 o1 f4 o# f$ X. W4 `4
. `1 ?2 g w& \& A2 t: c, |: j55 C2 ]+ O$ m( d0 J x" X
6
; W4 A; H n# \7 m7 ]0 p! x7
7 A1 Z) t2 Y, e- L0 Q+ Z0 S核心函数,对数字进行转动
7 m% Q' K7 H* ]' T! m" w5 X4 t, U; f0 t3 v e
if (!state.startTime) state.startTime = timestamp
* B5 Q2 ~; Z; Z state.timestamp = timestamp
; ^$ h; i( T, ~ const progress = timestamp - state.startTime# E4 N1 l& r P: A- n+ ]$ ]: _0 |6 H
state.remaining = state.localDuration - progress
8 D9 a3 U( b. {1 [3 p0 T: c // 是否使用速度变化曲线" Z- j5 H6 v- ^6 n6 @$ k1 u
if (props.useEasing) {4 B3 {. W, v9 C
if (stopCount.value) {
7 m' J: G# `* H/ h state.printVal = state.localStart - props.easingFn(progress, 0, state.localStart - props.end, state.localDuration), q7 f, P/ k5 n) v
} else {' o* U, h5 c+ @9 ^6 f
state.printVal = props.easingFn(progress, state.localStart, props.end - state.localStart, state.localDuration)
! S O6 L1 z, C: m& R6 F* y }
+ j: O: T- z' X5 z9 A } else {! R' ^4 V; w8 U6 n8 o2 o ~3 y
if (stopCount.value) {4 [9 U# ^/ Z: N2 t! {. `
state.printVal = state.localStart - ((state.localStart - props.end) * (progress / state.localDuration))8 e. m1 K2 t6 {0 c+ l' ]4 R/ b
} else {
! x3 A- g" h H( V8 L5 G3 Y state.printVal = state.localStart + (props.end - state.localStart) * (progress / state.localDuration)
& @$ b# Z& {( u0 c }
. F$ |4 `# K0 l) i. S }% y! S0 A7 ^6 p5 L, _4 V4 Z9 ?8 O& n: g
if (stopCount.value) {
3 V2 a* R+ m- @* f/ ?- _8 p' e, Z state.printVal = state.printVal < props.end ? props.end : state.printVal& c9 R4 |6 A4 T+ T9 M$ B# B
} else {
3 G6 [& E2 C! d5 `5 C& k state.printVal = state.printVal > props.end ? props.end : state.printVal
, W' r/ f+ k8 U( ]! U }+ f, O/ v2 B+ m" Y. U9 x+ H0 H
1 r3 ~6 [4 l* n2 B: ?- g4 k
state.displayValue = formatNumber(state.printVal)
$ N# W. K# F8 f if (progress < state.localDuration) {! F9 e9 Y6 s5 |* j$ J/ Y+ c
state.rAF = requestAnimationFrame(count)) Y5 R: M/ E: [6 ^* m3 Z
} else {
/ Y1 \2 ]( g$ S0 Q emits('callback')
0 c! {! ~: B0 y, ^9 u& S }
* i5 }: I' U2 V7 ?( G+ M3 U2 `}
& X: l6 b5 H( T. [4 `7 l1 }9 E9 s# }" U1 ~
/ J; ~! P# e+ e& r
// 格式化数据,返回想要展示的数据格式, ?$ W2 ]2 p1 ~1 }$ Y& b% z
const formatNumber = (val) => {
" j1 u7 W: w1 x% N1 `6 ^5 j val = val.toFixed(props.default)+ @5 p( T5 q( D$ L7 C1 W, i2 K6 ^
val += ''* Y2 k3 h; d; C
const x = val.split('.')9 r, r$ P# h4 v3 [
let x1 = x[0]
% P8 [2 H( H" a: [ const x2 = x.length > 1 ? props.decimal + x[1] : ''
( a5 L5 S* K/ W9 v const rgx = /(\d+)(\d{3})/) Z( R5 k; U" F9 J9 T* W ]
if (props.separator && !isNumber(props.separator)) {8 y3 H' O. F5 p/ [+ U
while (rgx.test(x1)) {
8 Z* R9 b+ j w8 s9 ^/ s& _# U x1 = x1.replace(rgx, '$1' + props.separator + '$2') U& F* |( c" |6 K- i- p& L( t" X2 U
}+ J" K$ y5 @! R2 E
}3 l$ \, h$ w% W0 O
return props.prefix + x1 + x2 + props.suffix
; B& n2 W+ `; `* K9 N}2 v% G2 V' h5 y3 d, z
f, v4 [0 O) }$ @ _# T, d
1& V& R( V& h/ |9 F, ~5 H
27 Z2 w5 B" G: a' ]9 _
3) Q; D! O; X3 l( k) g' D0 R
4" F/ n) G( f/ n* U8 u- b% [
5' P) Q4 C5 m4 L
6
' n0 m* {* F8 ?8 X1 W! N7
2 s+ s! C0 e: L* {5 F8% Y; B L; i z6 X7 n6 F3 z
9
_' A/ g) C# V" W1 B( S* J7 D10: t J! f- a0 V. h' H
11
! X& b% ^4 c# y12
' E$ D$ h) r" z' o13
' w$ {" Y# X3 R: \ G8 V/ y14! {( |4 Y4 y H) Y: v7 Y
15: G0 N' K, i" z
166 w2 O- }/ |1 F3 Y+ c. f/ L$ ?
171 I: S8 g6 U. m- i4 F
18
' c) j' f7 T1 s2 V19
# ]0 _& C3 b6 ~20
. H1 l. }5 f, A6 q( W21' ]3 P1 ?1 a. I$ ]
22
- m4 m* u8 e2 P6 o23( h0 p6 H4 a: Z
248 E$ W ]1 s* I9 ?$ a
25
5 J- m% S6 a* B5 x6 H0 B26
; T( D# t6 w+ H- U27
) T$ w3 B. X1 r28! z |# H7 V& l4 K5 ~& p5 a
29
- K$ X' {; G3 m! o3 E' n30
! G {7 N) h& X& k0 u) T* j31/ n4 ]4 N$ |# C% U6 @
327 X. b, C- `9 ?, N- }6 n
33
( {/ x" v: r" x i2 T34( `3 q; d9 h# F# j9 J1 N
35. R; d% r4 W4 [
367 ]; h. m5 x' v. z' ^
37
' ], y% v; P( d* a: M38
$ `# q' A& O' j2 U: f& z3 H& I39. q! V/ J5 Q8 V3 p3 W
40; `8 g1 |" R' i; u# ]* r/ q
41/ q4 v6 n; g: K" S! [% z1 C
429 s" E8 _0 @# O$ v: X
439 Y& r* H0 {9 @' ?
44' B$ b! S% ^: b. G& l
45
7 {, e' A1 X9 ]% {$ A( A8 q46
$ {2 d5 N5 ^" k3 o# f6 H5 G47
& ]+ x+ F- V' k2 R, x3 S5 X8 u! x% O48
$ J5 P3 M/ A3 p: N8 B) B' s4 ]取消动效
3 S8 i! p) d+ W) g0 K/ R& ]4 q- A5 B" a* n; [; ?- z9 p
// 组件销毁时取消动画
6 o$ E; j% a o" O2 ~onUnmounted(() => {
# _( Z) U. \# c cancelAnimationFrame(state.rAF)
- J8 t+ ?* y" ?! I9 C})
$ f$ k q- D# @6 ?! X# h1
) D9 Q. O8 b' P8 _2
0 C- @: ]0 N) K0 W( d+ d3
* @( [5 k$ w' R. L% I( w" D45 G. q' Z, `1 ]) u2 @6 H
完整代码, ~0 P$ X/ H' k6 v4 Z# E# w5 M: z
" i( t/ R1 C/ C, I. H6 y$ V) v. R3 T' q<template>
5 P; s& ?) j9 C' J2 M8 c# e {{ state.displayValue }}* W% J( j9 b. b
</template>. w; c8 ?. E Q- ~
( } z/ ~- w* J4 `% @. \
<script setup> // vue3.2新的语法糖, 编写代码更加简洁高效
! N( \) V4 L' ximport { onMounted, onUnmounted, reactive } from "@vue/runtime-core";
1 p0 C9 p5 \+ ?- z( U! Z) _import { watch, computed } from 'vue';- e$ j0 M; V' d. o. s: A& L
import { requestAnimationFrame, cancelAnimationFrame } from './requestAnimationFrame.js'& K$ c5 D% L( x3 p! B6 f$ [2 R
// 定义父组件传递的参数
& O7 ?/ f% w2 s sconst props = defineProps({$ a( X) O& h+ |1 v+ G+ D& y9 L
start: {
: L: V% _* o0 O9 @: K type: Number,$ m1 [' V$ U4 o' A* V9 k; S1 z
required: false,1 C' I+ x/ G: ?0 y& F6 Y3 Q* U
default: 0
7 t0 G6 v% \! q% s$ x3 v },
5 j6 c* A6 D6 o8 s- o B$ a end: {
; G# @- M4 y4 ^ Z' M4 I type: Number,8 {6 Q( l0 n, ]0 @0 z$ S, a
required: false,! y% W( C% U- B( f4 [
default: 0
3 l1 N) T! E3 Z/ C; q+ s# A },
) x9 O m0 @' r `% E! W2 H% j: g duration: {
! [' m; e: [. E/ U- o" V type: Number,
. T1 @$ i3 u! [ required: false,! {' ?* r# g% T' p& ~% X1 _
default: 5000
. c2 y: a/ ]# Q9 ^- } },6 [' i4 A: I( h W
autoPlay: {
/ Q2 P) u+ j9 J' ] a$ F type: Boolean,# M& e8 m- l3 R4 U! y b( b7 {2 ^# {
required: false,
: N/ k0 s5 g0 l8 ] default: true! o4 k' }/ r5 N) p0 k# w! x. p/ a
},1 y9 w9 i3 T, }8 D0 h: Y: Q
decimals: {! u+ [6 H: q M& o# {
type: Number,
! @( E' [+ t1 O4 B0 d- I& M required: false,
' u" [& E4 X5 q M' d& ^+ c default: 0,
1 |6 U" |; b) C4 M& ^ validator (value) {& |4 K9 a! ` M/ {
return value >= 0
. B( V0 A* ~; _3 P4 e }8 S: w6 R7 E/ J* P9 X' q G
},- ]9 y' h" q" r% Y$ C" C; w
decimal: {, H7 S& H8 M ~/ y; g8 q6 W
type: String,
3 S* N2 y0 z- h/ [) }4 M1 r; t required: false,8 i1 p5 Y1 k+ d9 P
default: '.'
, H; P& d: v6 D1 S% P4 O. C },
* d5 E T( B6 ^0 @! ?0 r separator: {! Z9 z3 r/ ?( P. @, c
type: String,
# @) K" Q2 V Z0 S N required: false,
% v5 q, _- W5 h# Q9 i( j default: ','; S4 \, x9 v% @. w
},* y- V3 }. a% n$ {' Z
prefix: {' c; J/ V& r7 D1 b/ B
type: String,6 G) g2 S; U! K. L* k; r
required: false,' T5 V) U" c, S6 A% y8 {5 C
default: ''
. i/ |% W `3 J( v8 G+ U }," s; H% \: J& J: W6 A; j
suffix: {- [# ~) k4 c. F. U1 g- F# B3 f6 R
type: String,' _$ c. K2 N* U
required: false,
4 `$ t) E7 l8 p: [: H9 T: P default: ''
+ l0 S' r8 A0 K" g" Y; e },
* D; Y8 ~* M" N6 q" P useEasing: {& l& T& {* O* |
type: Boolean,8 Y7 x: p, e' e
required: false,3 [( h* Q. ?8 }" ]- L+ q; [9 ?/ g
default: true
) B6 A2 M7 Q* B },
* ]2 v" d/ x5 h @/ ?0 I easingFn: {. Y4 s/ V4 E- q/ p, b x5 u* f* f
type: Function," P, ?, |/ m0 D9 I0 j& p+ k
default(t, b, c, d) {' K( T7 j" @( J# L! c
return c * (-Math.pow(2, -10 * t / d) + 1) * 1024 / 1023 + b;- [1 V1 ~- n: g* s2 b
}9 ?/ n/ h6 i B. M K% N
}8 j; E5 j7 ~: B1 B B7 ?
})% c" Y; e+ L4 K0 ]8 J
7 e) A. x1 n$ F4 I) i2 c
const isNumber = (val) => {8 ^4 R- |* m! \; B: j5 k
return !isNaN(parseFloat(val))- c1 k, _: K6 u2 F9 Q
}( W8 ^8 [9 W) W) w: |; s- _
- l" a- |5 s( y// 格式化数据,返回想要展示的数据格式
8 e( ]6 Y& z9 k* N* |+ b' |+ n7 Tconst formatNumber = (val) => {1 I S( J5 |" _; P- F# V3 c; N
val = val.toFixed(props.default)! Y2 P+ |# l. ?
val += ''
! P( t5 W/ i/ J6 l) T const x = val.split('.')7 z7 \: y @: E% \# \
let x1 = x[0]9 E [: o/ V! Z4 t
const x2 = x.length > 1 ? props.decimal + x[1] : ''
" e7 r8 q8 e6 Q/ ?9 R0 S3 m- w( U7 T const rgx = /(\d+)(\d{3})/% ^! J' _! D- L- a7 L; w1 z
if (props.separator && !isNumber(props.separator)) {
5 l& l% w: I( Z. N9 ]% ^ while (rgx.test(x1)) {
2 y H9 V' m4 {2 l) K x1 = x1.replace(rgx, '$1' + props.separator + '$2')
3 e% }7 L1 W1 |/ q0 d2 W# X }
. j: l* g* A ?( e& ~2 w }
2 v( G8 m) v7 i* P8 O( t return props.prefix + x1 + x2 + props.suffix
+ u* L/ Z }* _2 l2 x- X9 j( ?* c}/ N# R" h, Q9 X; `3 G; O
5 O" ^! r" |* N1 b, d4 ]+ v// 相当于vue2中的data中所定义的变量部分! d' J& ~6 u L) I' Q& Z
const state = reactive({
4 ]8 j( Q! F4 T/ ?0 n$ f" z c localStart: props.start,- |% C! z' k3 ~/ l% V. I
displayValue: formatNumber(props.start),
" [- Y; T2 y( i+ T printVal: null,5 A( ~+ B/ Y5 Y; V: g( k2 R7 K
paused: false,
* l+ K3 }' r- v% G, B% c3 W localDuration: props.duration,
1 ]+ W2 S5 i: N startTime: null,
2 ]+ E4 t5 I! r) I timestamp: null,
A. B* T' ?4 K# D' Y9 u remaining: null,
! F, q+ b0 q$ Q: p( _7 @ rAF: null1 t2 X/ k0 |" [1 O% n$ _
})6 W! D8 G5 t( I9 M, T6 v- _2 j
9 J2 }6 O. Z, g( {
// 定义一个计算属性,当开始数字大于结束数字时返回true" D& R K8 Z' ?+ L! q, [4 e
const stopCount = computed(() => {
* L. Z" s: F# H Q7 X return props.start > props.end
2 f- B: `* i+ S4 k2 s})
9 K5 P( [7 }' h4 c% A; H4 Z// 定义父组件的自定义事件,子组件以触发父组件的自定义事件
- V( D3 {2 w8 E5 g3 u8 q4 T% E2 Econst emits = defineEmits(['onMountedcallback', 'callback'])( W) G! a8 S: Q4 L4 a$ k8 Q5 l$ ` N
- B4 @' |6 ]6 s4 v( j
const startCount = () => {
' i" A! [* T. n9 V( ^ state.localStart = props.start9 q0 ~( Y# E- _' i! O
state.startTime = null0 K: j. p% v" N& i3 R9 \
state.localDuration = props.duration8 \) M# o7 u& k* B* l
state.paused = false
- {2 `+ m4 d8 z. S! M7 m state.rAF = requestAnimationFrame(count)
9 P; T! h/ W8 [, ]( C$ S}
7 V- w T: {# d* x3 \ p4 w5 w' h# G# v0 a# Y m8 Y# g
watch(() => props.start, () => { A$ e* [% N Z2 W) }$ z# Q6 i
if (props.autoPlay) {
+ N; i* f# ~* u startCount()
% o( ]. }$ n; B: ? }
$ Z- o. q! v# r3 v2 [9 R7 x: W' [6 b})) E( z8 V! q- m2 H
8 U0 M" ]& s4 y
watch(() => props.end, () => {/ c: N8 W" |' L; d- o# u% Z
if (props.autoPlay) {
8 u- D- G* D4 ?) J( u; p( `7 L& ? startCount()( G* F& D9 M, v0 C3 ?- K
}' R8 H( Y- O& X( x7 |5 W( L
})
( ?: x1 l! |: h# ]" I. M( a Y// dom挂在完成后执行一些操作
! w4 l3 y% F1 V ?onMounted(() => {
, G0 R2 e) U. J7 }- m9 Z9 Z) v9 J if (props.autoPlay) {
3 Y( d- c0 A8 o, h# E. J startCount()
* k2 X7 O$ E! b$ V }
7 v6 q! X: d$ E; V* E$ L emits('onMountedcallback')3 Y$ N/ Q3 }% F1 a6 z6 y+ \
})
2 b3 G6 M$ b! {3 R' T2 b% k9 c// 暂停计数. j1 x+ V2 t" q
const pause = () => {, K- `9 D2 f$ G% |) F3 U
cancelAnimationFrame(state.rAF)
) m+ q% u& K S3 w: T, g- [}# A/ j& {! R9 L3 P% U
// 恢复计数
. t" G9 h1 q% B5 X8 |8 f- Q) n zconst resume = () => {
& j6 i( Z& h# S* k3 T/ k) d. p state.startTime = null- K: r8 ]; d8 `, E7 J
state.localDuration = +state.remaining M1 H, E2 @. b5 o; V9 R2 I
state.localStart = +state.printVal, D; h: Y8 S3 f' V) a8 L3 z
requestAnimationFrame(count)
; A# Y8 P! S6 E2 Y+ w, V! A5 ]# n}
; c# x/ m; |, D; X. \" h. i9 J3 o6 ~
& l1 T9 x" x/ e e% cconst pauseResume = () => {9 k1 i0 d6 a- p0 j& ^0 ~# }3 ]* J
if (state.paused) {
0 Y2 S& }+ C5 d$ _/ W! E6 T+ @ resume()
~. n* A* A' {; ^* O/ t& m state.paused = false( `! V' b5 k) @. w6 i
} else {
( B- B- y" ~0 j1 P$ S& m pause()" n/ }0 i$ e2 l* K% f+ ]
state.paused = true$ e, W$ f: M2 S/ X
}. G& ~4 t" `2 x+ K0 F
}
9 ^- N, ]1 y; t. {- }9 L& w% N% `! l8 _7 j ]
const reset = () => {
5 I, y: ?2 h5 V; d+ L _ state.startTime = null# r# X7 l9 k0 c$ d
cancelAnimationFrame(state.rAF)
6 ?: ~2 j. y0 p) \" ]% z! X1 d state.displayValue = formatNumber(props.start)
( y' V) e. l9 Y* R) p0 J4 P}
7 b5 b5 a C* e% P8 D! J1 W6 f
) b- N3 \3 j6 c7 l9 nconst count = (timestamp) => {$ [/ ^* P) `- }( d4 A
if (!state.startTime) state.startTime = timestamp
8 q3 n2 I0 }% m U% s state.timestamp = timestamp
' E3 J1 ]# x g( V. ]5 m$ U const progress = timestamp - state.startTime
) R5 ~' E8 T$ @! X7 d _. M state.remaining = state.localDuration - progress
+ I3 e! ?1 p2 y* X) Z% C; q! h // 是否使用速度变化曲线
6 N* v# @; L! C+ @ if (props.useEasing) {) `) k5 D8 Q9 r- k6 K. G0 R& D
if (stopCount.value) {
" W, M# k! B/ @3 | state.printVal = state.localStart - props.easingFn(progress, 0, state.localStart - props.end, state.localDuration)
6 V9 P H5 p: z3 _' W' }" Y } else {
: o+ s& ~% |6 K2 y state.printVal = props.easingFn(progress, state.localStart, props.end - state.localStart, state.localDuration)7 N, g! ?* u) I1 C0 Z( |. J0 {1 v* T
}
) q: f0 T) `0 D/ [/ O! V" ^6 f } else {2 n, L' C! B2 Y( z- u. _
if (stopCount.value) {* n; Z2 ?3 A! {; `7 }# P$ t8 _
state.printVal = state.localStart - ((state.localStart - props.end) * (progress / state.localDuration))5 j( Q& x" @8 r! Z
} else {7 h6 j- O3 B9 `: [+ R' J, K
state.printVal = state.localStart + (props.end - state.localStart) * (progress / state.localDuration)
5 @- Q* q3 H- t# T4 R# |. k }2 Z- q2 g! Q+ K& j0 ^, p
}
% o# ^! g; f8 _' a y if (stopCount.value) {
4 ]8 }* p* o3 _- g! H, f state.printVal = state.printVal < props.end ? props.end : state.printVal
4 m( U& b$ `. ~: A } else {, T6 H2 f5 c: C9 O* [- l5 ~
state.printVal = state.printVal > props.end ? props.end : state.printVal
! V) R6 _1 m9 N4 H; i }, t g' ?9 x& T* X# Q' m5 L, k
% u' p! d% V+ G* B- A& O7 w- ^5 @ C state.displayValue = formatNumber(state.printVal)+ [1 o3 b7 B [6 c. z
if (progress < state.localDuration) {
4 Z( x+ ~1 w% R6 I" { state.rAF = requestAnimationFrame(count)
! h* s9 _ ?2 ^1 B9 c) J, h$ R } else {
/ y* r( y& G7 \# k: c emits('callback')
5 a I. w0 Y- `/ ` }
# ^9 N$ @% h' p}
; o$ ^# W0 {4 ?4 n. m$ t, T// 组件销毁时取消动画
& j" V! a# T- D) {$ EonUnmounted(() => {
, k* A+ w% W, c cancelAnimationFrame(state.rAF); V" d8 [3 K2 h$ Z" b
})9 R- }3 j0 A2 s
</script>
$ i, `* c5 N5 |8 m! C0 w2 }4 Q6 }* X
, R" e* h0 o% E1 n1, o8 [! @4 @$ M; \( S
2
. H, w* E2 r& a1 J# E3# @0 r n. Z: u/ J
4
, J) V3 }* `* l8 }% V( \57 h8 C3 a% J% ~: a+ E! }. U2 |6 o
6: A2 O& E: y. J- y$ K* \
7
! _/ R9 C" i4 P; _8
' [5 b+ X* L7 u2 I# _3 A3 X8 ^' ]97 ?4 i. V% B( _
10+ }8 |0 P. I0 T$ A# O3 |
11+ R/ Y2 y7 @$ G
12
7 ?0 f, Q y8 ]1 @13
9 K8 t3 }( Z+ H! s14
) [+ E- ^: [' \! F3 z( |; h15; }) H+ Y" C: K' A
168 A% q$ g8 W3 B! t _* d, l
171 T& x [+ n1 k: X9 b! S8 M7 n
18, ]/ {! z3 B4 z" _
19
6 s6 N7 s1 }2 |% |) w0 y( Z20' j$ }; l! F7 m+ W# z
21
. c% t& `5 F, T# I223 N5 H" k; A! j
23$ s d3 g% }: Q* R2 T) k% v
24
* t! Y! L5 C! {8 c" M25
0 {- a% S) W5 p267 D* {; Q7 h4 ?
27
6 Y( y! i3 I u' I0 }! }28 `$ L/ d2 V9 D7 z
29( V- N7 {2 D! h: b% B6 b! {( Q
30
% f0 y5 n* x. V, i0 G; @31
# n* Z6 O9 G6 ~" {) n32# c5 U: G) V8 W) [& M
33
4 n9 r6 U* V; G0 D/ |: S2 `0 H4 [1 n7 e34
; ?* r6 S3 A6 J35+ m5 _ v' J( f% w8 z
36' l# P) T5 D+ }4 a* G
37
1 b( |+ T; l) N2 L5 a9 H% i% \38
$ D9 d1 x s. [396 V% @/ e$ n3 k& P& @3 g
40
+ Z- R: [ ?1 p& {) y, C: }418 b; n- k4 t4 i8 s
42
, O% Z: x3 u1 w- j43
' p7 W: Q/ R. { i9 X1 O44
0 z; }3 E5 m4 J2 \0 T45
h# [0 [$ _" P( Z- d X6 U46
. s( l% q9 b) o2 W. }# ]4 v47- E4 r0 w5 N/ G2 `- O- p
48 h: D) e5 K: w# Z3 M
49
3 c, b+ A' {/ {% U2 p' E50- O8 [$ A; j& P' H: x9 o9 I2 X
51
' t2 C) W" d; N5 }9 v( ^, M525 h: ~; o; B/ Z8 v2 R8 }
53
) @& m+ l6 O- @. O" m54! ^7 y# ^- I" R: {* V$ d. n' F) A
55
. j, V" \- B2 u8 T+ |4 w56
% f, M, n/ ]$ \7 H1 I: G57
+ e- E7 h6 ]# j6 j2 j: K/ D58
3 b* e' v9 r, q" B: \! X2 _3 K595 T- |! T7 V% v) S0 m% _0 `
609 K$ ~" {) ]# V/ C" V
612 L( w( X: M0 j
62* O( M) ^3 `- ^. q+ w
630 t% j$ s3 y: S. r1 M8 q
64; L9 p. _4 C0 k2 _+ c: Z' ^
65% m2 \" v# I3 `. P4 q4 n- X% ^. Z
66* a2 A* f. U% d( I
675 b: p: H$ M2 w3 q
68
7 E! }6 c+ Y( u! h2 }694 Y" W4 r0 J! n
708 S: e: Z. Q) n1 E
71
0 x5 _" t1 {, P w4 W" L6 N72- a( L7 X3 M2 q X4 N
73
/ T3 k8 B8 z. A1 F* ~3 f# f0 S74. j/ a0 K1 K6 g" L. x8 C$ ?
75
0 P7 r4 H) o% F3 l: l76: {. |2 Q+ f' K
77
, E$ T0 s. G5 k; D. I$ ^78$ @1 {( e( G; T% F0 N0 _
79
7 }% }8 K4 V7 k: h80
: W. M9 v8 A/ ]% E81! \5 J0 w; Q+ U; N. p, X) G
82% v1 {7 F" W* q0 a
831 |+ h' f; x5 o; f4 t% S
847 m& J9 f1 S8 D3 [% q* b- n) ]& k- D
85& F4 ^/ K2 h/ }* z1 E/ o7 q5 v* h7 p' Y
86
) C5 p/ C7 P8 R/ h( u2 t, W8 X) ]87
, L0 k! R4 a1 ^- a6 G% |8 y$ N88* U! k: L% d3 |
89
) h% Z. n! y. V1 y: Q' b, l- v90# m& P$ |8 `% F9 k3 |
91# `6 l0 ^- X5 l7 _. J$ b) V% \
92
$ u+ a; T1 r4 `, Y7 R) T938 |. [8 W; E+ o* U' R
94
3 F5 b& k( x( J/ C* p95% X2 j5 q" g0 G: N- j
96
8 s/ [7 a+ O3 j97
c& j1 S' f* J2 C+ r2 ?! H% X98 r- I. }8 o1 v& W4 L- K
99
m1 f, d9 ?/ `7 p! l) x100 f, R" Q2 P* f. }# P/ |
101 b0 |8 P$ g5 p) v+ i6 q. j
102
, O5 g, ?' m- r# |& E2 S103
9 v" P" m- [5 q+ M7 C2 Q5 z7 Z, Y104
8 L3 O5 ~! o5 P6 P105
+ i" H9 W m7 g* H9 d' J, B106
8 B7 H6 s- ?$ E! d" J% P# M107! n/ \2 X. Z/ U0 a4 @ R% U* E' U
1085 z T ^* @$ g5 {' H4 P9 \
109
, T* K2 h: w& x- A) c( w1106 D; L2 e) U. E& B7 l. n3 x6 j% R$ V
111
( r! o5 M# Q, c, Q8 z" l, `112
5 n' q0 y+ Q6 P( [1135 f$ H( K3 r8 u' f2 h
114
$ x# i* d& j3 C! V# i+ H* u) x8 @115
, Z, d; n' O+ t) m3 L' `116$ [! {' ^, ]7 E) T+ ~. u% P
117& B# s1 L7 _- ? v' t3 ~1 `
118
# t, K% \ g2 }: w8 n119
. d+ n0 a/ t3 `% G2 s120% ~/ J# X4 F1 a" A- Y* t: X
121# P- L' g _) S+ d
122+ i A$ q7 G' m, q8 F
123
0 d L) E& G% s124
: G1 i4 }' n4 ]4 o125
* w5 Z# V$ D! I+ Y( `# I2 V. v126) j" ]) E% d% R
127
0 ^6 A+ k- F. W: H2 M128" s0 g% ]3 M- L8 `; _4 s) J
129; w& a$ f! X4 P2 F! L! V0 B1 }% o9 P) F
130
$ r- T+ j1 m. |5 l: _131
# X& ^! }% Y& a i* A1 Y132: j( r1 S7 C# j5 O& j: y
133
( L! N o! D- B0 a1344 ?% E. k& t M. S' x
135% I) {# }& d- N( a4 }; U l3 r
136- k6 d/ k* h9 X$ i
1376 \5 V/ H$ b; O6 Z1 P
138
# a5 q0 r8 h$ i; J7 D139
/ y7 |3 n4 d2 l140, |. F& R2 s3 I1 G
141' U5 W6 _- _# T) E: I! X
142, M) X O. P6 c
143
$ h B m( @2 G$ f) {/ D" k144
7 c: o& i9 w- Q( b7 x+ Q& G4 e145+ X8 C! l0 |$ q& C7 e
146
# M$ P% b: m) {) t; u1475 z9 a8 T C# m8 [2 n
148
, ~) ^" A6 ~+ s" L1490 ^9 x( o4 I9 o0 G) U
150
- l2 I& @8 J+ z5 g6 O) m/ {151
' {2 Y2 }1 e# g8 {9 m e" s) C1527 a6 W( u0 D- W1 T+ {! ]3 ?% f
153
) y8 c" D+ Z3 W% L8 Y154) J) t1 C2 Z+ z9 R$ h0 P$ J8 }+ _
155
4 T. }( P& c* F156, T! Y& n* i) l$ d% H* n* \* g
157
2 o8 k/ m; j6 D7 S7 M! {1584 \" ~; M7 Z# Q5 U! M7 H% K
159
6 J" p* H, r* i7 p7 Q160
- \6 n* t) d f: H161
# D j0 B, t7 Y5 D! [* ~162
7 N+ F6 ^8 `, p0 ^ W% r% z163
8 h- t2 X( j& q V' B: k" D0 n3 N, R164
$ i% i9 x% a. y2 q2 F5 ~165; K; c% f$ z: F' L) d6 I/ ^
166
7 Q; K) l" R' b# f+ K167
) H5 S( S6 f, R2 {7 @+ F" I8 L) j168
l% m( ~& d9 q( {169) F1 @6 i# X) h0 s+ h
170
( q: k! c R6 e0 E0 m: ?' y0 [171& X9 K) ?: t+ ?+ U
172
8 G; B+ T8 B& P1739 j7 f& }( `6 v7 U
174
/ d, n: m4 G0 w7 |! R& Z W' i) X175+ K9 y" Y# P& L% I! n
176. J% T `& @- C$ R
177! P7 O5 n- d5 D2 c7 \6 A) q
178
+ H! g) I7 |4 @% B179
* z! ~4 V; E1 o8 E180
$ K( h$ E9 }! E181) o" v8 z7 o0 s
182, v/ C& D2 |/ z0 ~" A6 x
183
6 \+ ~% Q; _1 K2 j4 J1 M1844 w5 h6 \& o& o. K( r8 Z
185& H/ e% p% o9 I
186
/ R/ Y7 w4 X: H: p# p' y187
7 v+ o$ w3 q& S) b6 p8 S0 j5 \188
+ n7 s$ O( a* V3 F% e5 ^5 ?1894 n# i# v5 t, a7 q( \* P% V7 d1 w
190, f$ x: C) E( B& I2 B1 A
191* A$ h! a6 }' g3 r
1924 u. [5 o1 k- Q& ^7 _
193; H Y' s/ \9 a6 h/ x3 x
194$ o+ n+ Q' F h: M
195
$ C, }( `0 g3 @+ \$ g. |- m: N# d" q/ g1964 i( o8 z0 |% u/ `$ [ Y) V
197
. E8 J! E9 P, i1 J1 f/ J1983 J4 |* J, k/ t7 G) e: f1 J
199 j" H) t; m+ d+ t' M
200# b9 i# g& ]! B4 B
201
1 T, @& e) U5 X8 H, Z6 _202( s, k. \1 L& @5 {: G# g
总结( T$ S: V$ {' I% i8 m/ V
自己封装数字动态效果需要注意各个浏览器直接的差异,手动pollyfill,暴露出去的props参数需要有默认值,数据的格式化可以才有正则表达式的方式,组件的驱动必须是数据变化,根据数据来驱动页面渲染,防止页面出现卡顿,不要强行操作dom,引入的组件可以全局配置,后续组件可以服用,码字不易,请各位看官大佬多多支持,一键三连了~❤️❤️❤️7 N+ x: r7 o+ H! T* G. a. u
. ~0 e- p! F+ Y& W% K. `4 K7 X
demo演示
* m7 p6 k9 S% h1 [后续的线上demo演示会放在# x" B- d- C) E8 L8 Z2 F& P. n5 x- K
demo演示- |( c; i4 ?/ }
完整代码会放在9 d7 s9 x" v& z
个人主页0 O) }2 R, B! I
* C) j) J) S; ^2 V7 e
希望对vue开发者有所帮助~2 T8 C2 ^2 f5 b0 r' J8 r) h2 }! N. E
( P+ p4 S& J" [$ t
个人简介:承吾
$ v5 r& O2 L7 h, a; J2 Y工作年限:5年前端6 g3 d6 {' ~. Z( h, Q, p$ C" d
地区:上海
8 c( s8 y% M6 W) Q0 C" n' m3 o" A个人宣言:立志出好文,传播我所会的,有好东西就及时与大家共享!
9 i( g( O3 V% |" V8 z
2 i8 v9 f0 m2 @9 }, a2 ~" ^5 M0 M2 U" b$ @
. t: S/ Z* r' q0 i4 X5 \+ b' _- s" W7 r, Z8 p5 w+ ^
————————————————
% J' f4 R0 g$ A n. |版权声明:本文为CSDN博主「KinHKin(五年前端)」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。$ _7 x& D- g; N
原文链接:https://blog.csdn.net/weixin_42974827/article/details/126831847
7 g+ n% C8 Y6 `& \& v9 T5 }' } N0 J+ t
9 e6 C! M- ~* s |
zan
|