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