數據展示,一直是各行各業樂此不疲的需求,具體到前端開發行業,則是各種各種圖表數據展示,各種表格數據展示,煩不勝煩(繁不勝繁)!
前幾天剛做了折線圖、柱狀圖、餅狀圖之類的圖表數據展示效果,今天又碰到了類似圓環進度條的展示效果。天天跟數據打交道,天天跟接口打交道,項目做了不少,菜逼還是菜逼,都是淚啊!
其實說白了,是自己對canvas不熟,對CSS3不熟,所以就找了一個現成的輪子:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
|
<template> <div class= "content" ref= "box" > <svg style= "transform: rotate(-90deg)" :width= "width" :height= "width" xmlns= "http://www.w3.org/2000/svg" > <circle :r= "(width-radius)/2" :cy= "width/2" :cx= "width/2" :stroke-width= "radius" :stroke= "backgroundColor" fill= "none" /> <circle ref= "$bar" :r= "(width-radius)/2" :cy= "width/2" :cx= "width/2" :stroke= "barColor" :stroke-width= "radius" :stroke-linecap= "isRound ? 'round' : 'square'" :stroke-dasharray= "(width-radius)*3.14" :stroke-dashoffset= "isAnimation ? (width-radius) * 3.14 : (width - radius) * 3.14 * (100 - progress) / 100" fill= "none" /> </svg> <div class= "center_text" :style= "{color, fontSize}" > <p v- if = "!$slots.default" class= "title" >{{progress}}%</p> <slot></slot> </div> </div> </template> <script> export default { props: { radius: { type: [Number, String], default : 20 }, // 進度條厚度 progress: { type: [Number, String], default : 20 }, // 進度條百分比 barColor: { type: String, default : "#1890ff" }, // 進度條顏色 backgroundColor: { type: String, default : "rgba(0,0,0,0.3)" }, // 背景顏色 isAnimation: { // 是否是動畫效果 type: Boolean, default : true }, isRound: { // 是否是圓形畫筆 type: Boolean, default : true }, id: { // 組件的id,多組件共存時使用 type: [String, Number], default : 1 }, duration: { // 整個動畫時長 type: [String, Number], default : 1000 }, delay: { // 延遲多久執行 type: [String, Number], default : 200 }, timeFunction: { // 動畫緩動函數 type: String, default : "cubic-bezier(0.99, 0.01, 0.22, 0.94)" }, circleWidth: { //圓環寬度 type: Number, default : 100, }, color: { //文字顏色 type: String, default : '#000' }, fontSize: { //文字大小 type: String, default : '18px' } }, data() { return { width: this .circleWidth, idStr: `circle_progress_keyframes_${ this .id}` }; }, beforeDestroy() { // 清除舊組件的樣式標簽 document.getElementById( this .idStr) && document.getElementById( this .idStr).remove(); window.addEventListener(() => {}); }, mounted() { let self = this ; this .setCircleWidth(); this .setAnimation(); // 此處不能使用window.onresize window.addEventListener( "resize" , debounce( function () { self.setCircleWidth(); self.setAnimation(self); }, 300) ); }, methods: { setCircleWidth() { let box = this .$refs.box; let width = box.clientWidth; let height = box.clientHeight; let cW = width > height ? height : width; this .width = cW; }, setAnimation() { let self = this ; if (self.isAnimation) { // 重復定義判斷 if (document.getElementById(self.idStr)) { console.warn( "vue-circle-progress should not have same id style" ); document.getElementById(self.idStr).remove(); } // 生成動畫樣式文件 let style = document.createElement( "style" ); style.id = self.idStr; style.type = "text/css" ; style.innerHTML = ` @keyframes circle_progress_keyframes_name_${self.id} { from {stroke-dashoffset: ${(self.width - self.radius) * 3.14}px;} to {stroke-dashoffset: ${((self.width - self.radius) * 3.14 * (100 - self.progress)) / 100}px;}} .circle_progress_bar${ self.id } {animation: circle_progress_keyframes_name_${self.id} ${ self.duration }ms ${self.delay}ms ${self.timeFunction} forwards;}`; // 添加新樣式文件 document.getElementsByTagName( "head" )[0].appendChild(style); // 往svg元素中添加動畫class self.$refs.$bar.classList.add(`circle_progress_bar${self.id}`); } } } }; </script> <style scoped> .content {height:100%;display:flex;justify-content:center;align-items: center;} .center_text {position:absolute;} </style> |
使用方法:
1
2
3
4
|
< CircleProgress :id = "'circle1'" :circleWidth = "40" :radius = "7" :progress = "30" :isAnimation = "true" :backgroundColor = "'#E9E9E9'" :barColor = "'#FF4F4F'" /> < CircleProgress :id = "'circle2'" :circleWidth = "40" :radius = "7" :progress = "50" :isAnimation = "true" :backgroundColor = "'#E9E9E9'" :barColor = "'#FF902A'" /> < CircleProgress :id = "'circle3'" :circleWidth = "40" :radius = "7" :progress = "89" :isAnimation = "true" :backgroundColor = "'#E9E9E9'" :barColor = "'#FFDB4F'" /> < CircleProgress :id = "'circle4'" :circleWidth = "40" :radius = "7" :progress = "25" :isAnimation = "true" :backgroundColor = "'#E9E9E9'" :barColor = "'#B8D87E'" /> |
使用時需要注意一下,如果你的頁面中同時使用了超過兩個以上的這種圓環進度條,就需要給每個圓環進度條設置不同的id,否則,所有圓環最終展示的數據都會是最后一個圓環的數據。
代碼中有一個防抖動的函數,這里就貼一下這個函數:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
function debounce(func, wait, immediate) { let timeout, args, context, timestamp, result const later = function () { // 據上一次觸發時間間隔 const last = + new Date() - timestamp // 上次被包裝函數被調用時間間隔last小于設定時間間隔wait if (last < wait && last > 0) { timeout = setTimeout(later, wait - last) } else { timeout = null // 如果設定為immediate===true,因為開始邊界已經調用過了此處無需調用 if (!immediate) { result = func.apply(context, args) if (!timeout) context = args = null } } } |
本文參考的是npm上的一個圓環進度條的插件vue-circleprogressbar
,之所以沒有在項目中直接安裝并使用這個插件,是因為這個插件有點不太符合我們開發的需求,比如這個插件不能設置圓環的寬度,不能設置文字的顏色,不能設置文字的大小,再比如這個插件僅僅為了防抖而依賴了lodash(這個lodash的體積還是很大的)。
至于這個組件在react中的使用,按照react的生命周期,或者react hooks的語法,或者dva模式的語法,稍微改巴改巴就可以使用了,很簡單,就不再展開了。
作者:小壞
出處:http://tnnyang.cnblogs.com
以上就是Vue實現圓環進度條的示例的詳細內容,更多關于Vue 實現圓環進度條的資料請關注服務器之家其它相關文章!
原文鏈接:https://www.cnblogs.com/tnnyang/p/11655317.html