- 在线时间
- 1630 小时
- 最后登录
- 2024-1-29
- 注册时间
- 2017-5-16
- 听众数
- 82
- 收听数
- 1
- 能力
- 120 分
- 体力
- 564447 点
- 威望
- 12 点
- 阅读权限
- 255
- 积分
- 174557
- 相册
- 1
- 日志
- 0
- 记录
- 0
- 帖子
- 5313
- 主题
- 5273
- 精华
- 3
- 分享
- 0
- 好友
- 163
TA的每日心情 | 开心 2021-8-11 17:59 |
|---|
签到天数: 17 天 [LV.4]偶尔看看III 网络挑战赛参赛者 网络挑战赛参赛者 - 自我介绍
- 本人女,毕业于内蒙古科技大学,担任文职专业,毕业专业英语。
 群组: 2018美赛大象算法课程 群组: 2018美赛护航培训课程 群组: 2019年 数学中国站长建 群组: 2019年数据分析师课程 群组: 2018年大象老师国赛优 |
vue3 | 数据可视化实现数字滚动特效- l4 M9 b; f6 ~1 Y( ~
& b% A/ S" L E; m: ]& N. ~# @5 ?前言: p4 E1 a+ f5 Q( @7 x& C. q
vue3不支持vue-count-to插件,无法使用vue-count-to实现数字动效,数字自动分割,vue-count-to主要针对vue2使用,vue3按照会报错:
+ D9 Q: L1 ], D: C" N" _6 H4 uTypeError: Cannot read properties of undefined (reading '_c')
& \! C& U5 V( w Q* M" _) S的错误信息。这个时候我们只能自己封装一个CountTo组件实现数字动效。先来看效果图:$ M' ]- c& G k: x; v8 ?5 P; n
1 X1 }. T! |. u) i- {: O3 L0 O# {% L
f( m4 j2 `/ }& Y思路
+ E K- ]& Z2 K Y0 ?使用Vue.component定义公共组件,使用window.requestAnimationFrame(首选,次选setTimeout)来循环数字动画,window.cancelAnimationFrame取消数字动画效果,封装一个requestAnimationFrame.js公共文件,CountTo.vue组件,入口导出文件index.js。
7 h2 s. _! h) `7 C0 p3 O+ K$ t& ]; Y, z# t
文件目录
+ A& @( k& [' Z8 S
" w/ i. {( b: V5 W
* g# J; ]* d, V- T" o/ W# |, Q使用示例
1 n1 } H% I1 V$ {) P<CountTo6 c$ [! ~2 F0 r; j9 ~% V* `
:start="0" // 从数字多少开始; W* ~0 }. e/ K( u1 w6 a
:end="endCount" // 到数字多少结束) I# g# R0 G' u6 P
:autoPlay="true" // 自动播放- z, t8 k- i" Q9 _2 W* [& T
:duration="3000" // 过渡时间
" Z" b% U2 J+ H5 I1 j5 O prefix="¥" // 前缀符号2 d/ ^3 `& A+ J7 |7 j
suffix="rmb" // 后缀符号
/ @: E3 S/ M) l1 ~4 @* \ />. A( d8 x4 B9 A9 {4 {& U$ O8 D0 r
1
) l8 E8 D$ h: T$ e: ~2
: Q4 B" O: L, ~* e6 I$ }* M" f$ W( D4 `3
" J8 [9 V* T, `; T4
+ @* }( Z' \4 [' ?* p+ ^) h5+ O. n' N$ y' B1 V" I( m
6) P7 Q) f8 r7 q) Z8 A
7# x( m4 H6 O" L7 |+ ?. t
8& K. A8 {/ p0 ^6 h
入口文件index.js" ~1 m, X, B6 z& W
4 N2 u, @ t; b) ~% ]
const UILib = {
2 R7 l; N A/ {% B: R& F- s install(Vue) {/ B7 T/ @' V0 Y! L: ~6 W3 g# G# ^4 q. Y
Vue.component('CountTo', CountTo)
3 W$ p% K0 T+ N+ f1 O8 G! \7 n0 O }8 V$ w' J+ o4 ~
}" x. V% q8 r6 J/ D
( L, }1 i2 H8 p
export default UILib# C$ i9 a& s5 D% g, F" J7 V* J
' m* P/ b1 X& L4 n1 D) H$ r1
3 u I5 p# M" l' ~6 a2
) v. p g [: ]* U5 d" u6 u; k) s3
3 L( j7 \) X( N; ? ]( z4
* C: Z9 O$ }/ j$ d5 C51 x* c. V9 ^0 N- a; @
6
$ ]8 y. T2 T9 j t75 m: j4 i h, O1 E
8
+ o K x) ]. |/ w, g8 p9# L) _$ y# }& |3 l- s$ n4 G# W
main.js使用
# F9 z# f( }4 H) y/ H Gimport CountTo from './components/count-to/index';8 K+ q8 |, t A1 V3 I- K) `# ]
app.use(CountTo)
' O0 ~2 k* [2 w4 f) D1. o, B2 ?$ u" y* t& e; n+ C
2
& r6 C5 v# O1 u6 Q7 l# b/ ?% j& s, trequestAnimationFrame.js思路6 N+ C* V4 v& A& r/ B- V" H8 l. R
先判断是不是浏览器还是其他环境2 u, e# c+ S9 R& |
如果是浏览器判断浏览器内核类型
+ z' @: e, }$ E# O4 P( K如果浏览器不支持requestAnimationFrame,cancelAnimationFrame方法,改写setTimeout定时器
5 `$ T& ? B7 E( G8 z, s0 }导出两个方法 requestAnimationFrame, cancelAnimationFrame
1 F0 x9 n; M4 I* x各个浏览器前缀:let prefixes = 'webkit moz ms o';
0 R4 e( |0 V/ x d判断是不是浏览器:let isServe = typeof window == 'undefined';, X' ]3 i, ~7 y: j
增加各个浏览器前缀: $ ?5 Q; N' f) @. C" q6 j$ `" L- `
let prefix;
0 u( \0 L# ]. |* Tlet requestAnimationFrame;0 Z: ]9 o. y0 P# f
let cancelAnimationFrame;$ c q* X& [+ L7 t
// 通过遍历各浏览器前缀,来得到requestAnimationFrame和cancelAnimationFrame在当前浏览器的实现形式
7 L3 \- {$ U0 b' u7 p) x0 H for (let i = 0; i < prefixes.length; i++) {
7 k1 ]. K/ P; m8 p& R if (requestAnimationFrame && cancelAnimationFrame) { break }
?; ]$ Y1 r5 p- l/ y7 b. U prefix = prefixes
! P+ e* W) D3 _$ w0 W1 {( `% P requestAnimationFrame = requestAnimationFrame || window[prefix + 'RequestAnimationFrame']
. c& [% W3 g! n cancelAnimationFrame = cancelAnimationFrame || window[prefix + 'CancelAnimationFrame'] || window[prefix + 'CancelRequestAnimationFrame']
; u- v+ Z: t- Y3 ^( a }
, I# s/ o, V& r1 G( F* w/ q6 W
2 M5 t3 i. n/ c/ h& a/ |! Q //不支持使用setTimeout方式替换:模拟60帧的效果+ U1 M/ Q8 J4 x! K
// 如果当前浏览器不支持requestAnimationFrame和cancelAnimationFrame,则会退到setTimeout! O3 u7 z* U/ r. E6 F4 v
if (!requestAnimationFrame || !cancelAnimationFrame) {& Q. `* G( N/ u' j' z/ B
requestAnimationFrame = function (callback) {6 S$ v' Z1 _( s" j
const currTime = new Date().getTime()
7 e. p2 S3 T! {: C9 }0 s7 n // 为了使setTimteout的尽可能的接近每秒60帧的效果
/ o6 h2 D/ h4 N o' q( N const timeToCall = Math.max(0, 16 - (currTime - lastTime))7 v- j2 N* m8 L' Q% a
const id = window.setTimeout(() => {
" [9 a; \; P7 ?+ y callback(currTime + timeToCall), D) l' V; h- d
}, timeToCall)- @, i2 r$ ^. N7 n4 p1 k
lastTime = currTime + timeToCall; l1 k$ s m/ T$ t) [' c7 e6 @
return id
& t! Y: d B9 G8 n w5 L% f }+ N6 _6 I7 ?. q" N+ \
$ a1 X) Q# v2 q- m$ t, ]
cancelAnimationFrame = function (id) {
) T5 [) P9 t8 C/ Y9 i window.clearTimeout(id)5 N3 M" T1 J" Q8 Q4 }
}/ Q; o& c6 C' }- Y E* \
}. F9 D/ Q7 ?& `) I: k1 h
0 O: {) l# Z0 Z( ^1
2 s/ I) x# ]4 V8 x, C5 Y1 m) l2; ^9 e5 I( r# C! @9 |/ C
3 T- b+ Q( O6 `0 w' B$ K9 z4 t
4
7 N9 x x9 G" W/ g$ H6 n4 B: f5/ L% {5 P' k7 S8 A
6
7 R+ K2 p! l# L; B" U7- G0 b. k3 N) Q4 ]/ \: v
8* e) P8 ` C: t
9) a" ?" W, o* n+ A1 O8 ^
10
1 d2 d6 _+ N1 {* P9 v7 @) y11% z7 L' o' c! t$ m% z6 I
12
! q$ G4 H2 V D' G# |5 P" G0 Q13! n* X( D7 i! y" S
14
; \: D6 U( W) y15
, i9 ^) P" ^0 H+ f8 U9 m166 m" u7 O0 J9 d. |( X: m
17
`( @2 v2 P; ]& A18
9 i3 j/ R3 n; s# L S19" v# l& n/ t& G4 n: Y
20
5 M+ H- n: Z, h6 r5 L* X. i: w21
# g& [ h+ c6 e1 W5 q0 |22; |% h! c7 t) R) @# h
23' L8 \. I* `: K8 |8 O
24
' d. D+ m8 s4 P25' `2 b3 w$ U: J3 F7 Z" b
26
$ C4 k" l7 o: }1 V# y" C277 m7 C5 r/ I" _
28
* t `/ U! ~; p' z8 N! |# q4 U29
K7 k* e# @) i& }4 F30
( r0 g+ H% v" X' x31
0 ]' }. w3 X" d4 S% y321 Z+ t X E# @; C" M" L
完整代码:
1 v0 u2 n) s7 ~- {" `requestAnimationFrame.js
) Z. b) G4 r5 W" b) o1 u! ^6 o9 A/ [% Z5 V- I
let lastTime = 00 p/ v/ O' d6 ?% c* {- d
const prefixes = 'webkit moz ms o'.split(' ') // 各浏览器前缀
+ ^" v& |4 k+ f* p; T' e: w# F9 @9 Y: [1 D; |! j( U+ I5 {
let requestAnimationFrame0 k) K7 v: E7 R9 @* b7 i$ W
let cancelAnimationFrame# o) n! x. z( {9 l
% n4 b0 J% G8 F4 @) Q i
// 判断是否是服务器环境
* D. K1 o+ u H* d ^const isServer = typeof window === 'undefined'; d/ G8 T. k0 O, q% y7 h) e
if (isServer) {
* B" u! F/ i8 V2 l, L requestAnimationFrame = function () {
' m$ e1 g( T" |# V return5 t3 u* j4 A% D" W% y+ D
}5 d4 E V/ `8 A; d" v2 h
cancelAnimationFrame = function () {
X4 p: ^# c+ y+ q/ c) B5 c% m return
' Y5 a. Q; B7 J# _ }: h5 H, ^( R( I
} else {7 n; F$ V2 o' j( l) X2 r7 s
requestAnimationFrame = window.requestAnimationFrame; m7 \6 H T2 ~
cancelAnimationFrame = window.cancelAnimationFrame
1 l. C% A4 |# [" I- x let prefix/ K' D) j q) B" e# B2 c5 f
// 通过遍历各浏览器前缀,来得到requestAnimationFrame和cancelAnimationFrame在当前浏览器的实现形式: b3 q1 ? j( n/ @7 q/ y( O
for (let i = 0; i < prefixes.length; i++) {
9 v, N- [. l' B% o, v$ l0 ^ if (requestAnimationFrame && cancelAnimationFrame) { break }
* e7 |1 M) l9 r, B8 T prefix = prefixes7 F8 }% [8 ]3 r) w
requestAnimationFrame = requestAnimationFrame || window[prefix + 'RequestAnimationFrame']' |8 ]7 j. ?6 p! ]
cancelAnimationFrame = cancelAnimationFrame || window[prefix + 'CancelAnimationFrame'] || window[prefix + 'CancelRequestAnimationFrame']8 U9 U8 L. |: D% ]- j5 g8 A3 _
}- _7 V5 [# Z+ z z2 I. O5 |0 J" F9 H
3 g% w* q5 O1 V5 O) J: R
// 如果当前浏览器不支持requestAnimationFrame和cancelAnimationFrame,则会退到setTimeout4 M0 _' h9 J1 ]% S* F5 o8 T2 ~
if (!requestAnimationFrame || !cancelAnimationFrame) {% b, F3 s t& p8 c0 ]
requestAnimationFrame = function (callback) {
8 g4 P9 R2 y6 u4 C1 C3 p2 @ const currTime = new Date().getTime()! J! q/ b1 d# I
// 为了使setTimteout的尽可能的接近每秒60帧的效果
. @! L% W- Y) I8 n const timeToCall = Math.max(0, 16 - (currTime - lastTime)): b6 Y% p. \; ?8 @# M
const id = window.setTimeout(() => {
% B( a' a+ h, h" G: y1 a' \% `8 ^. c callback(currTime + timeToCall)
0 A5 x! c3 C- @$ @ }, timeToCall)
+ v9 |* `5 W G; l# R% ^, \ lastTime = currTime + timeToCall
( x- E& `3 f! d3 A. }; V return id, ~- k* V% K% \
}3 U N c v$ t; B
& s# K5 F3 `0 q9 p- K* U4 x
cancelAnimationFrame = function (id) {- Z0 U: k& A9 c1 V1 t
window.clearTimeout(id)( E E2 M) B7 L4 N7 i
}
: V1 C- w$ z2 p# E: B! }* P }7 X( a& c) V6 t6 o6 w
}2 o- q) v ]7 w
9 r3 J, O3 @# Wexport { requestAnimationFrame, cancelAnimationFrame }
$ q. H( w0 G/ z7 _9 h) N" K
3 `2 z# P( O& ~6 o& r) J& u: \& |, [0 x" S& U, O
1
) ~3 j- x( J2 G6 x7 M; w4 z: H9 T2. F+ E; `1 j }0 n
39 q. b9 Y0 P' ?4 ] p
4
# s0 A, [" W- C3 K. ?5
6 R) G5 L0 w" S, I, D% n6
4 n& Q! P5 f; ?% Q/ t* n U: V7+ X1 c2 b9 F- U6 N! O
8
( w, T$ f, W2 F. a a7 z$ N95 @' F, r- F" X
107 i' X! x) q- j
11 j/ {& \. n1 r4 Z% s2 A& Q
12- _: |" ?. ?- R4 D
13* K: \7 R( ^' u( q9 ]- A- m
144 ] H; R, x1 H$ U8 X5 x# F9 n7 t
158 Y; w) Y7 I9 d5 M! @
16/ o* i1 V0 O$ u5 A. ]2 n9 q
17' V/ j4 ?& A# W% h. P- t Z
18' l( o0 t$ n0 k6 |5 a0 Z; V( P2 V9 ]
19
8 J+ c9 p7 w- k7 D1 m. ?20" x( h: u1 Y7 E3 y
21/ V# ]7 f' ~" Q, m
22* l; c2 T# d5 u' [
232 T) h+ \1 f8 P3 i; k! R
24
7 m- i% ^5 `. V' d) x- p25
7 R* R# s. |$ V- R; k4 o26
; N0 d$ j+ p! q273 S& B$ v' I' d6 J4 j. X
28; ~" Q/ u" U" j3 P. ^
29+ N& }: Y. r1 A* g% o6 `
30
7 _, S! B& W6 u% y @% ], m31" T. |6 `& a& } q. g) X
32
5 l2 a# I3 B( x6 i6 @: E33
o) } v- e- |8 Q& X+ m* o34
% s& v; ]* g' B* \35
) n& v) {5 i% q- T( T3 x: r36; t8 A% S# b, P K/ V0 }/ j5 G
375 p% w7 l/ e% L
38
3 b3 S; K ?2 y* t, B& @# K39
# q9 M; X. [2 @40
3 B$ Q9 K/ ~( D4 x. z# j41
- @" r4 g$ U1 }4 L. x4 {420 ?+ R! E7 {( Z& f4 ?8 K$ n3 d
43. D3 l$ `8 [/ U2 g
44
4 z# K# ]* H- @% O7 z/ \45( ~/ a6 [' |' S+ `5 E( F
469 S# |. C5 U$ f9 v
478 W# f7 @, ~& @4 M7 X
48
7 _9 Q' W$ X4 o/ WCountTo.vue组件思路
! ~- x' o5 i2 x" e/ ^9 @! F: f首先引入requestAnimationFrame.js,使用requestAnimationFrame方法接受count函数,还需要格式化数字,进行正则表达式转换,返回我们想要的数据格式。
3 p d. ?* B: L8 p: G ^! r/ j9 ? |
5 B4 D' H0 }) u8 u Q引入 import { requestAnimationFrame, cancelAnimationFrame } from './requestAnimationFrame.js'. |# K) Q0 m% C" G" c8 C
1
0 H( t2 x: ?$ P' W8 |3 [! E需要接受的参数:9 o1 h. e- T$ f' r( K
3 u1 A: s. ]/ l& P+ |
const props = defineProps({
" ?) q( @3 }! g9 S start: {
! n& k& p! w( K$ ~( j* U type: Number,
; c# V$ G7 t1 ?$ e required: false,
R5 N% X5 W3 S, A# R9 j" L0 O; u6 J: ] default: 0
1 _6 h1 H7 d, T6 B5 J },& _2 L# B4 Q& Q$ l" b) s( r
end: {
- l9 ?4 p; l: \3 T) k Z0 n type: Number,; S3 W* s' s& F7 M
required: false,$ U6 R( v7 w6 S% A3 i
default: 0
8 I$ M0 M, a5 Y0 d: V4 _ },
! J8 j s# Y3 L duration: {
# |0 ~) R J; w5 o type: Number,
( {0 K; s( K4 ? required: false,
' `. z" H- t( ? default: 5000
" J9 ?$ B% S) H0 G2 Z },5 r: A* Y# [; U
autoPlay: {
: k, v' f! M, v* c7 Z! m type: Boolean,# D5 b' m$ [3 Q% y7 m
required: false,
( P: S6 k$ i- H3 g+ L; B) t default: true) h( n' `& R0 _. z! C& I( K9 g
},
8 q+ b% F/ q( n* e decimals: {' w2 c/ K F# B
type: Number,
! |2 T( w7 r2 g3 r5 B required: false,8 y8 m- r/ `9 D2 O) k1 l
default: 0,. y7 [. ~) S! v* I. n3 x' K1 B
validator (value) {
2 ]' [5 \ x; ]* Y* |7 o7 o return value >= 0
! r9 }- {$ G" C, m }! G( I: O2 E, G- _* Q& \
},
) ~( g2 t/ K; K1 d! L* P decimal: {$ i1 i$ z1 c; v& h# z
type: String,
! m2 k2 O& c, K0 C required: false,* z$ |5 g( l6 O: R, ?( l1 o4 |8 ]7 @( g" t/ `
default: '.'$ J8 t( A1 p; p, U
},0 m0 X0 V( D1 M2 {& \
separator: {9 V6 L; u& ]4 F, A( ]9 x5 G
type: String,5 N; w3 I* X2 G: @3 `' L
required: false,) X: c7 j6 R J3 U
default: ','$ l. q+ {: T7 A% M; E0 w
},/ H# P; }$ u% V: r) |
prefix: {7 R7 L: B+ |; v/ g# d
type: String,9 n' O* q+ C- q
required: false,5 x% U9 a$ o* s$ K
default: ''
4 ~' S- u- K$ Z },
% V* O6 d% j3 t+ i, z [' R, @ suffix: {
: ~0 f \2 P- M o type: String,
- }* S' ?- v7 \1 S# f: A$ l required: false,
, l9 g0 m7 U" p+ | ~ default: ''
8 t. [; S; h0 r t" v h* P },+ q% m E5 W# {
useEasing: { ]8 Q' \) Q' C. w" w1 Z% d
type: Boolean,
- C4 h4 [; x; b: }6 D/ C+ D required: false,6 o6 p _# K% T7 f& O5 {6 C- w9 r
default: true
1 H5 B& K l1 U1 d" M },
% u5 q. S+ D* F% d easingFn: {6 _6 p. w, E# N4 l5 ?
type: Function,
( E2 d6 i" E& Z* M% `7 ? h) H( g default(t, b, c, d) {
9 @8 R' x6 J1 a8 { M; r7 L! x5 D return c * (-Math.pow(2, -10 * t / d) + 1) * 1024 / 1023 + b;
- l; `: O3 f! t) Z }
- t# T/ Y% x( m2 U }
5 s( j1 h( H6 i* R}) A" v! z' C1 m1 B8 |2 s
7 S9 d% J3 h6 D0 g% y$ _% b$ O+ n4 T* c/ @' p: B) A
1' ^3 F: P; i$ U; O6 @
21 c8 @! c5 ?; X7 c# C
31 S' I8 R* L7 g- z) O# d
4
$ Y1 z/ q' a' v9 K" n: Q5* h5 c! e5 S; W6 v [
6, A8 O, B$ v' _' Y0 p5 n9 i
7# ^/ A% U. F0 W0 r. _
8% X* G" ?# U3 G
9
* M6 ?! c0 p# G: A7 a- l10
5 ` h5 V# `" P1 n11
8 O' _" `6 U W0 p) K) E6 v12" R: Z0 r- {5 N3 w- j
13
& t! B; ] q+ C/ w- a, ?5 v4 Y- d14! | s l6 {! p# @) y
15( @1 l) S7 X( k
16
( o3 P, c% I3 Z2 f$ C* {, H2 S. W17
" G5 y( x) J0 o8 {- y% p18
4 F" g% ^- h2 [, J1 W8 v190 H2 j( ~: _: J# b0 O
207 }' A7 ?- @( |4 |, P- Q& P3 i
217 n: h" J, l) B7 @! I
22
& n! V% A# P# i R23
, j) s0 x2 i) |* F# @) ?243 b1 l& P. _/ t6 u) T/ ^
25
4 Y) N$ z8 x, v& A9 q- T26
* L6 p" C6 b! X: b( O6 ~27$ B* H0 R& R, O4 q
28
3 M/ o7 k( D+ V6 V* \4 ^) e29
7 J$ k; N h4 T o* ^2 m' |30. v2 v) W3 O; ~8 X% r. B( x( u
31
$ ]8 y" O: B {; e: M# o32% U8 Q# E/ P- U4 v; A4 { S
33; o$ |9 v2 O( `- s
34
' \: E& T9 _5 u/ O) r2 j" M7 j35
3 W5 z! @6 E2 A% n' d' W36' X8 f% s2 ?3 A0 C: O) g
37$ q& G( B! d" o! B }
38
6 l9 o0 k( K% L396 g3 y, X& F; w+ y/ r5 i K8 {
403 j. i: i" q1 N+ o
41# G) r% u" w' g% L8 z- u- X) B" s
42
. M3 o& i c5 D6 \: j$ Q43
" p7 v# I( S, L# q446 @: i2 t/ ?$ w8 q8 F; E" F
45
. r2 c$ G$ Q! `) I46
( F( }: H4 q% ]: w$ e6 i& u47 o' j0 K K$ N9 Q; L, p
48) K! T& j2 a3 ^5 d1 r9 j
49+ ~! _2 d0 N# p0 G
509 x1 e: K! S! a- A: L$ r1 W
51
+ C9 L( V9 m3 B8 Y7 D- t7 B# O52/ }( [4 D* S# h
53) L P2 D: x/ ~9 \
54; W7 G& g4 q& Q2 G( i' D
550 v" y E% A& g- q
56/ }+ X/ ^0 e( X& t) Z5 L2 l
57$ M+ ?+ j0 {% B) N" x, m
58
0 G6 s7 G2 |4 T59
! C+ r7 P1 U; H60
2 c8 C; |5 u7 i' e0 O. t7 A1 o61
! }( W: ~8 H. T) s5 @. c- K' w626 w$ @1 j9 X6 ~" D0 [" _9 X. ~! @
启动数字动效
% z6 u2 e8 B, ?# \ t4 y9 |3 v& n: G* x) Z- t- O9 Q( s
const startCount = () => {# l: s+ ` E" A' y, o7 d, c) I
state.localStart = props.start% g# _6 A# E3 N1 b) W" q
state.startTime = null- C1 E/ w2 v. L2 A' t7 N% j
state.localDuration = props.duration
8 h' l5 g8 `" H1 c: s state.paused = false/ m" x1 }+ G' P) ^6 u9 ^
state.rAF = requestAnimationFrame(count)3 P8 u$ p N9 T7 w/ N
}$ T3 E; ]! l) g: |) A% ^
10 Z, T+ s! W6 c1 k. N" |: p
2
; o) g/ s7 y# R32 A3 Q( y$ {8 t8 l( k# V" E& M$ v
4
* K) q' b9 D/ q+ N5 N7 D5
/ A% H% Q: U. t0 R, g" c63 {5 q# |5 c$ f. W- s& W& O7 [. F9 o
7
A% [( Y+ g5 w! C3 Z" z核心函数,对数字进行转动
! m8 _ E# m% z5 |7 j
9 Y0 j1 B. j- W0 w' ~ if (!state.startTime) state.startTime = timestamp0 k8 q1 M% d" H( a3 a
state.timestamp = timestamp' e8 y, \6 h# N) c2 l
const progress = timestamp - state.startTime: M) r( v1 ~$ O) U
state.remaining = state.localDuration - progress* T0 v2 Z" c) n
// 是否使用速度变化曲线
* y/ V4 q! }* s: G: ]/ z9 a if (props.useEasing) {- S# s% o6 E6 [! W! d5 A+ o* `8 L7 o* _
if (stopCount.value) {
9 k" a$ k! M5 ?& ?4 ^/ ~; D state.printVal = state.localStart - props.easingFn(progress, 0, state.localStart - props.end, state.localDuration)
& {6 Z6 t6 n, _2 w8 I2 S } else {
# S$ a7 w5 l. h+ z% M state.printVal = props.easingFn(progress, state.localStart, props.end - state.localStart, state.localDuration)* F8 I5 {; @2 m# x/ P$ A
}. }9 d7 }; V$ ^/ ?/ x" T
} else {
, Y5 r I+ s+ S& s2 U if (stopCount.value) { K; ]" @: I$ ?* d9 G' o
state.printVal = state.localStart - ((state.localStart - props.end) * (progress / state.localDuration))
6 ]8 _% h) e8 V; u8 y9 l5 g } else {- R2 Q% s) [5 O% o6 h
state.printVal = state.localStart + (props.end - state.localStart) * (progress / state.localDuration)
3 k; o8 v0 n5 _; z# ~ }; n! x6 n1 O0 z
}) Y4 F* W! x$ g- A. n7 b, ^3 t7 z
if (stopCount.value) {
5 s! k- C ]& @; [" ] state.printVal = state.printVal < props.end ? props.end : state.printVal0 a& j8 P8 U( B! M
} else {# ]2 ?) T, `1 U3 Y' g. ~- S
state.printVal = state.printVal > props.end ? props.end : state.printVal0 u& \( r6 |4 T
}
8 N% X. S0 p% n% W4 F3 w7 N: Y5 r# _+ D
state.displayValue = formatNumber(state.printVal)( K2 Y+ n+ i/ ]) D& Q: x' X
if (progress < state.localDuration) {
8 i! E2 e0 c4 m( P% n- [+ d) o state.rAF = requestAnimationFrame(count)) q+ o: u% x! e8 ?0 X
} else {
; z& o5 u# F& G" b$ d: Z3 O emits('callback')
. Q& w4 A$ `4 g4 f, J( j0 g3 H3 u }
+ D8 D+ H8 F# X}
7 y9 x% ?1 [* ^6 Y4 \4 W) E6 W: d. J% D0 m4 \ j; j
& m3 J9 ` m }# X! K4 n4 b& L// 格式化数据,返回想要展示的数据格式4 s. D6 U" I3 o* T1 D
const formatNumber = (val) => {
& y1 c. ?! t! f" q/ V E val = val.toFixed(props.default)3 b- f4 a, l1 H. [9 Z# m% _- T, _
val += ''
8 C2 T1 P, B. g- {) b+ X8 o const x = val.split('.')
2 w' b2 v. d' f, V9 j# ^7 b let x1 = x[0]: H u* @5 V# N, v! B8 H* V; Y
const x2 = x.length > 1 ? props.decimal + x[1] : ''2 B2 p7 @- I+ d0 ?$ O9 l
const rgx = /(\d+)(\d{3})/
# o- |" j0 c+ U, w* ], s4 r* v: H if (props.separator && !isNumber(props.separator)) {
1 v, i+ _% |/ s- \) ^1 Z+ r while (rgx.test(x1)) {1 \7 _7 a2 |( m# g# W# D2 f; T
x1 = x1.replace(rgx, '$1' + props.separator + '$2')* p; Z( X7 M7 l* X$ B0 V4 r1 @
}
, @. [3 Q' \. m; X! R/ k$ O% n }4 }1 j' _/ z$ A {! ~& R& l2 n1 ?
return props.prefix + x1 + x2 + props.suffix" m5 i! @8 b5 n+ \0 R4 R
}
* J. R% J- E2 Q' p# A, ^, {3 }; u( g% y3 T
1
& `/ W% D( E' F( ]2 W( t4 y' Y, v5 C
3. \7 {3 Q& @' d& U V
4
9 Z! _; d% M( G( E2 d5
; n) c9 v2 K& E" a6) W" r O: R8 x& L2 V
7
- s4 W8 }! e9 M. \' j$ M6 u& o$ i8
+ q8 k! y5 s _; H% w5 E94 J" \& y6 ^9 E! g0 G
10
2 E( n' m2 M( y S11
* W9 `' X) G1 L/ E% L, g12
( x6 p! H/ m1 X3 r8 a133 u8 P* w) }$ ~
14
. N( G" y) b+ Y+ J5 }+ t15 r% n" i5 }7 ?1 S' i
16: }, k1 m6 L. B9 Q, a
177 d$ x/ C( ^4 b8 x4 S ?; @
18
, F* o% ?$ A5 e3 s* N7 b19' q+ m% B' A* ^4 w% t3 ^
20. t# P0 f! N: o9 S) \5 J1 I
21) q: p0 l2 h. e- S! B1 L5 A( a
225 y% g3 q/ j: ]4 O/ H( h4 B) E: b
23* Y* [7 M7 k ?- k4 h
24* y4 u* ~- @. m0 X
25
# t7 o; h) D$ g, B% o. m: |26! O( c) e" u" A# }; {! g
27
% {" w2 u5 p1 p1 m, d9 H* c& w28
6 o" j# a5 Z% Z: d! i/ X29
) _/ }6 x9 u* f/ y' m8 D305 s3 o4 h2 Q8 l% `5 G
31
) M7 _3 o& @& O z0 U7 R32/ y% j( x, E+ T* }) F
33
- D& ]' k* v) t# `+ m34
. v l' o: d$ X% H35 l4 ?1 T7 L+ U- |- ?) N
36
$ l8 x/ I4 g- h y. o: B37
X, P; g( k/ y8 D1 \38
9 G k6 s5 T0 |5 N39
+ s- ^! [( l. ~& r" z [# T. p2 ]0 d40
( z: H' Q- f4 Q$ ]' y- b+ l41
4 ]. Q w$ v. b* G7 C' ~% s# F% R42
/ U; M- D. o# b' d43- ?: b k9 S+ n! i6 G0 p$ c
44
% u$ c9 f( i9 a6 n* q453 O! V$ Q& |& w* m. c
46* j. }" U2 V2 g% S3 U0 C( a7 K
47
. d9 @7 u) ^; e- g, s) R9 n% x48; x" H. ~' s0 i9 W
取消动效8 e4 F4 q# O) _ S. a9 M
# U0 k5 T, m. c" _
// 组件销毁时取消动画
2 G$ O) z5 R2 ^& z6 a' x) {onUnmounted(() => {, p/ V& M# q* k6 w2 _
cancelAnimationFrame(state.rAF)
1 u! o) R$ \8 A% P \# x' _})
9 j: i3 z& M# g5 b2 ~! Q10 W3 a3 F( v1 b% B6 c
2
1 `: U; z* O/ I, Q5 I9 ~7 L9 I9 X3
' G4 k. \5 [" ~4/ c7 {( C5 _& O$ l- B7 K1 x$ X
完整代码3 z) [. B7 X. v! b# i$ ^$ Z
0 f0 ^0 u8 L! b( R. k5 U2 I0 d5 d<template> f5 h) |5 X4 M1 R7 I4 Z" B3 m
{{ state.displayValue }}0 o5 p L' y6 @/ `
</template>, y8 p" G9 U: @- T
+ B ]: H7 o* f l9 N* {: P8 U<script setup> // vue3.2新的语法糖, 编写代码更加简洁高效* N( f. p# \# A4 W5 O( k, F
import { onMounted, onUnmounted, reactive } from "@vue/runtime-core";4 g$ i3 \% r# I/ S" l
import { watch, computed } from 'vue';+ D. F4 r* X; e, M- e) t8 W# o
import { requestAnimationFrame, cancelAnimationFrame } from './requestAnimationFrame.js'
( e4 j* q/ ] b// 定义父组件传递的参数
$ O, Q, [; Y, H$ ~) A: c* \const props = defineProps({- g0 g! [. L* }7 ~$ j% u! A
start: {( b6 Z/ ^/ N' P4 J5 A. f6 Y& w
type: Number,+ k# y; i( p; ~, x8 I
required: false,
/ a8 D3 m! e( E' c default: 0# e+ T" Z9 a; B4 }2 @2 \$ y
},5 Q, t% C" y: O" H
end: {
, k2 @" U3 [% H, m0 F6 W1 E1 I type: Number,- y/ n. Z( A/ ]# ?* W2 m, L
required: false,+ M( d1 G& ]+ l( d# B- z+ \
default: 0
7 ?- c- c! [; o* @5 Y4 b5 U6 S& H },
8 ^% r/ F# ~8 U/ U duration: {
6 o" D, P( h8 V3 Q$ i5 W type: Number,5 \! D+ u4 p; J$ R" Y
required: false,
; x! x7 b3 r$ \5 S0 V7 z2 H default: 5000 L5 H# C8 U" o( t
},% I: {5 W) Z4 x( D4 R( D
autoPlay: {& i; C6 H# k m' e. y- g
type: Boolean,) W2 J4 f# _" J2 i5 w R
required: false,
5 n: i* Q. K* D6 e: a, [ default: true' Q6 h1 l- h! u J
},- e# S* _) G9 y% i4 t, l
decimals: {6 G7 l1 T( l. v
type: Number,
- k, h9 c. [/ f* A+ `9 z required: false, m/ {! L" B! R: S& Y; o
default: 0,& t+ `* |5 v$ K# `3 B; o$ g8 S
validator (value) {+ X7 R: P: v* c, o% s6 m- ^
return value >= 0: o1 z4 ]/ F" j) i7 v
}
+ w9 Q$ c7 r( i" v/ ~ },
+ _0 j1 [2 {6 H5 W decimal: {
' n, S0 I" _( t* {9 { type: String,+ N) D2 _; P1 Q- W. j
required: false,! u; l m: e' T+ F
default: '.'
7 x! v: @) e4 q) D2 h },. G- f1 b! t' r
separator: {4 L$ N4 S8 x+ |4 ?; _, ^$ }1 n1 O4 p, v
type: String,+ q; U3 n- }3 ~; x2 ]
required: false,# L$ ^" ~5 d5 d
default: ','
k5 h: o; @6 t* ]) _' u" d },; n, \+ U8 T, h" ]" d
prefix: {7 l. N' w4 Z/ O0 F0 ^; a" J2 ^
type: String,
; X3 |" L+ g2 e% T5 E3 { required: false,8 W4 T' M* K" I( s8 E" r8 e
default: ''
8 Q- _" ]( m9 y$ ~( R5 m! O+ `, X9 I }, @: \3 z$ w7 k+ o
suffix: {
( z& R' T1 _% {) U3 y0 c! v type: String,
+ O' u; V/ `2 D8 a0 M( k required: false,
2 l' }9 H4 Q1 ~ C* N. r+ w default: ''& w' ?* N3 N& Q9 }1 Y
},2 C% S/ p$ I4 R5 l) a
useEasing: {& l2 `* `/ u$ E3 C* L. Q8 l
type: Boolean,9 V. _- T \3 ?& U! S5 V* y5 F
required: false,- ^! c. T$ V$ n; q
default: true
3 w& g; f: k4 D8 U3 r' q( V },3 B( J; k5 f. `$ V, x! j
easingFn: {- T% A' X7 l* j T1 v2 N2 Y: |6 E
type: Function,5 l- h2 c7 n+ u
default(t, b, c, d) {
3 J0 S% v$ Y G return c * (-Math.pow(2, -10 * t / d) + 1) * 1024 / 1023 + b;7 k6 E* w v3 k' k
}8 H6 B6 @, K* L9 ~
}
, a7 v# w4 ~4 o$ F, c}), c7 M+ t. u4 `
, e+ G7 S) `* k0 K' Z$ @" r5 T7 Cconst isNumber = (val) => {* w2 K9 s/ o. w3 k
return !isNaN(parseFloat(val))
6 l9 G$ A* Z0 q; N4 S+ U- W}! q2 ^7 O, `6 l
/ R( w$ L( o: H5 d1 q5 y0 B2 b// 格式化数据,返回想要展示的数据格式6 y, ^, G) O: D* x( F4 u6 c1 k
const formatNumber = (val) => {4 Q6 i) i5 R, ]( R, V
val = val.toFixed(props.default)
; ~" u, ?! L$ c% | val += ''
0 |; |/ R3 D& @ const x = val.split('.')
) i9 j' o! ]/ ]4 k+ B& h let x1 = x[0]/ e8 p( \) j3 Q' X
const x2 = x.length > 1 ? props.decimal + x[1] : ''
7 ]( n/ r/ ]! B, R1 B' ]% S const rgx = /(\d+)(\d{3})/
( q$ I( e7 S' \7 g6 l if (props.separator && !isNumber(props.separator)) {
- c* r o0 J* c$ } j while (rgx.test(x1)) {& k6 p9 `! b( N6 T( Y" {
x1 = x1.replace(rgx, '$1' + props.separator + '$2')# O3 O1 U& G c- O& b. A0 l4 `
}
% P9 x' d& Z& U$ H _- \% r }
# K7 k; T) V3 m% R g0 |, v return props.prefix + x1 + x2 + props.suffix" N: r) b2 ?/ X& e
}9 X3 g$ i, ^% R, W3 R) ?
2 X3 `: Y! C' z: _: q0 b8 f; l7 r
// 相当于vue2中的data中所定义的变量部分
& r* B2 z) X* i- Econst state = reactive({
6 K* [1 E9 K. R+ z8 g, N1 r6 u3 O localStart: props.start,
" j% N( T; e8 z# K, e displayValue: formatNumber(props.start),
, e% l* g: g0 v# D+ H. P8 C printVal: null,% @8 b8 e* ^, ~0 B; e
paused: false,
1 k* ]! g2 y- a3 _ localDuration: props.duration,
6 I9 v4 t* ^ H startTime: null," [/ l4 e: F' v0 p" w( O
timestamp: null,& @4 G2 q8 w. ~. X" R! Y
remaining: null,& k+ P! x# @" d/ X7 n3 F% U8 @ q- i$ a
rAF: null
7 `5 Q7 t" Q2 X5 v})) u. |) l& y% A' u
& _1 p4 D2 B6 X4 L: c( R// 定义一个计算属性,当开始数字大于结束数字时返回true# F. V S/ z# j( \% C
const stopCount = computed(() => {. \' a* q/ w: j" R" |7 J" _7 Q
return props.start > props.end2 Z0 G9 [, Q2 }4 [; c! {! O
})
& c7 f# |, a+ K' F2 V// 定义父组件的自定义事件,子组件以触发父组件的自定义事件
' {3 M% m; S# [+ M/ Uconst emits = defineEmits(['onMountedcallback', 'callback']). c; M- N+ B7 \; [8 x8 ^# X
7 {2 Z& c% M& _8 V2 a' Jconst startCount = () => {
+ v. O+ e, m, `8 s' J1 j state.localStart = props.start
/ M& Y; ?( E/ a8 y: }2 { state.startTime = null
) E& t4 e; a( U5 Q1 {+ n! G3 R* Y+ m state.localDuration = props.duration( q9 G5 h$ ~! }3 `7 l
state.paused = false
0 m: |$ y" ]( L( ^0 v state.rAF = requestAnimationFrame(count). m8 E9 w, x4 y; ^2 M( P
}
/ i! m: a H4 r& Q. i3 O2 @1 B6 e- o
watch(() => props.start, () => {6 ?3 q( D2 U# O- v0 g( Y* H9 H
if (props.autoPlay) {
* D* @# X( r3 W% L7 N8 Y startCount()1 A1 w' H8 ?. i6 C
}
9 D% Q: b; N5 G})
. H% s+ h4 P& I1 M0 C" L+ ]! Q9 V `% P! H
watch(() => props.end, () => {
" o$ A7 A5 X _7 |+ a' s if (props.autoPlay) {
) w3 j9 n5 y! ?4 K$ W* t startCount()3 J o2 h: u1 F2 ^, u! B9 q
}
' L1 e5 c1 z8 M4 W! O( |/ w}): l. n8 O9 u* H; D( ]3 e4 z
// dom挂在完成后执行一些操作
$ d9 F6 ]- w0 q- y" V PonMounted(() => {
$ N4 B* b L1 o1 L if (props.autoPlay) {
* }, ?- v, W* C$ W startCount()
! d3 o1 G) l+ y* C1 }; ^ }3 Z* I( H4 T3 n, Z) D m; d
emits('onMountedcallback')- f; S6 [' f0 U3 Q
})
) H. g$ h4 h3 ~+ I# w2 b// 暂停计数9 K. f& Q5 M; V" r: w8 X2 \/ D% j
const pause = () => {. A; X7 `# @! p- z4 w' r. {
cancelAnimationFrame(state.rAF)
/ K' b, r& T. p; Q! J& V: w0 d% B6 Y}
5 {# J+ D& [5 E// 恢复计数7 U6 ?; Y7 u5 H% P$ c
const resume = () => {
7 Y; V5 ^. Y) t+ A E state.startTime = null
, K$ t/ l5 P7 T3 h0 f* K state.localDuration = +state.remaining2 h5 @! n! b# f d# @ N. D6 r8 a
state.localStart = +state.printVal$ a6 y' @9 G- {& C/ p8 U
requestAnimationFrame(count); P& ?! E9 P9 M( o, z- ~4 t) J% a
}' |& o* Y4 n# x7 ? H
' m0 X% e7 T, N9 n. P
const pauseResume = () => {
( i% Y3 f% l% G( _ if (state.paused) {
- P9 { l t" @) d resume()
7 k( u$ e0 N$ l S& f, l; L+ H state.paused = false9 B4 v" V9 _/ I" T4 d
} else {+ p$ n- c- b6 a' n# t
pause()8 _4 S% ]' D# b' k
state.paused = true
' q. h! X$ ?, R9 |3 U( K4 T }2 O" f9 y7 y& _5 w" g9 ~% z
}
7 s7 Z6 B0 N, r( D' F
& E- v9 c' N9 |# r, A% L$ f) Lconst reset = () => {1 S9 Z( F: D6 s( ]+ c
state.startTime = null6 K0 J! n9 u( P
cancelAnimationFrame(state.rAF)
4 J6 G# }' B* c" b% \1 n state.displayValue = formatNumber(props.start)
6 o5 ^7 a6 t1 a4 @) K}
( X: Z* S) [3 \$ z) Z7 }3 `2 c* q t9 \
const count = (timestamp) => {
. [* U+ K8 U. r8 ^- [& b+ T( O, M if (!state.startTime) state.startTime = timestamp
' Q( l$ l1 l" S. @, K- e/ d state.timestamp = timestamp- q, x5 n9 A. B3 B, W
const progress = timestamp - state.startTime
: ?# \" n, m- Y, f state.remaining = state.localDuration - progress, o4 J! h8 q2 l7 F- i
// 是否使用速度变化曲线" e' {, `. ]0 W `- N7 a
if (props.useEasing) {
3 @' }( G- @1 A, q$ K7 H if (stopCount.value) {& ?& N) G! a" u8 V9 G; Q
state.printVal = state.localStart - props.easingFn(progress, 0, state.localStart - props.end, state.localDuration)- q- t: b- l3 O$ l' \9 U8 V, Q
} else {
# U; N A! I$ v' W state.printVal = props.easingFn(progress, state.localStart, props.end - state.localStart, state.localDuration)+ _: ]: M0 T& q
}
9 ~3 d, Z3 [: z# n2 L$ q) [( C } else {' I) Q p* y) Y" T5 Q
if (stopCount.value) {5 U; i7 f0 r- j. ^6 A. ]: L: |
state.printVal = state.localStart - ((state.localStart - props.end) * (progress / state.localDuration)): @# j, x4 g! |/ X' \( J7 }
} else {& l5 b+ H3 K, i: T4 C3 K, D; X! d" s
state.printVal = state.localStart + (props.end - state.localStart) * (progress / state.localDuration)0 P4 o- v' S2 ?! z
}) B3 |; F! C, C8 i+ ~
}
1 r" \# Y1 ?: k% F& |$ f2 c if (stopCount.value) {
; T! ~6 c1 p* L- K state.printVal = state.printVal < props.end ? props.end : state.printVal
# V$ H- G! g( b2 T } else {. O- T; L7 g# x
state.printVal = state.printVal > props.end ? props.end : state.printVal
( z1 ~# E) u( d% x, R0 H0 W7 r }
5 Z0 C; C1 f# O9 c+ U
. H. k& { m7 g* M! W7 A+ x8 d state.displayValue = formatNumber(state.printVal)
) ?8 L+ i2 M3 h" U, [2 l! @: P if (progress < state.localDuration) {
" H1 @+ n2 u+ h3 J state.rAF = requestAnimationFrame(count)
: m, V l f! _7 p# r/ g* o$ R } else {% ~: B# P% @) o: t3 e+ O& K- _# N
emits('callback')
/ Z$ u/ U, r# x: N }
% n; O: B. y3 m9 `. m}2 b' X; L* a; C
// 组件销毁时取消动画. L! m& V) |1 _% I! Z1 P
onUnmounted(() => {
8 z( _, h$ ~4 C2 P5 t+ q cancelAnimationFrame(state.rAF)
9 P, ?( P; Z( V# e. i+ A})! v5 l: B; L4 U- \
</script>8 ?5 n0 r( O. j; f
5 Q! |3 a; @8 G- v: f$ J1
& J. T% N7 n9 c8 x# r2
; U) `2 V8 C# ]8 M2 `3) c0 ] V* [8 [4 t; |
4
/ X8 _( d: X" Q" r$ N5; Y4 y: R$ ~4 q: B; l
6
8 J/ m/ m+ G; j7 A5 Q7
. m. S: J& o7 M3 x A0 l8
8 Z- r% h1 [7 r/ C: C# r# x- O95 N5 R! W8 i; P# K# S! W
10
: E6 o9 Y+ Z6 w11
+ j* g( _) w( V5 v, }2 ]) c12
3 w1 j8 C S2 v! {139 K; {" m* g% i/ d4 R, r; I
148 e8 o) `: }* Q- c7 \% w
15' i# V* c1 U/ [( V/ x
16
8 {" ]) `1 o- r( W @/ W+ @17
* }7 K3 Z' ^' q1 M3 T! \4 b181 U1 D& e/ w, C) f$ P- y9 e; r
19
/ i; g9 ^; |& K; ]20( X* L9 `2 C/ Y3 v6 w+ C b& a
21% ^$ G5 R* S$ P1 b, T
22
( S8 ^& g) i/ H: `) y- O23
9 k0 P) U5 ?& B m) T; W! q24
# k; c: j) L" w7 |25
6 s" o" g! K o+ ]1 U. u26# S$ x" K% l* ^1 P% S% {3 z
27
( {3 o) L4 ]2 B; a* _" a28
6 G3 Y/ N2 m: Y* E9 v; G# W9 Z29
5 T) U" a7 q" z! P Z* x- t1 T304 D+ z* w9 X+ @. n9 P
31+ I4 M- _* G* V/ l
32
0 J- g( a5 N4 x7 \ r33
' ]9 I& }$ z. F$ Y- O1 P( k34
7 \/ I: A7 P+ I35) i. e1 B" q0 q" k x
36" z* m7 Z* H) [4 g
373 a: g6 i6 S; E2 m( w; K
38
# j9 K+ g# y0 Y# L398 z' V8 \0 z" u1 J- z. S- i* s
40. Y4 [% e/ f. J+ _/ v% d0 s
41
( u/ N& J( W/ _1 b" A42( E1 Z" [8 d3 c$ @( @. r" D% |' t
438 J% Q7 ~0 @' l. b; M$ O& l
447 D k, D( _- [
45( p8 j0 d4 E$ E$ K8 c( S
46
$ w2 X$ S2 i6 o3 d: z473 p2 F( m' p0 g. n2 o
48
- \$ j+ K; n4 ?49, S! F# R$ r( k! T
508 H* n4 W; w: y: U6 E* k
51
4 ^% C; e' H1 @9 B$ l52
6 B4 j! w1 ^! b3 `# x- k53
- F: K7 q7 o* d54* ?8 k A# v) B x" ^% u
55
. z- R* j" g! I6 W: n6 A* \56/ L9 S$ V1 P8 Y+ M( O" a
570 u6 K& x( I6 t7 Z. Q) v
58$ m" X% `$ H5 E; c# n; ?7 p
59
- u; H! R' v2 I605 x; g$ z1 y1 D& M4 v
61
3 @ W% _1 s. ?6 c" a62 t3 d) u5 s% `% ?/ a2 s% @
63
2 e! s& w, c4 `1 |; N64+ P2 i" L( I1 [& X& V
65* i( T4 S6 t4 t7 k8 J. q# U# m
66; Y9 Y! [9 x" h, i6 e% U ?. ^
679 `& h2 a+ m) B$ C: J5 ^
685 r4 {4 j3 N6 r
69
" [ Q0 n' H7 Z( [709 K# D9 O9 J+ a1 d9 ?+ N& @
71$ N5 J+ c" M6 F7 _) o
72; z+ [0 k4 E5 `' \! k& D
734 d7 v# ]8 Z5 q+ C( W) `% T
74# r; ?7 y$ _6 `7 A
75
3 B: M' ?% w+ e8 q; C# T76
) T4 s m8 K4 p+ f8 R7 ^! b773 [: e3 q) _* @, u
78( w+ D5 v) d6 G3 Y- y9 t! E
79
# j3 L4 w# Y! f806 W1 @ x! B' s( ^
81/ K' h8 B4 L5 q7 O- H
826 k. A+ A& K) q/ G# Z* |
83
2 q( H: k% G, P84) R) N' L3 m- P9 A. l' P Y
857 T" t2 I/ b" }' |2 i
86# N) u& b# ?$ e M3 p# ^
87
; [% A+ _( Y" d8 q5 Q88
$ y! |( w6 n& Q, d% H89! N6 s$ c- V3 X; i
90( a. x! y2 S# ]9 r, `# e5 l
913 q8 {' f0 y) V( B) N
92
. z& N# X- y. z( |; d# B! z7 g93
2 I& _4 T7 Q9 Z- q94
8 b" B' s, W% R% _3 J95
2 k9 H5 ^. l6 J9 N: _# e96 q8 x, E% d$ n- ~3 |. N
97
- x+ ^7 R3 l& P: [98
, q1 }5 y+ j+ P/ a99
2 ?7 W2 b1 o' C$ W4 j+ Y100( U s8 \+ g. V, w) L( G" G
1019 U2 m9 R+ N5 W5 ]
102
( f2 v2 c3 p+ l+ s103/ V& h) n; z" D7 l
1045 q h, {0 P' P8 v
1056 X7 @3 \6 e. R2 J. F% Y, g9 @
106
6 `7 J( O) R( m! D107
6 n2 A, ?2 @, c2 C4 X) h& s3 ?108
9 h# I1 ~( [5 s$ d. X8 z1 |6 b' L1098 _. o7 U; K3 l
110: Z2 g9 Q& Y- r L! t J1 ^: P
111
! `. G$ z6 R" {; Z' r' \4 P112
. A2 ]9 S2 i! E. V: r( d1 g5 k113* w6 p2 s* ?. l# U" ]0 ]
114
/ R* p5 K" `# |3 I( q1158 ?* L: W) e1 _ ~* m
116
( X0 C6 X! b- R* t+ M117
9 g4 n& T6 f* v; k' r118
% t( C x a" s; P8 G1196 f' E- V8 M! C# T
1201 W* W8 g. z4 [ q5 K
121
+ S7 o; d6 {9 E) ~# j122
. u$ \9 v7 I4 B! t2 J% A1238 V ^# B0 j4 U5 E
124
9 C8 m7 a/ K* g125* I3 @. {6 m# f9 m/ ^
126
4 ^& J; f+ a! ]127, _- g; G6 z+ z' P# {1 L
128
/ a' @2 ?9 x6 {" x! v! ]129
8 w, F7 j* U1 r- p6 n! A7 p e130: z/ {7 Z/ g1 Z8 @
131
4 A$ l: V; R, D9 I0 b7 d132, I7 b/ o* v; c+ u9 T; D0 K6 R, x! j
133
/ J0 n( `! d& V# V2 R- t134
* O/ w/ `4 f3 W9 I135- E+ Q% J6 V8 Q! B T% k' y* A
136% P7 |4 a& n% k0 [4 q9 O
137# G3 J. u! {1 e& Y% @ E9 p% D
138' [$ d) D. H/ u
1395 d. i+ N" l9 ^( x7 Y8 u6 b2 u% H
140
3 f+ L5 D- d. v b141
8 N) N- ]' ^/ V4 _8 ]8 a- Q, e142' M6 h* W2 C3 t# }, t8 ]
143
% [! q* v l9 |& G' s K144
+ S4 w- Q& `8 P4 ]9 b2 g: S& ]4 S145
7 w+ Q4 D9 B, |146
3 h0 b6 _: U4 {! k1474 y4 r' @) c' b* o: O" \
148/ i a4 Q( P& p) N5 [ i' m
149
6 \& K: S3 Z0 V6 H9 D+ B+ u150
. F) g$ w8 c+ W& V! k7 P+ d151
( J7 c1 m8 e; k152
7 g% i) c. H: v8 U4 S h/ W- ]' ?& p153/ J& @ S# ]+ K w% \5 e* u
1544 e1 l8 s, d- C
155
3 Y! E* z3 `! G. ]( R0 _( B156
7 ~: Y& H$ T- w; K' W4 y157
. g8 C5 y$ A4 `0 L158
" m* B/ p9 M8 I2 e( i159/ D7 B* }- X! t7 R- G7 W3 e8 t
1602 I3 p' `7 H9 i7 Q% N- E$ F
161
; s/ W# [+ o6 ]& `1627 W$ o6 E( `# O8 I- o
1631 A* L* L( R! Y8 c0 c2 D8 L/ P
1644 ?5 R4 n( V$ t- M# _/ B
165; I3 l/ N* K: }& O
166
. s# ]. L5 V' T$ f/ w167; X9 S# u" \; l0 z8 F$ k: L
168
' A& S6 K7 j/ z1 v169
\; R; H7 y+ S& e1704 W2 j7 V2 X) N& J8 D8 a' t
171
. D, b9 X# N1 I7 Y% n* `- e N172, c3 o3 R- N4 j5 y& T: U. H
173
z Z% X" _9 ~, f k. d8 w4 g174
( l" O! Y2 [" B8 N6 _7 w; N" M1755 L% l" N6 H6 M) f+ K# j& h: y
1767 Z w& _8 z2 B0 B8 b: Y
1773 z ?( c1 X/ T9 Q1 G
1788 ?7 i. a: R% g& \( ]
179
+ K; O/ w, r( T1805 s9 C+ {' K! F" N" c
181+ X! `: Z* [$ q- L- i5 d/ f
1821 m1 H/ E1 d( K6 I3 K+ u
183) Q9 e# C% M0 p
184
T/ ~5 T+ A) Q( v* f185
2 W6 o3 p& J/ i, }6 N1862 p3 L6 o D- @* k
187
' M, M- W- b$ C* b/ x4 i188
% y; h" x' @& [) Y189
3 E" b, _0 e1 a6 }1902 f; J1 t; [+ G" Q1 f
191, O# v. m; O& m, r6 e- _6 Q
192+ g5 X- i. O+ C
193
7 z2 U& L2 Z; t9 c9 U194$ I2 ?- _2 c& I* }! I r$ Y
195
0 Y1 L+ L* o2 [8 F3 P' _1964 @: O7 V `9 v2 k+ \* u
1971 V4 F4 { v% N% W6 s4 H
198
6 r k, H) H4 i: \7 r& p2 U) z199
. q; P) m3 i! D" G. V2001 i' e4 f# @: H
201
# Z+ A4 M1 {+ ]3 |! _2021 R) D, m- Q0 E H6 z
总结
* f" N9 x& H$ d2 Y( ^1 w自己封装数字动态效果需要注意各个浏览器直接的差异,手动pollyfill,暴露出去的props参数需要有默认值,数据的格式化可以才有正则表达式的方式,组件的驱动必须是数据变化,根据数据来驱动页面渲染,防止页面出现卡顿,不要强行操作dom,引入的组件可以全局配置,后续组件可以服用,码字不易,请各位看官大佬多多支持,一键三连了~❤️❤️❤️& g0 v6 J! ]+ q/ M: j1 q
1 j i% N" F0 w6 e" o n
demo演示4 `$ Z3 F* O; ]/ d* f
后续的线上demo演示会放在) ?+ O" |0 u: p/ b" M' ~1 T
demo演示
9 V4 }" p7 u7 M* g; z2 E! k完整代码会放在
r+ L7 D) T) ?. W" N f7 x个人主页
$ d9 X7 [! E+ |5 C. ^8 H. A" t0 v! B1 I C8 u
希望对vue开发者有所帮助~# T3 D- T) c6 I2 E; u0 [/ O" N! y
) u( T c: n* ]4 ~$ K' O0 f& Z个人简介:承吾4 M- _" ?% q# ^3 m6 E& d
工作年限:5年前端" X/ L: t9 ^' i; ]0 t2 A! t5 }- Y
地区:上海% X! w# o+ g: Y
个人宣言:立志出好文,传播我所会的,有好东西就及时与大家共享!; K: ~+ d* |8 C7 Z |! c
5 o" A/ V5 f& {# I1 n. K& _' @: \4 U8 z+ e8 `5 |, j
" @# A! } k8 |4 ]
: h+ B3 B/ h1 A
————————————————1 z+ {4 y: E+ s
版权声明:本文为CSDN博主「KinHKin(五年前端)」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。/ k4 i+ {6 O8 z! y$ q
原文链接:https://blog.csdn.net/weixin_42974827/article/details/126831847 G( u* U2 P% }2 `2 w+ P
/ O7 T( o5 Q- t8 i( g$ {, [/ U
$ o6 s% F3 U4 n2 E* n5 f |
zan
|