- 在线时间
- 1630 小时
- 最后登录
- 2024-1-29
- 注册时间
- 2017-5-16
- 听众数
- 82
- 收听数
- 1
- 能力
- 120 分
- 体力
- 566251 点
- 威望
- 12 点
- 阅读权限
- 255
- 积分
- 175098
- 相册
- 1
- 日志
- 0
- 记录
- 0
- 帖子
- 5313
- 主题
- 5273
- 精华
- 3
- 分享
- 0
- 好友
- 163
TA的每日心情 | 开心 2021-8-11 17:59 |
|---|
签到天数: 17 天 [LV.4]偶尔看看III 网络挑战赛参赛者 网络挑战赛参赛者 - 自我介绍
- 本人女,毕业于内蒙古科技大学,担任文职专业,毕业专业英语。
 群组: 2018美赛大象算法课程 群组: 2018美赛护航培训课程 群组: 2019年 数学中国站长建 群组: 2019年数据分析师课程 群组: 2018年大象老师国赛优 |
vue3 | 数据可视化实现数字滚动特效
" K2 b5 p |3 M8 c: u: |) w# c! X
前言
9 E) k2 i' g7 X& y( M& H( }vue3不支持vue-count-to插件,无法使用vue-count-to实现数字动效,数字自动分割,vue-count-to主要针对vue2使用,vue3按照会报错:0 t, W; F b$ L$ ~
TypeError: Cannot read properties of undefined (reading '_c')
5 T" U( z; C2 j4 }' q7 C, e的错误信息。这个时候我们只能自己封装一个CountTo组件实现数字动效。先来看效果图:/ K4 y0 Q/ p) f# \1 J) K7 ^: M# n
/ x) j# R8 C$ M( w; A
* U5 {- S+ R, a8 s8 N/ t3 ^- t
思路
7 o8 \8 F7 R, G4 L4 w% [5 A使用Vue.component定义公共组件,使用window.requestAnimationFrame(首选,次选setTimeout)来循环数字动画,window.cancelAnimationFrame取消数字动画效果,封装一个requestAnimationFrame.js公共文件,CountTo.vue组件,入口导出文件index.js。
( q4 z$ u, c0 f0 D& H& ]4 }+ u0 i. x+ c7 ^3 T4 j. o3 c2 E8 r
文件目录, h' D j2 W$ a! q3 u" o& \
, [5 \9 H" {0 J8 r+ `
" W9 c$ c ^% s" u- y" |+ ?
使用示例
% s7 d! E* J( J<CountTo% v# y$ G* i; U( }) O7 ]: ?
:start="0" // 从数字多少开始
9 l. @. l4 `# m: H; W- |7 p5 Z :end="endCount" // 到数字多少结束
1 a* T' x, ^% G/ v :autoPlay="true" // 自动播放! h E8 i4 V- N5 t' ~9 X: Y. f
:duration="3000" // 过渡时间0 j8 K' i% c) v" d P
prefix="¥" // 前缀符号
k1 ?9 l: e0 g0 D8 m- y suffix="rmb" // 后缀符号, k) x+ l& ^% a) }1 x
/>" _, S+ s8 q7 z. _, L
1, m( ?5 d' z* E
2
: w l; m) a( D' [/ A4 }3 d) ~0 J3
+ r' M# C1 V6 V8 E( \$ N4 g4. e! y( Z0 G+ m& r
5
z5 e: m8 e* o( ?5 Y6
. ~- M+ j" g& S. k5 ~0 X5 l7
# X/ @" @5 _' p/ Q8
/ F% e1 U0 B+ V" \! o入口文件index.js1 P) k0 q. A& @' T: h$ s, }
) G9 c1 f8 j1 Z2 z3 p
const UILib = {) L& _; q5 l" W5 R* r7 n$ t" y
install(Vue) {# X& e9 U# |* V4 K5 F5 p0 z+ @
Vue.component('CountTo', CountTo)8 |; [) O, s" a8 U) }# Z) d
}
! k) i$ \2 c1 [) K7 [6 z5 z' a}
5 X# N; [; _: ^$ p, ~+ ?; O- C; J x/ Q& z" Z& W
export default UILib
7 l9 Y1 ]7 f, f* R* P( P2 V
- V0 S: A! q. n- L- k1& f1 K6 Z" ~8 u6 j
2! s) z5 u3 e% k* D9 H9 y; h& d
3
% U, P: i1 n# L) `) o7 M9 {$ w" J; y4
5 e0 q; s4 B* }5
1 M# L8 M u2 `) k! x( Y" W6, C* I, e g0 J. ~
7+ O( x2 Q7 c6 i7 }7 B
8
5 G; p7 V6 N4 j& P9 V% w96 D0 ], g$ w, d- y- b0 ^
main.js使用$ \, g- q: d, S! F1 A$ l) k
import CountTo from './components/count-to/index';
: h+ G, m$ b* G' S& d0 C( @app.use(CountTo)2 q/ L2 n e' {
1
: p8 I" F5 v$ h. J: k2
5 {- K% y) {4 z1 `! ]6 N* |requestAnimationFrame.js思路
/ P/ N; K3 S3 ^+ H: H! a先判断是不是浏览器还是其他环境
; E5 B: H, \2 p: Y如果是浏览器判断浏览器内核类型
& `5 r5 V/ c5 K& a* a2 h y如果浏览器不支持requestAnimationFrame,cancelAnimationFrame方法,改写setTimeout定时器4 z# J$ `" c; U8 X1 c; E1 D
导出两个方法 requestAnimationFrame, cancelAnimationFrame# B. f5 I- ~9 {
各个浏览器前缀:let prefixes = 'webkit moz ms o';
! N1 }. b8 D( ?0 n判断是不是浏览器:let isServe = typeof window == 'undefined';1 r; o6 K( j2 a
增加各个浏览器前缀:
4 l- F7 m) {( h" @$ `* h! nlet prefix;! I# b; d9 u# ^* R. U! B6 s# Y2 Q3 d
let requestAnimationFrame;8 z; P, f: u: _- P/ m
let cancelAnimationFrame;
, d3 |9 L6 \' C: T! G// 通过遍历各浏览器前缀,来得到requestAnimationFrame和cancelAnimationFrame在当前浏览器的实现形式* G+ f& f0 N9 _
for (let i = 0; i < prefixes.length; i++) {
* W' Z, ]$ @; Z) N1 l% c if (requestAnimationFrame && cancelAnimationFrame) { break }6 ~$ g; _4 o5 H3 p$ H2 L
prefix = prefixes; V9 `0 c; z) M0 I) T# ^
requestAnimationFrame = requestAnimationFrame || window[prefix + 'RequestAnimationFrame']
7 k: h$ `8 F; l! u5 x cancelAnimationFrame = cancelAnimationFrame || window[prefix + 'CancelAnimationFrame'] || window[prefix + 'CancelRequestAnimationFrame']
' c: D2 d8 H6 }" V F }
* n# e1 J3 W& b p: Q0 Q% t3 T+ |0 \+ s, Z& I1 |
//不支持使用setTimeout方式替换:模拟60帧的效果+ k, x p/ q$ A- x z' f6 ^
// 如果当前浏览器不支持requestAnimationFrame和cancelAnimationFrame,则会退到setTimeout
3 t1 x2 ]/ E* Y7 ~) y, F: x- E if (!requestAnimationFrame || !cancelAnimationFrame) {+ @2 E+ r& k, ~: L5 h2 E W7 w
requestAnimationFrame = function (callback) {0 Y* Q* N Y3 ~$ M% ~% _
const currTime = new Date().getTime()
1 s+ s" D3 [% l7 X // 为了使setTimteout的尽可能的接近每秒60帧的效果! Y4 Q5 `( o4 `! I, Q
const timeToCall = Math.max(0, 16 - (currTime - lastTime))
- g3 b% T' O" f- ^ const id = window.setTimeout(() => {7 S0 E7 }6 [ A( g
callback(currTime + timeToCall)
! W# |$ }$ Q) h9 L) W) d }, timeToCall)5 m/ e9 `4 X% D( p u0 \+ q
lastTime = currTime + timeToCall
) G7 [& M3 G3 H7 J8 Z3 O8 E2 | return id
, V s e4 [( d# k! W3 e" ] }
! a. A n: H& D# ]2 A2 m
7 S6 W% L9 J4 F' R! F: ^: f cancelAnimationFrame = function (id) {
: h0 j2 L1 a- R, _& n window.clearTimeout(id)6 v% M9 B$ p* u2 g& J" z$ D6 f
}
1 D6 m& t: ]- y. \ }
7 z: j4 t, [* j! i: G
- o6 x& @6 \9 X4 }17 K8 \7 z& r7 m6 Y8 B6 }, w
2' G" ~ J3 Q0 q$ y7 ]" I
3& d# T! |) i) ?! t4 h5 m
4+ m+ F, `- @; p8 |9 A$ @
5
$ n/ ~; {, K/ f6
# [4 f( L; [$ t& h R' c: M7 m7' y6 r5 N) q4 p9 T( D" o* L
8, g' a! C- r9 o
95 G) Q; f T% _, Q$ L& [% g$ k9 q
10, z/ h J0 k: n' g5 v5 ^: I
11; K/ h7 N' y9 D7 N1 J2 J6 A/ ?
12% `5 n- b7 R7 j9 H( @- u: X
13' i3 _2 d! O7 x6 m4 f( X
14
0 g: b3 O& T0 |+ \15, v# r* \# a& M t% J! m" {0 a
16' K9 w+ b3 K6 @) ?
179 ~/ }6 l; o: N1 y5 x- [
18
4 x; | E! w" T- V7 B+ J+ \( N19
3 C/ k K, m1 y# a: u; g20
/ t8 c" M+ ~, h4 |6 g21/ U2 S X& U/ \1 b$ I
22
" R) Y2 N2 Z! p5 U8 l; z6 g+ f# s23
3 r% f" M, l' T# d' W24- y7 Z x; U- W
25. B4 G( ^" I- c$ Z
262 ?' o+ O- M- D4 B6 U6 J
27
9 ~# W" s/ z0 l( r+ X28
4 H. S( {' L. r4 x8 e0 o: p: Q292 E" _- o1 [) s1 \
30
% b; P/ D8 j" k7 |1 \$ D31
: N1 c' }. A% e, U323 j* P" z; [ N2 O# f, L. k
完整代码:
c+ S6 c& ^& ?requestAnimationFrame.js
4 _1 S5 r. F* ]
+ |/ y3 H. C e$ U1 V4 Vlet lastTime = 0
1 }4 H: G, a$ l9 \& y. _const prefixes = 'webkit moz ms o'.split(' ') // 各浏览器前缀- W x( w6 y- Z9 N* ~, w
' R! j- ~; T o2 U5 p! X0 W- l4 q
let requestAnimationFrame
5 q( R. G* v! s2 P1 elet cancelAnimationFrame
% W# s; f V4 C0 e% Q! g3 |
# h/ Z- B7 z# a/ x6 M// 判断是否是服务器环境$ n1 ~8 b4 j2 Q3 c
const isServer = typeof window === 'undefined'; u* G: ~3 a0 y4 b3 c! o
if (isServer) {
6 \; i7 S6 r! a( O5 n8 _ requestAnimationFrame = function () {8 H1 D' t5 Z7 t8 x$ h: w8 u, N
return- C+ e5 E/ B2 Q+ m; Q# R$ B" O
}; d( n& p s% g
cancelAnimationFrame = function () {" v; ~# n$ a% t( ^9 O. |9 {
return
' J8 y/ J( K9 h: a2 p, ~ }
, P, E6 d7 x$ ?; f. A, d( c} else {1 ~9 D! M4 }4 b0 |; d+ {
requestAnimationFrame = window.requestAnimationFrame
! ?: l- V5 d8 V+ C) {, w1 X' K2 ~. r cancelAnimationFrame = window.cancelAnimationFrame: ~8 h! U7 y# k( @% s# O3 l; b1 v
let prefix/ j' b; Z! d; q- W3 R4 s, }! b
// 通过遍历各浏览器前缀,来得到requestAnimationFrame和cancelAnimationFrame在当前浏览器的实现形式
3 n1 f# |' ]3 J" |$ \# o# u for (let i = 0; i < prefixes.length; i++) {' @$ A# ~5 [! q# W3 W. P
if (requestAnimationFrame && cancelAnimationFrame) { break }
9 {5 }3 j9 {# q" A* x prefix = prefixes4 m2 U2 ^7 _# F/ k7 {7 a0 w
requestAnimationFrame = requestAnimationFrame || window[prefix + 'RequestAnimationFrame']
+ K9 b; K8 G3 c3 ]& ~/ e c cancelAnimationFrame = cancelAnimationFrame || window[prefix + 'CancelAnimationFrame'] || window[prefix + 'CancelRequestAnimationFrame'], H5 G$ \7 h! b0 I9 `) \1 V
}. m' u( H6 `6 |8 ]. ?$ j- w7 E2 i
: ~' h, T9 ?0 a7 Z& y; f
// 如果当前浏览器不支持requestAnimationFrame和cancelAnimationFrame,则会退到setTimeout# B1 X4 w/ c6 x) ?" _
if (!requestAnimationFrame || !cancelAnimationFrame) {
9 Q+ N4 M! D5 M- ~ requestAnimationFrame = function (callback) {1 P3 a: ?, W. I9 j5 w* V2 d# i7 q
const currTime = new Date().getTime()
. ?5 ]# e' o. \ // 为了使setTimteout的尽可能的接近每秒60帧的效果
$ O# c: m6 D$ J8 Y; |5 a9 F! L const timeToCall = Math.max(0, 16 - (currTime - lastTime))3 v& ~- ~. T( K' @' y! {4 k, a2 p
const id = window.setTimeout(() => {
, ^% V' Q" J1 f# y8 u callback(currTime + timeToCall)1 C* r* k. z* G# e( n
}, timeToCall)
* S# I( t- u }* B9 h lastTime = currTime + timeToCall1 l( @- J% s3 f6 N( P! d8 k- `* S
return id
: ?! C q8 {' |! a0 d! f }: z) D" Y( F# l( o& B, C7 W
l6 A' c- g4 ?/ ^0 V d
cancelAnimationFrame = function (id) {, a0 D( d3 _. h8 a! ^
window.clearTimeout(id)
+ v" i- S! L; H- ?" { }
|8 X) k3 y; ~. m% R! y }
8 d2 M+ ?0 f# ], |}( F6 N4 `. N2 u0 v8 ?; w3 S. P
: A" H! u5 Z3 @+ H; @' q: `export { requestAnimationFrame, cancelAnimationFrame }
+ _6 { x! E) d/ f) t
8 i1 } J% O8 Z# f: Z2 I7 [# i. X) {$ ?3 K
1- Q- `4 N7 { o9 @
2+ j2 [1 d) I3 L, q# M
3( a, N5 b1 w" I* {. X! i
4/ L9 O# k' j5 {
5- [( a3 ?; u+ N9 x; S3 [# d
6
5 `! y% c" Y1 C: l: [7" t! G3 f2 n" k5 d: v; W
8
; T) H6 s* ^+ c$ q% Y' G4 w96 L( l% {) I$ }& t
10/ E( ]+ B, z: K8 J" F
11
/ p2 G8 e. C* i' n2 p12 {6 m, N& n9 q! _
13
& f- y ^) D+ A: H( B8 p: V3 v14' @' _+ ?! G" i( y, B+ J
150 r! H! E1 t5 X' V' X
16
$ S- X5 B3 y$ ~7 [ P17+ c& c8 R) ]4 {& ~! S# {& h& r
189 k; u4 G0 n) E$ Y6 s/ u6 t/ d0 ]3 q; Q
199 z" V. o3 o9 E' \
20
: W' r8 T2 r, c I4 P7 ]9 d/ p21+ `% E6 h6 Q5 b
22
+ {0 t3 G* @" w4 w- t23
& q' F* o; L2 L. L0 M! A. k24
# L2 O7 |4 x( N5 |# o1 k; ]: ^% F25
5 a) Y: k4 @" p& s. G: X261 g x8 A' O9 E5 ?9 K7 C# D6 N
27
1 b5 R7 }0 n6 u; e a$ t28: q3 }4 Z3 N+ @5 o- F) ^
29) f6 \6 m2 l( @+ M% W7 d0 A
30
: q u6 l, C2 n: d9 o31
1 j$ n6 S; y7 \4 m% v2 w. [3 e32
0 k$ r) y$ u, {' _33
, y6 d! X; J5 l( M4 H! c34+ j0 Z$ y4 u2 f& u9 \# y
35) S6 s8 |" t# ]5 e( @8 ?
361 l6 M2 \6 c! K' }1 V
370 z2 A. n0 V# Z; V% a6 ^7 n
38
3 h7 A! Y9 ]1 h. P0 X3 k8 B& @39
) i0 J, i4 R) v. f: F+ a407 B! w- \5 N( A6 L6 X
41
5 C* O+ W0 _7 ]* }42
8 {! s7 T" @1 b* i9 D: E) ?; K43
3 r \, ~8 x; ]/ t$ }% D44/ O; Z" ~$ M- t9 `' x1 F/ s
451 s, w$ J! U" H
46. u m% I( v0 j& n. u# p! ^3 G
47
$ A: J4 j+ v1 }& h Z48) q7 I) M( N; [( H
CountTo.vue组件思路
: K6 k% h# i8 V2 B6 H2 o7 g8 N% V首先引入requestAnimationFrame.js,使用requestAnimationFrame方法接受count函数,还需要格式化数字,进行正则表达式转换,返回我们想要的数据格式。
, {* e1 u7 X- n& j0 P9 p
& W! L1 U, j5 `, b F" r) b引入 import { requestAnimationFrame, cancelAnimationFrame } from './requestAnimationFrame.js'
W9 t/ t$ n3 |10 @- x( Q- |* v4 @
需要接受的参数:1 q) d2 v( Z- ?0 e) q8 f5 \
4 s! I% Q5 Y) sconst props = defineProps({
M$ ?" O- L O' c) z8 j start: {: f9 w5 E4 ?+ I" k
type: Number,
S+ I7 X, U6 y# W' ^1 j. Y3 g d required: false,
, Q; [( Z+ g5 N5 w default: 0
" q/ V& {2 F4 N# u/ h; G0 { },# q9 m- ]6 N* ^! S
end: {
. e$ d. Y+ M1 z: U% a( V" r+ p type: Number,! q$ n9 ~- o! W
required: false,
1 i/ B8 |6 V, L/ a% P. Z' u+ _, `+ t default: 0
. f0 k1 U, Y$ u! x5 y },0 I7 l) L3 d6 J5 ]
duration: {' n8 {# A! }$ q! W( O0 R
type: Number,
, Q# ?; q; w/ T4 a required: false,
2 z8 a \9 f! g# r default: 5000
- t" u7 R* W: g) A7 M },) m; R G# Q. c7 W. ]5 n% w2 G7 |& G
autoPlay: {
: h5 q" F4 L7 C7 ?( i* }% M type: Boolean,
! }8 u5 M. Y( V4 N& G6 w required: false,
6 c1 f7 R" A9 F0 q) d default: true
) G; m" N5 R: I2 d8 m: {& g& z },
' r* d# T. C; U5 X) x; ? decimals: {
( W# u _6 k$ A/ Z type: Number,
+ x' ]# J/ {' M# p' B required: false,
% H# b5 a, o# i6 |* I default: 0,9 h, h1 y) B7 }7 s
validator (value) {- C; o7 f6 k" d1 @8 H& [
return value >= 0
. Y( O2 t% M, e1 H }; h7 y3 U& z' I
},
q: b7 q( Y* W& l& A: [) k- m decimal: {
8 C A2 v9 C: H$ C# ~' E type: String,
3 ]% o% G: d$ t9 S$ I9 a: J1 q. t% P required: false,
( Y- S# k+ D, w default: '.'
& {9 x# t d9 }% O4 W5 v0 d },
* X7 r( D+ L- V separator: {! B2 b5 W% {" D# I
type: String,8 F; {2 Y+ P9 ?" w% z# B
required: false,
7 M/ Z1 M/ D6 `; u8 u default: ','
! A, o9 ]- {2 N6 n/ W: p4 E },1 W7 {/ y7 b }" H7 d7 g
prefix: {
1 B+ _7 s* h* M8 {+ q$ U6 A6 z type: String,' K) U8 x7 R+ }% G7 Y h4 x
required: false,
& H* z, @2 R% O0 W, c default: ''" F6 X/ t; J6 E. Q' o; Y
},
4 s: f0 C: R1 Y9 \ w$ q suffix: {
( h* v# i! p6 L0 X1 s! W" ?0 i type: String,
5 P! y/ J6 y. K8 C3 D) @ required: false,& X3 ~6 i+ X5 ]3 M8 u h
default: ''2 G) |0 E1 g( P
},
* l0 @1 c$ V. f1 r* R8 g7 |* k" K useEasing: {& O! _1 M$ Q; x/ v8 g; E" B
type: Boolean,9 S- ?7 U, x4 P) M. t1 V& r
required: false,
( X& t. X9 a0 Y Z default: true8 Y+ N2 L0 R7 p4 u8 k' j* J
},
. \% K) K" p; W! p* L' e( V easingFn: {
6 G+ W( Q% S5 b' S* |7 ?# P! f2 l type: Function, d7 o& r4 |: Z# @2 q9 } H
default(t, b, c, d) {, Y% `# X: U: D: m
return c * (-Math.pow(2, -10 * t / d) + 1) * 1024 / 1023 + b;; B( j. [+ E6 L5 t& K6 K) E2 ?
}! g/ u6 b4 j1 A0 x
}
9 G0 f1 N% c7 m' w+ A1 Q})
0 b( y& _. {% R; w
& d6 z/ y& q5 {) X8 g9 h4 X, r" j
1
6 G6 H7 _3 T( N6 t+ E2, q" O* r# W( `' y7 J3 o# k
3: r/ w1 O. g L7 |. \/ |+ \
4! K& e5 {1 P6 \- T# m- |* z
5
+ b2 z2 M2 k& R7 F6 O5 {6
, k& X/ I3 r2 { u7 M7
$ E& `! d& h# k1 C2 a- R83 V" F7 c2 j/ \9 u
9
. H5 J7 P$ _, g8 Y4 p1 \! g: C/ ]101 |1 K! I9 t2 S" Q; ?8 |
11" A8 w3 w: t. G9 ~
12
% q7 U* p, E! J; Y0 N9 j3 J13
8 X# W2 Q8 h+ Q( |14
/ N) ~4 o7 P) C' ]15: Z) f$ w% `9 Z! s/ C. \
16
: N) m0 k+ a# Y- R' d2 N17
. o% s8 Q* t; H. B2 |3 a18- a& w& r; [% y0 C0 `
19
: @: B* q C+ Q% A. D20& Z* q- [0 `% E0 R& U, s9 c* |
21+ E \7 Q. h; x/ \9 m: B: ?7 u
22
0 {! W M0 O; l" _23
" T! v8 j$ r9 {3 p( n24$ {' @* {$ N$ _6 K0 {! w8 x5 Q
25( [, x- j8 C3 C# R9 A7 ]" D
26. J3 f0 r. M( T
27
" |. L4 n0 y7 {% c3 a& c [2 i6 z28! E0 L7 x" a. K3 @! M
29
, a/ p! n& h0 d& S, o0 N" N/ E300 y' U! b8 p& L# j
31! P }! c8 }) d( ^
32
% t* R# m1 i" V# _* `; n% M33
0 {6 y) u4 R- P34
& C# l( [4 T$ B, \8 ]. w35
% f8 r1 O, h: Z9 t) c36
/ S: D# p- I& _! H37- W- e, _$ i/ |, k2 o! P; ~
38/ a) u# f. r7 v" {6 C, P% m( T
399 j ]7 |6 H% A1 P4 z: m
40* T; K+ ^1 i8 G' @
41! j1 r# u- l5 Z9 n
42) c: m( N+ q7 r" I/ n/ G2 c/ c; z, u8 a
430 q! K# X+ l2 O3 C* z9 g
44
2 \1 P' F! {5 A w7 `" Y7 g45
7 X2 y2 f+ w {; i- j46
5 Z! A1 _. k8 V47( ]% n" c4 V1 I
48
& R- R% a+ D \; J! \, a- A; k. A49$ m# s( r, i/ g% W5 g
50
0 ]" C3 Q. T% d7 Z0 m- _; v51# n; Y; p: [8 U5 R' b9 j
520 m- |/ n* i) Y7 v) Y3 l/ R1 d
53
2 g/ q' R' X! Z- ?# G+ [0 T542 k# a6 F9 P! l
55+ F: n* J1 Y- [; f) F4 J
563 P" K/ l! V+ q/ h
57
) s: K. R: M8 v1 n3 \58
7 f0 o8 ^4 N0 b2 v& v* Z591 s) Y1 C6 @7 L8 y; o2 T
60
1 {3 g5 H) d F" |. k% O61, V1 I' S* P s. O' w& i0 u8 m, b
62
" y8 U7 m) b/ X; j/ _1 x2 k0 m' S启动数字动效
& F* C6 B1 x+ @( Q* H& q) h5 V5 o, P+ o% |$ l% N$ @! T
const startCount = () => {( u5 `7 a2 U6 x1 l; y; J
state.localStart = props.start
7 B; |* q. Q. P2 S. }' n7 ^7 G state.startTime = null& g: n6 {) e0 Q2 I/ f( P. z) Y
state.localDuration = props.duration6 y# f& A# H* y3 N( l8 W% @. E9 e
state.paused = false
* G3 e# X0 G4 ^; e$ e1 A state.rAF = requestAnimationFrame(count)
; r+ H3 v \; q9 I4 l0 p p+ c}4 z8 \4 P+ Q A1 {5 a: y! A9 U5 B; B
1
- Y% u: v- l) I( @) m- m, m2
! o1 B( o1 G9 z% y; \3
p3 m' q! l3 U5 G4
" y1 _$ z$ y9 X! E( @& e! z! F5; p1 x" Y8 y7 v$ B5 Z
64 i! q% l+ ?1 Z7 K4 M T
7
! n6 X, F" y! a1 m, s/ M核心函数,对数字进行转动
3 n. ~% R2 v. Y7 ~! d. ^8 G) C1 }3 r- Y7 w0 |( G" a# y1 K
if (!state.startTime) state.startTime = timestamp
/ [, c: n2 l6 C2 D% o# Q state.timestamp = timestamp
' i- B" \5 D+ h% A2 n3 b: w const progress = timestamp - state.startTime0 f0 R9 i, P7 {7 R. {! V) g- j
state.remaining = state.localDuration - progress2 |1 \. f( E A$ w, `7 U
// 是否使用速度变化曲线- L/ F$ [$ u+ O! o( Y( N; c. G8 E
if (props.useEasing) {
& Y8 H# ^" `$ a# C* Q if (stopCount.value) {
" X5 k! z5 h6 Y" y state.printVal = state.localStart - props.easingFn(progress, 0, state.localStart - props.end, state.localDuration)
8 w. [- B* P" {4 e, p& n) f } else {& d4 k" C% F3 {( Y4 F7 U
state.printVal = props.easingFn(progress, state.localStart, props.end - state.localStart, state.localDuration)/ ^7 I4 ]' j* U2 {7 s, e8 ^
}
4 C& g8 N; o; Q0 Y } else {3 d; }! v$ O! P0 X
if (stopCount.value) {" |4 _9 Z, _" F& n/ d# D- n% F
state.printVal = state.localStart - ((state.localStart - props.end) * (progress / state.localDuration))
# a3 |- _' |3 [8 k S } else {
. P' `9 g' J$ L! S8 c state.printVal = state.localStart + (props.end - state.localStart) * (progress / state.localDuration)
' e; m) z4 u) q$ N9 ]* [" o }
& |1 w6 b8 V/ g, x+ y! I }
; z- m3 Y% Z P2 I if (stopCount.value) {& V$ s, V* y' d2 A) S# e
state.printVal = state.printVal < props.end ? props.end : state.printVal
9 j ]4 o4 R: A+ n- Q- t7 k* }3 k. c7 q } else {- W; K9 M2 R% z2 o) @
state.printVal = state.printVal > props.end ? props.end : state.printVal. A7 t. Q# N; r+ J# o. o$ j
}5 j: b$ Q! o* M2 n
! Z3 D4 x4 C$ U1 i+ U
state.displayValue = formatNumber(state.printVal)
" t1 z3 ?, N9 R2 s6 L( g if (progress < state.localDuration) {0 J3 s1 x3 M3 f+ |+ A' _. [$ @
state.rAF = requestAnimationFrame(count)" w' a5 r n v2 j/ S2 Z2 L. u
} else {
* R: k) i8 y; P0 g [' A. m emits('callback')
0 F2 s. g1 A$ D+ L7 \ }/ `7 p, u7 m5 \/ a8 Y- h) {
}) C# [2 R. q% J. |7 C/ R
$ [; N" |$ f, E! i+ w
9 s# q" Q+ z* D9 n# n// 格式化数据,返回想要展示的数据格式
' F/ u4 a U& g8 H# M6 `, sconst formatNumber = (val) => {' Y7 K- n: [0 @5 v
val = val.toFixed(props.default)+ b" J7 y, c- t a. V
val += ''" H+ A1 ^- e0 _! `$ u! }5 G! c* D
const x = val.split('.')1 d K6 D& G1 w' S7 s3 ?$ @
let x1 = x[0]. }' R( ]) V5 u+ z
const x2 = x.length > 1 ? props.decimal + x[1] : ''
# \" n( C/ ?& I0 | const rgx = /(\d+)(\d{3})/% w/ S2 \# a8 y1 H+ f: `
if (props.separator && !isNumber(props.separator)) {1 G/ v8 m. f" T8 j. p- M
while (rgx.test(x1)) {6 D: Q) i' m3 M. a& E7 \3 F: A
x1 = x1.replace(rgx, '$1' + props.separator + '$2')2 T9 V8 U( [4 ]5 J6 `" x: e. x
}- \5 E0 U% ^; `% l. a* M; o
}; p8 j- v& F+ ~8 \- ]- x
return props.prefix + x1 + x2 + props.suffix2 q% Z h/ o6 N
}1 v2 Q4 K6 x& N/ {4 T3 a2 H9 V) R
: y. k2 o" c6 t( M: o
1
* q* W, M7 K% P" N9 G8 k* L; y2
& P+ I. Z" y- W& s3 G3* g& F) G- l( Q( n
4
; F; P) p# h' r- n57 @$ t, S: t5 B3 J. C# l
6* s3 `3 F3 }$ x8 S
7! j2 F2 t& c( P8 t( ]- z: k
85 e# h4 V% Q2 y2 Q$ P9 h2 j9 V/ \
9/ J7 X$ g" q( V0 o
10
* _: {3 B# h: N$ b# c6 d% [11
; E" [, ~+ E; B12
1 Z4 r1 W/ o+ _9 ?. z3 O' T13
8 n T0 s! O9 ?4 S' w14
P2 d# y2 G5 O% V! {" c15
) m# s! y) _; c, o; S' e3 _168 I! H, ?3 P! d# ^1 k) |
17
& y" K h2 v0 X6 L18
: w6 z' n5 r8 S+ C2 y, }8 z) s19
1 R+ i$ h% O+ b& i* `3 C( L- n20% v% h7 c: D u: s- w
21% y, Y6 s: ^4 u
22
! u/ M/ G( S, g* R. e5 l+ h* e23
1 E8 ^. b9 l, c) F" k8 ?1 p24 v3 B1 I- l( [" q
25
$ s9 c, F8 R7 [6 q7 H" ?5 a6 ~26
- B$ z6 b9 N, D; C/ V27
9 s5 K% N( {. I, N, w28
' ~: m& [; o' L, c b3 ?- U29) X9 @5 J9 G# r1 H
301 }, A4 }: w! Z9 t) Q7 X
318 i1 P3 `9 e0 h9 H* S3 M2 F
32
$ n' n; e* k3 P. [7 |% k: u33# e- o' {1 F; a/ C% o' b# r, I
34
! \) D- e& b# }, j351 q) ~4 D. D. u% Q. J! a( s
36
/ Q4 S9 F% Z- h* t: x% U371 n" d) c# b- ]" v
383 X7 E: ?1 R6 a3 ?& }* c
39
) X) Z0 @- @5 T1 K8 i+ U1 J402 t! n- p, U% m/ W0 S# C
41
! ?% o2 Y0 x/ R1 g42: @' ]2 c) V! q8 J& m
431 ^ P% C6 U U- z% c
44
: Q) m9 t% t5 b6 n45
- H3 M) m; ?8 V% q# q) u46
9 w# i: G, J, s: P( L4 J47 `8 F0 [9 P2 d f' U
48' V( i( J6 A8 M) [0 h
取消动效8 _* ^. v1 J }6 Y, P# s
" ] t4 F1 l! i8 \' v
// 组件销毁时取消动画% R( {2 H3 N' K2 z% G' d7 O
onUnmounted(() => {
3 q) I% z' Y" u0 q5 g/ b4 w( C) r cancelAnimationFrame(state.rAF) S8 D) |, m0 P9 ~
})
. B [+ H0 U" O H. l, _1
. J; E/ H5 m- b" R8 W3 E. x: d2
2 G( ?1 M) s# [! A! G$ H3
! ?' z! z3 @" o. A) K3 P7 \4, ]% x8 D8 [8 i* s# P2 y
完整代码
. |7 j8 Z7 b* G) x- M
* Z% K" H7 v2 e f2 [<template>0 F7 q: q8 a$ A9 C* Q
{{ state.displayValue }}' a, c0 d j& ~, t9 K" ?
</template>
2 k+ e# u" B' M; i% q) T: o% X h2 N( ^3 V* Q
<script setup> // vue3.2新的语法糖, 编写代码更加简洁高效
6 w& F7 x, s1 J+ yimport { onMounted, onUnmounted, reactive } from "@vue/runtime-core";
% Z, n5 G; `; a ]) dimport { watch, computed } from 'vue';7 L r9 T$ V) U$ u- J
import { requestAnimationFrame, cancelAnimationFrame } from './requestAnimationFrame.js'
8 R4 I% L" S$ j- H2 Q. }% Z: ~2 t// 定义父组件传递的参数. i# r$ a4 ?9 w) [
const props = defineProps({
' {- X* |+ w) ?, i start: {
b: y; ]8 }7 Q7 z% { type: Number,5 u/ p0 h( f4 K, I/ e0 f
required: false,
- G. [9 C; u5 `5 t: N7 C0 H default: 0( ?5 n1 S' A) }
},$ o# L! W1 T& W8 \% l+ M& i
end: {
5 X9 F+ g {0 Z3 r type: Number,
- b' x$ r3 c/ \ required: false,
- [5 A! w! b6 a8 I$ O( m) u default: 0
8 Q* _7 a' ], g) V9 d },
+ O' H6 K. S$ x5 w1 v" `5 V/ z duration: {
" x, P4 o. @5 i. P4 S type: Number,6 N; I8 H; C# k N$ n+ [3 O) n4 c
required: false,
4 O0 {& ^1 K9 O# p* N& ^ default: 5000& }! Y" F6 h* b1 }: R$ r4 o. `/ m' y
},
$ q+ t5 E/ C4 F! D! ~ autoPlay: {7 Z3 M% {# i! [8 Y; a0 z, E
type: Boolean,
3 [1 M0 W% P2 g7 A required: false,
9 e$ K" k% E" f8 m* Z: B default: true
5 Z# X" r4 U- ^/ a" T },
; [" E9 A3 }" X decimals: {; Q* R* ^" v' W; |8 _7 ?
type: Number,
3 M R3 S5 Q( h) ~ required: false,- t4 U ]: m0 e; Q
default: 0,
) v$ i A( }+ t validator (value) {
) f5 \8 z2 T$ ^7 N/ O# u return value >= 0$ }$ X( }( a) @; J+ y) I. ?
}
$ m7 t( \! d- Z( C },' ~3 J# [: g# F! M7 |! [4 C7 m1 V
decimal: {+ E' w) O1 i) r
type: String,
+ \0 s3 J# O6 J6 z" a' C# K3 T1 b required: false,1 i2 A5 r( Q4 {
default: '.'% _% V! h& X* y0 o2 y2 y
},
- F& e0 [3 t- s( u separator: {
& M" R1 `5 P: ^+ }4 M2 R8 [ type: String,
5 J8 y6 e: p( h; Q required: false,6 I* S, N- j; b r1 G# c
default: ','* w5 T8 F, @. z" |
},+ l% q# D, q! I% ?; D" B
prefix: {( [7 M( }. I5 k) p) l& n! \3 ]
type: String,
( W. e8 r3 ?: d& M- S required: false,
# F8 Q- E7 D: s7 u4 T default: ''
4 T+ l7 l4 V+ q+ z6 x },
* Y3 u2 l% H1 X1 D R- g8 I suffix: {0 H* n8 o& i+ R) I; W- k+ N, ]5 X
type: String,
z4 ^! u' m9 K7 G8 L1 g# Z required: false,
- {. `4 e& C* v+ M- w4 G default: ''
# T3 l7 p. q6 X$ |% D! ` },
5 C5 ?& |0 X; Z- C3 y' T useEasing: {
% J% c3 o$ o9 N. V3 K4 N$ B7 c8 ~ type: Boolean,- F U* @2 w1 A. n- A
required: false,1 E- [3 ^, E: v% S7 V, L& d
default: true
) R+ U; P; M$ {$ w },
( V/ {+ l( g5 n O4 m- r easingFn: {
. z K# Z9 a# M3 q8 `$ S type: Function,% w) m* F- Z9 ` a0 v8 e' J
default(t, b, c, d) {0 r: F3 i/ U0 ~ c( X' C3 L
return c * (-Math.pow(2, -10 * t / d) + 1) * 1024 / 1023 + b;* T5 d* ~+ |% [( l* W6 b, o9 [* a
}* N$ _' p% Y2 X T
}
( `$ s+ g* d* N$ E! M})2 b3 j9 u8 j/ z& t- g9 q
& H8 B8 p4 C- q: y/ r8 q
const isNumber = (val) => {
! e/ C4 I+ Y7 g) s: _5 X) i9 j* Y4 M return !isNaN(parseFloat(val))9 n( K1 u2 `7 J2 U) B
}+ y6 I* }: {; \8 d
% P& ?& q. U5 p# M
// 格式化数据,返回想要展示的数据格式
- D' g6 [9 s c# Lconst formatNumber = (val) => {- L) L0 l) k2 d8 W/ }9 E! J
val = val.toFixed(props.default)
- h n; q f5 ?7 L3 S val += ''6 v4 t/ E& U& |4 [0 I0 |# Z
const x = val.split('.')
0 i: p2 R# j0 J let x1 = x[0]
! `" O; P) w" P; _0 L, b const x2 = x.length > 1 ? props.decimal + x[1] : ''
. x$ ~ P b- B4 o$ H6 { const rgx = /(\d+)(\d{3})/
7 m d$ U/ Z' S- Z" {2 }9 l if (props.separator && !isNumber(props.separator)) {3 ^) Y! D7 r' |$ J* c( p
while (rgx.test(x1)) {
& R6 D4 i. k; Z: i) O+ S$ |) | M; Z x1 = x1.replace(rgx, '$1' + props.separator + '$2')+ |( h$ i; S2 F. J: @/ b5 y% c
}
) z: i! J7 ~* f+ ~ }
2 M: }* [0 A, g return props.prefix + x1 + x2 + props.suffix
+ f5 Y0 q; O) j}! N2 E% c) I9 D1 G
; y; Z. w: Q! ]; `2 x# R% q
// 相当于vue2中的data中所定义的变量部分. V# U/ W( X" I+ ~
const state = reactive({
. I9 v* U6 K% ?" Q. }2 b localStart: props.start,- y) s4 w6 Q& u/ j( p) @0 N- F
displayValue: formatNumber(props.start),
; K% p* f7 S; Z8 f0 V7 u3 ]; [ printVal: null,
; S; ]& ?4 J7 r# f- w3 J paused: false,
$ N+ N; [$ n w9 P |9 O0 z localDuration: props.duration,
8 r& G; G7 r+ G& X startTime: null,& z- e- }1 i3 p2 L; E3 W
timestamp: null,1 \( N4 P1 V6 m# E. \* E6 @: o
remaining: null,
7 W' r) H( M$ P/ ?' l; { r rAF: null# u* ^$ J' t6 A/ E
})
& F' X) g: h5 ^+ H% L( z: i/ d2 |( S6 A( }. `4 D1 Z
// 定义一个计算属性,当开始数字大于结束数字时返回true
/ @9 g3 d5 @1 \/ `/ Dconst stopCount = computed(() => {
1 y$ }( v& E8 Y) h } d return props.start > props.end; E* I. \6 K, L' ]- `5 g8 j/ O
})/ K V3 r6 i3 B j# B# ]
// 定义父组件的自定义事件,子组件以触发父组件的自定义事件
0 p+ W! k6 w0 b* y" g; y- ^const emits = defineEmits(['onMountedcallback', 'callback'])
& f1 J0 D) S6 H! E
) V" q( P: {, ~2 n0 o! L" i( lconst startCount = () => {
7 k9 ]8 U" h( e7 @( w' Y state.localStart = props.start* ~- C7 p# H1 X7 N8 ~- W0 V$ c: G
state.startTime = null
/ ^( ?8 i7 j4 Z4 H5 m2 H state.localDuration = props.duration1 ?* H$ C+ b2 H+ H! D
state.paused = false; G8 G8 t) l3 S/ f& P
state.rAF = requestAnimationFrame(count)
3 I; e2 ~) p; i5 W! M) T. O0 `}" X( H5 d7 x* |1 ~& Z( B/ m( J
( W3 A2 i8 I. C) @
watch(() => props.start, () => {
, g: b2 Q. M" P9 n if (props.autoPlay) {
1 P5 K' O& v( d3 V startCount()) c% p! `- S( G1 P% e
}
1 o2 a! M4 ]( V [})
+ {" r5 h4 x) C! s8 u7 o# T. g, K! n& ]: l
watch(() => props.end, () => {7 Z# y1 m6 C& B$ ?
if (props.autoPlay) {
5 D% R$ A c" e% h, F startCount()1 ]9 `' R' G; X7 f
}5 P! b8 H; o3 K7 y( S7 G# l& D$ U
})/ ~) [7 B0 m4 W `5 C- }: D
// dom挂在完成后执行一些操作
; O" @4 w6 @7 T. konMounted(() => {
; ?2 v* }( }6 `$ y+ K6 s4 w7 f- d if (props.autoPlay) {1 |- z: a* [1 o" u E0 a3 J7 r9 `
startCount()
6 c$ K* A% q6 y* V }
0 \& X! H+ n! d; U8 Z emits('onMountedcallback') J- b8 F) e/ K9 }: c2 i" v+ A
}) G$ f- r, C2 J4 A1 x
// 暂停计数
+ U' E" ^2 L) E; K2 gconst pause = () => {
" q1 h+ F5 n j' P/ |, z cancelAnimationFrame(state.rAF)
: d; _ U3 `4 j) {$ I}, E7 X* q( Q' P1 `7 H
// 恢复计数" o: I$ J1 F) ]$ Q
const resume = () => {( P. L: r4 C) q+ S, [% v
state.startTime = null$ G) W9 O: m) o5 ]8 L1 \, x8 k+ @
state.localDuration = +state.remaining
% V1 J* D. R7 |2 @1 A! N state.localStart = +state.printVal
, f) Z7 [) `* S requestAnimationFrame(count)
5 g: X" Q0 \1 m6 `$ d}9 p9 M/ G& V2 s4 U6 x- M% l
5 | }. [9 Q) Y. H6 Rconst pauseResume = () => {
; L% |* _' M" w4 P0 N& R) S4 w if (state.paused) {
5 K2 d* k3 K3 d! t u resume()9 l' x! h, X `3 q3 R
state.paused = false
) I' P/ _, L+ c5 Z } else {
% ^ M. p3 U- K: _+ M pause()! S8 B6 L% L p
state.paused = true
& u' l8 `+ R" M! U+ g3 {, u }
; E" M o5 K% k}! p4 U/ f/ [, a
8 c, a0 j: F+ [& Bconst reset = () => {
: O( j9 r& T$ J3 z: V0 Q E state.startTime = null; O9 `1 ?1 B+ z6 I |
cancelAnimationFrame(state.rAF)% n0 t, r6 R7 }
state.displayValue = formatNumber(props.start)
2 f, z) Q+ f; b}0 a3 t+ J6 }3 Q& V& Q, g' ^- d
( i, K* i- s. O4 j' ]const count = (timestamp) => {4 H- g: |- c2 M* j
if (!state.startTime) state.startTime = timestamp
6 q% G: ]& U6 B* `- d" b state.timestamp = timestamp
& O9 R0 w. q5 h1 P const progress = timestamp - state.startTime
, G7 M5 _! Q" p+ b$ a0 r; r state.remaining = state.localDuration - progress
2 K1 U) V+ C9 P // 是否使用速度变化曲线' ~6 X; v( t& M
if (props.useEasing) {8 \( {; i& U0 x" M' v8 P p
if (stopCount.value) {
8 @' v c0 ^; E/ M0 m [ state.printVal = state.localStart - props.easingFn(progress, 0, state.localStart - props.end, state.localDuration)" ^( R0 H, M F1 m
} else {
! U |7 T: y5 Z7 K0 b state.printVal = props.easingFn(progress, state.localStart, props.end - state.localStart, state.localDuration)
8 s$ B; C1 i6 W } N; P# z: k/ p# a$ h! }
} else {" ^+ `2 {" {% @5 C, O
if (stopCount.value) {
; I" A I2 o* D3 G y" m0 W state.printVal = state.localStart - ((state.localStart - props.end) * (progress / state.localDuration))
% `* B- ~: `9 F+ A } else {% b$ z7 M$ t: a( n% e
state.printVal = state.localStart + (props.end - state.localStart) * (progress / state.localDuration)
; Y+ c% z# @, u8 b; N1 |& B }
* v. e. ~; p n7 {( B2 R }
! n0 ^' \5 `6 F* K7 [! X if (stopCount.value) {
# v9 @$ I5 n5 [ state.printVal = state.printVal < props.end ? props.end : state.printVal& i( Z) l C8 S- J* q, [2 l0 l' V
} else {5 }( R6 K3 z( J# Z, `: K! Y6 X
state.printVal = state.printVal > props.end ? props.end : state.printVal+ F' i' z$ z5 u6 E0 }9 \
}3 v1 k3 P6 v" U
, r; `. y7 { i, G state.displayValue = formatNumber(state.printVal): D/ n# N' f* ^1 f
if (progress < state.localDuration) {8 F! O' [8 v! S) A N
state.rAF = requestAnimationFrame(count)
0 ~1 W/ u4 w, s+ r3 e9 v } else {
T. a0 E- a* Y7 ^1 j ^ emits('callback')( d8 C9 e! i7 i4 f8 v5 g0 n0 r
}
0 y: z) r& x, v) K( Q& R! d}9 E0 z5 Z) k) \ n- B: ^8 [9 Y2 e4 ^
// 组件销毁时取消动画* x$ t0 S4 z+ ^- h1 @
onUnmounted(() => {0 c, k+ Y0 `) D" M% b4 z$ B
cancelAnimationFrame(state.rAF)
M/ O2 N3 [% j$ W; m/ C( V8 R: s% r})
, R# _2 P1 p7 I0 N4 o" `</script>9 i, @% @- s5 X7 ^5 f1 G% i4 e3 N
! Y$ V% T* v- j7 A# H' ^5 q
1
8 L) a. ?8 _! \3 ` h' W29 w4 y( Q2 F7 \- P! r
3
; |; a5 [# W: ?: b3 _- j% s' z4
v8 r v4 }6 i5
5 ~7 Z* w6 \6 M4 |) N3 T6' Z: U _& N; A- f' ~% e, P3 A% k
7
1 q0 E6 H# _/ n' Y6 E5 ~84 j2 j, q, J2 H! g
9
/ R4 q' A; ~! D% q, C0 d10
) h# g1 o( g' R% k: D11
' [, H' y2 I' x- w f12$ H1 c5 k3 k0 E3 I' O' f
133 G7 W, D) V& T/ y7 x8 V- f
14# ~" I B8 ]7 ]/ i ~8 ]
15
$ @9 s5 k# H. c* G! t2 Q1 m16) @, V, l! F' ~( k
17
3 ?# H/ j" F0 T6 Z, v3 _8 n18# A6 n, e& N- _1 w2 Z8 }. l4 g
19
9 ? d( K% O2 a* J# A& y5 N) l. X5 U20, s) T% Y ]) ^5 f3 ?( l9 b
21
# r6 ?* s5 g+ I+ ~/ ~) h3 j) v7 W22
1 X$ ?+ A; C8 Y: H" M( k; K. f23
. P2 Y* B8 k9 @" f$ o1 L" O24
6 ^$ C! E. I: l% ~( H25* x2 Z% b% i W# Y* o
26
9 B4 W; T7 t5 h27
( S& Y( h% k# o! |' o28# J7 w7 O# J* |) r
294 O+ m. j3 o; r. q
308 P3 j4 d+ s" V4 T9 b
313 K' P9 y- b6 _: I
32
Y: O' A! A J0 M1 t% E33
5 W/ d- }! E0 z9 t# Z* g& t) _34) P" J/ k3 ~; w" |; n) Z
35
. J" @+ v# C% F1 f) H3 i, O/ T( e36
# G, _8 H9 n. U" b8 O- N* O) f, ]) |37
0 t; V! a; y" D: z s# ^6 z38! z: l# I W4 F+ ^% h
395 b" f# @8 j" v" @; N- C' y9 f; ~1 |
40
7 j! g6 D" E5 G r( y, z4 |41
) ] q; Q$ J5 ~6 f# H42
B/ v V. J' E! @* n43
6 H1 P* `% R# i0 |, j444 H4 c1 I8 |4 \& U
451 e3 Z) x1 e( f9 Q3 \" f9 m
46
_$ |' M% l1 ?47# `9 D! d! u1 A9 {+ h
48- ?4 W, U4 g' P( @) u8 s
493 G; M% h5 D- }# Q
50% n9 G& f: n. C! K9 @
51
7 n7 P5 ]) ~- `# ^! w52
1 [$ g' \9 S( G' _$ g! l \$ ^53' y- A8 u# V7 N* r! F Y# \6 {
54
2 E2 D A, i O, w* n- Z55
, U+ R" l4 C6 {* `4 |56
5 e, a" m0 f$ D" b57' W8 y+ M. q, ]( D
58/ j9 S/ j- j/ c% X. t
59
# ?+ i8 J2 F! X1 v$ Q1 g/ ^60
) U U5 C) _# O0 d% f618 p- D, b( y$ d! U( w1 o8 w
62
8 @/ n u, f1 O9 a$ }632 q3 B6 s8 Q- R- U/ T% s9 |
64/ i' w! V2 R+ t2 }8 Y- A
65
# |) U, O6 W: x& t: @2 ?66 K2 a4 W0 L2 X3 ]0 g1 |5 ~
67
" V8 @2 e# G9 p4 A68& B- }2 S/ @/ V& b: {
69
k# X+ a) O2 _ q& N& K2 h! D70
2 o7 f. t; [' X* g) u3 v71
# p* b: Q* @& P72 a; T* O6 A; K- r# N. u* {$ u8 I
73' x4 s+ y! P1 F1 \& J# U
74
$ M* e& h' g2 x2 r9 u7 k75
- H' D% |9 Z' V+ ^+ |- @ s76
( ^: O9 ?/ h& m0 K; S77- d7 d; M1 }2 x# ?" X( |
78
# |) m2 ~% e+ ]) X7 f2 _% z79( t- h% L3 E+ b! v L8 _. N# O0 v
80
2 F; V+ A4 }" Q# W81
) E8 a- P3 m" X# {82) L/ u8 C0 \$ X8 K/ p% H, ^
83! z- x4 I: m2 e; a
849 S) K& ?1 y( |& s7 V2 P6 ^2 u
85
% r A* o% w2 @: M1 r7 ]4 M+ _! ^86$ X! z2 z; {/ Q+ B# e6 D0 E
87
; F4 a% s0 d; l' x887 h/ r5 Z' {2 {
89
0 i: ]1 \& A/ [9 h) M( b( y90
: ?* U9 q+ y7 `7 T1 W2 f5 H91- G4 K. ~9 ^* W9 F
92& ~5 l8 s& N/ J, ^9 l
93
3 E3 F8 n( B5 J4 [94( k. a5 Y; w4 W) w+ m
95# b! T$ \3 e {
96
' \, X7 i1 [& M6 m, b. J97
1 c! J, U( T1 e- v/ a" Q* D98) E$ R7 _, P% n7 `: A" w+ N
993 K& y* f& P( m4 Z
1005 G- _8 `# ~/ ?+ t8 H7 ^
101& N0 b! \/ z3 x3 E
102
7 J4 S* w) t% d) K( Y1 c) M3 L103+ P$ `/ i9 T5 _: v5 ~
104
; k2 ?' y& M/ U3 W105
( U L& _9 z8 c4 W' {2 K106
- S4 k8 w& V3 k n- Z1076 `& g& c" k# s1 A* z
1084 t# g7 [- X- o9 ~! W/ G% n
1099 n* U- t7 G4 k5 c; I4 M
110
* ^3 a; e) y" B0 t: ?$ S111, y; i" _7 i Z
112
* T: l2 d3 o( m9 M. p113) C. E K K' r0 c1 [
1144 y$ f6 T0 V2 L+ M5 `
115
5 {: F2 F- S/ Z: F6 o1 x116
/ M5 S) N! e) b5 B6 z% g5 |. o1177 w' m! O$ P/ q& f7 S" |
118
1 c3 U9 i" \7 @" a: C$ L119; A. L8 T9 \: j1 }& D
120 d! u( }1 \7 }) g; } z( g
1217 q$ G( O9 J) i3 g
122
2 j4 k( h: g0 B! f6 H123- a6 F3 T9 T8 e z
1247 G3 g' j! H' ^! e* d3 b( D) O
1250 z7 O. f# u: T4 a8 L
126
6 ?+ M7 ^0 W" t% z8 ^9 @- }127
y. }* |' ?1 ?- g- }1286 H) K5 Y$ j9 k; C: `
129 V. D: j H! b2 i/ E: R! l
130
8 |- s a5 s+ K" r! M131 {+ ]( i: u, p# ?, {
132; J+ s+ {) ^6 n' _9 ]
133
# Q Z0 q6 r# X. u134; K k. O; i0 o
135
, X! |/ r P1 ^5 z136
) ]* z0 `7 M; t137
- v6 s. ]% J( O: L+ d- y4 a6 M138
& o S! F9 ~4 N7 H139
4 |( i4 O) f* |6 h140
6 F# w1 \, C- t' K# Q. q# @% V2 K5 D141 R3 O$ {4 _9 y3 S
1425 R7 q. b- v$ R; [5 ^' B, i9 t0 K
143% [% Z1 }% n: z0 S# _, K
144
2 a6 m/ O+ J g9 w6 }145! z! G2 v3 [7 \$ O d
146
4 X9 c, A0 v1 r$ T147
" Y# C' e6 i! D4 i1483 g% w5 w: `. ^+ m8 x9 b' r
149/ C4 r" P9 b/ k+ [$ D7 w0 w- B1 C
150
$ a, ~) I3 R9 l+ R; i# N7 h- e151
' j ?3 X3 f& p4 c152. H+ v( q& x e+ n
1536 D i9 O- b9 C. V1 ~
154
$ ~) z! b" g; v5 o- d155; N& s- d s9 _+ B& l: ~
156
4 k6 q; _$ W$ J6 D157
( x- p2 v3 t5 k, }8 ?158/ ^/ [7 A* C: i2 ?: r
159
% f2 }5 ^3 X- F$ d5 j160
& K+ X9 U9 R6 J7 p- M& U161
) l8 J P% j) l" Q162
9 ^+ E+ J) G ~! n) w, W163. @1 G b9 z( j: X, M2 g2 R
164
5 V" \# x" p8 Q165
+ D- q. u$ \! s166
6 e: O6 Y' O! z1 x3 w167, ~2 U h; g. ^
168
4 u) I8 v( Q( w u- f/ S) |169
: i% E6 {2 u: n8 V T170
" y9 q4 b5 k2 q" u2 h1 T7 F1717 |1 x! Y) Q. e; }5 k
172
7 A; L) B. E$ \1 A8 U8 `1 H0 Z8 k% I173
1 H1 k1 y2 e1 L- W' ~ R1743 D) w; o7 Q0 S' w! Q/ f
175+ o/ X! w& `7 k. S
176
g1 d5 b$ H0 h& Z177+ l1 ~9 h4 Q1 F8 Z4 e0 O, K
1784 P7 W! E C [0 C$ h; a# h1 y
179
2 f" G$ d- o" y( q+ ]9 W180
! l, j3 w. t F8 G) F* Y, Y: i181* D' a+ i6 I, D) z/ x
182
6 [' H# `' T+ M& Q" a6 _0 i& O1 ~1838 w$ e4 L3 |3 v k. `
184- d. z" v+ R7 a$ f) d0 I, e
185
& L5 Z$ N3 W1 B0 a+ T+ e1864 Y9 n' `3 \3 G; H" o6 g
187
. r' H. _/ F, I188( D5 }( L$ s; ]' u) i6 G
189* v* C9 d, j; ? \3 T
190
4 X( M+ ?) _- d1912 _1 r5 h: \/ }1 o5 w" q
192& V) N; a, x4 i' |; F
193
8 z) h/ d& T% v1943 \5 g1 G1 q6 Z& A
195% t0 t3 g, I5 C) w/ v+ @" P2 H
196
2 V! N, M. M* }3 e, \* @, j1975 G5 X, y. Q: k: z T5 m
198
_. a6 p+ V9 J# t- c! i199
4 Y5 {9 {+ x5 r6 d9 ]" H200
2 R6 ~9 p J6 @201
8 ?" _" n0 T, U0 l* W8 F, ]" C202
0 ~3 `4 j1 _! f, p5 j J7 m& Y总结
0 g8 f: q9 }- H ^ g7 v0 t9 C/ F. m1 v自己封装数字动态效果需要注意各个浏览器直接的差异,手动pollyfill,暴露出去的props参数需要有默认值,数据的格式化可以才有正则表达式的方式,组件的驱动必须是数据变化,根据数据来驱动页面渲染,防止页面出现卡顿,不要强行操作dom,引入的组件可以全局配置,后续组件可以服用,码字不易,请各位看官大佬多多支持,一键三连了~❤️❤️❤️ t6 N: x6 [- H/ ~5 n
$ R: A# l- o# d4 H7 i
demo演示
# M# ?5 g0 D) C# ~+ A5 a, g后续的线上demo演示会放在2 b" `- G- R8 W: g
demo演示
/ w7 r/ c5 w+ w' D完整代码会放在. G6 G/ n. n3 @1 t
个人主页
* k5 W6 F. i9 m; P& ]; o3 L9 l' h
6 X2 O/ J5 f5 b9 p r- N希望对vue开发者有所帮助~. l8 w' h, J. n* D! y
5 B& s7 G# D+ U# r8 l3 i个人简介:承吾
, |9 u7 _4 {+ H) v1 B& v. R工作年限:5年前端; P& q" p! W- Q- J' W9 `
地区:上海3 {' x g. H1 F# z8 M
个人宣言:立志出好文,传播我所会的,有好东西就及时与大家共享!
. e ?* L. R7 ^* f1 V
1 I. r3 X% _/ V8 a
3 K+ J, H, Q# W
5 m! @/ {" ]/ q' z5 J* L: Z# Y8 b; P0 Q6 J1 G! f! Y2 ?( F
————————————————
^6 r' g8 I/ r5 g4 F版权声明:本文为CSDN博主「KinHKin(五年前端)」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
- R& M% E0 {! s原文链接:https://blog.csdn.net/weixin_42974827/article/details/126831847; [/ e( G2 f+ l% ~, U
" N! s' }, s4 \0 I, Q. H
9 L) o+ n7 a `8 ~$ O: i |
zan
|