Vue【原创】时间轴 【time-axis】&【date-axis】

2023-08-30

封装了关于时间轴的组件,有时候统计页面会用到。

效果图:

时间轴分为2种,一种是time-axis:范围选择模式,一种是date-axis:步长选择模式。

代码中涉及到的工具类和图片资源,请移步页面底部的gitee地址下载源码。

time-axis:

  1 <template>
2 <div class="timeline" :style="{ 'background-color': themeObject.backgroudColor }">
3 <div class="start"><input v-model="st" @keyup="excute" :style="{ color: themeObject.color }" :disabled="interactive.inputDisabled" /></div>
4 <div ref="line" class="line">
5 <div ref="pgs" class="progress" :style="{ 'background-color': themeObject.progressColor }">
6 <div ref="slide" class="slidebar" :style="{ width: slideWidth + 'px', left: lbarLeft + 'px', background: themeObject.slideBackground }"></div>
7 <div ref="lbar" class="leftbar" :style="{ left: lbarLeft + 'px', 'z-index': lzindex, 'background-color': themeObject.barColor }"></div>
8 <div ref="rbar" class="rightbar" :style="{ left: rbarLeft + 'px', 'z-index': rzindex, 'background-color': themeObject.barColor }"></div>
9 </div>
10 </div>
11 <div class="end"><input v-model="et" @keyup="excute" :style="{ color: themeObject.color }" :disabled="interactive.inputDisabled" /></div>
12 </div>
13 </template>
14
15 <script>
16 import { debounce } from '../../../src/utils';
17
18 const reg = new RegExp(
19 /(([0-9]{3}[1-9]|[0-9]{2}[1-9][0-9]{1}|[0-9]{1}[1-9][0-9]{2}|[1-9][0-9]{3})-(((0[13578]|1[02])-(0[1-9]|[12][0-9]|3[01]))|((0[469]|11)-(0[1-9]|[12][0-9]|30))|(02-(0[1-9]|[1][0-9]|2[0-8]))))|((([0-9]{2})(0[48]|[2468][048]|[13579][26])|((0[48]|[2468][048]|[3579][26])00))-02-29)$/
20 );
21
22 const TYPE_LEFT = 0;
23 const TYPE_RIGHT = 1;
24 const TYPE_CENTER = 2;
25 // const MAX_DAYS = 90
26
27 const BAR_TYPE_LEFT = 0x01;
28 const BAR_TYPE_RIGHT = 0x02;
29
30 const THEME_DARK = 'dark';
31 const THEME_LIGHT = 'light';
32
33 export default {
34 name: 'LiloTimeAxis',
35 model: {
36 prop: 'data',
37 event: 'changed'
38 },
39 props: {
40 data: {
41 type: Object,
42 required: false,
43 default() {
44 return {
45 startTime: null,
46 endTime: null
47 };
48 }
49 },
50 min: {
51 type: String,
52 required: true,
53 default: null
54 },
55 max: {
56 type: String,
57 required: false,
58 default: null
59 },
60 theme: {
61 type: String,
62 default: THEME_LIGHT
63 },
64 customTheme: {
65 type: Object,
66 default: null
67 },
68 interactive: {
69 type: Object,
70 required: false,
71 default() {
72 return {
73 inputDisabled: false,
74 leftButtonDisabled: false,
75 rightButtonDisabled: false,
76 slideButtonDisabled: false
77 };
78 }
79 },
80 range: {
81 type: Number,
82 required: false,
83 default: 0
84 }
85 },
86 data() {
87 return {
88 st: '',
89 et: '',
90 lbarLeft: 0,
91 rbarLeft: 0,
92 lzindex: 1,
93 rzindex: 2,
94 barType: BAR_TYPE_LEFT
95 };
96 },
97 created() {},
98 mounted() {
99 this.type = -1;
100 this.move = false;
101 this.defaultLeft = 0;
102 this.defaultSlideWidth = 0;
103 this.maxWidth = 0;
104 this.allDays = 0;
105 // this.maxDays = MAX_DAYS
106 this.pst = '';
107 this.pet = '';
108
109 this._addEvents();
110 this._initDatePrototype();
111
112 if (this._validateData()) {
113 this._checkRange(false);
114 this._redraw();
115 }
116 window.requestAnimationFrame(this._updateDisplayList);
117 },
118 beforeDestroy() {
119 this._removeEvents();
120 },
121 computed: {
122 slideWidth() {
123 return this.rbarLeft - this.lbarLeft;
124 },
125 themeObject() {
126 if (this.customTheme) {
127 return this.customTheme;
128 } else {
129 switch (this.theme) {
130 case THEME_DARK:
131 return {
132 color: '#ffffff',
133 backgroudColor: '#000000',
134 progressColor: '#3e3e3e',
135 barColor: '#ffffff',
136 slideBackground: `url(${require('./assets/slider_pattern2.png')})`
137 };
138 case THEME_LIGHT:
139 return {
140 color: '#000000',
141 backgroudColor: '#ffffff',
142 progressColor: '#ababab',
143 barColor: '#ffffff',
144 slideBackground: '#072C4C'
145 // slideBackground: `url(${require('./assets/slider_pattern2.png')})`
146 };
147 default:
148 return {
149 color: '#ffffff',
150 backgroudColor: '#000000',
151 progressColor: '#3e3e3e',
152 barColor: '#ffffff',
153 slideBackground: '#072C4C'
154 // slideBackground: `url(${require('./assets/slider_pattern2.png')})`
155 };
156 }
157 }
158 }
159 },
160 watch: {
161 // ================================== watch ================================== //
162 data: {
163 handler: function(newVal, oldVal) {
164 if (newVal.startTime && newVal.endTime) {
165 if (newVal.startTime !== oldVal.startTime || newVal.endTime !== oldVal.endTime) {
166 // if(this._validateData()) {
167 this._redraw();
168 // }
169 }
170 }
171 },
172 deep: false
173 },
174 min(newVal, oldVal) {
175 if (newVal) {
176 if (this._validateData()) {
177 this._redraw();
178 }
179 }
180 },
181 max(newVal, oldVal) {
182 if (newVal) {
183 if (this._validateData()) {
184 this._redraw();
185 }
186 }
187 }
188 },
189 methods: {
190 onLbarDown(e) {
191 this.move = true;
192 this.type = TYPE_LEFT;
193 this.defaultLeft = e.target.offsetLeft;
194 this.defaultPageX = e.pageX;
195 this.maxWidth = this.$refs.pgs.clientWidth;
196 this.lzindex = 2;
197 this.rzindex = 1;
198 this.barType = BAR_TYPE_LEFT;
199 },
200 onRbarDown(e) {
201 this.move = true;
202 this.type = TYPE_RIGHT;
203 this.defaultLeft = e.target.offsetLeft;
204 this.defaultPageX = e.pageX;
205 this.maxWidth = this.$refs.pgs.clientWidth;
206 this.lzindex = 1;
207 this.rzindex = 2;
208 this.barType = BAR_TYPE_RIGHT;
209 },
210 onSlideDown(e) {
211 this.move = true;
212 this.type = TYPE_CENTER;
213 this.defaultLeft = e.target.offsetLeft;
214 this.defaultPageX = e.pageX;
215 this.maxWidth = this.$refs.pgs.clientWidth;
216 this.defaultSlideWidth = this.slideWidth;
217 },
218 onDocMove(e) {
219 if (this.move) {
220 const dx = e.pageX - this.defaultPageX;
221 let left = this.defaultLeft + dx;
222 if (this.type === TYPE_LEFT) {
223 if (left <= 0) {
224 left = 0;
225 }
226 if (left >= this.rbarLeft) {
227 left = this.rbarLeft;
228 }
229 this.lbarLeft = left;
230 const ldays = (left / this.maxWidth) * this.allDays;
231 this.st = this._getDate_(this._min, ldays);
232 } else if (this.type === TYPE_RIGHT) {
233 if (left <= this.lbarLeft) {
234 left = this.lbarLeft;
235 }
236 if (left >= this.maxWidth) {
237 left = this.maxWidth;
238 }
239 this.rbarLeft = left;
240 const rdays = (left / this.maxWidth) * this.allDays;
241 this.et = this._getDate_(this._min, rdays);
242 } else {
243 if (left <= 0) {
244 left = 0;
245 }
246 if (left >= this.maxWidth - this.defaultSlideWidth) {
247 left = this.maxWidth - this.defaultSlideWidth;
248 }
249 this.lbarLeft = left;
250 this.rbarLeft = this.lbarLeft + this.defaultSlideWidth;
251 const ldays = (left / this.maxWidth) * this.allDays;
252 this.st = this._getDate_(this._min, ldays);
253 const rdays = ((left + this.defaultSlideWidth) / this.maxWidth) * this.allDays;
254 this.et = this._getDate_(this._min, rdays);
255 }
256 this._checkRange();
257 }
258 },
259 onDocUp(e) {
260 if (this.move) {
261 this.move = false;
262 this._redraw();
263 }
264 },
265 excute: debounce(function() {
266 const startTime = this.st;
267 const endTime = this.et;
268 const f1 = reg.test(startTime.replace(/\//g, '-'));
269 const f2 = reg.test(endTime.replace(/\//g, '-'));
270 if (f1 && f2) {
271 this._redraw();
272 } else {
273 alert('日期格式错误,请按照2021/01/01格式输入');
274 }
275 }, 2000),
276 onResize() {
277 this._redraw();
278 },
279
280 // ================================== private ================================== //
281
282 _addEvents() {
283 if (!this.interactive.leftButtonDisabled) {
284 this.$refs.lbar.addEventListener('mousedown', this.onLbarDown);
285 }
286 if (!this.interactive.rightButtonDisabled) {
287 this.$refs.rbar.addEventListener('mousedown', this.onRbarDown);
288 }
289 if (!this.interactive.slideButtonDisabled) {
290 this.$refs.slide.addEventListener('mousedown', this.onSlideDown);
291 }
292 window.addEventListener('resize', this.onResize);
293 document.addEventListener('mousemove', this.onDocMove);
294 document.addEventListener('mouseup', this.onDocUp);
295 },
296 _removeEvents() {
297 if (!this.interactive.leftButtonDisabled) {
298 this.$refs.lbar.removeEventListener('mousedown', this.onLbarDown);
299 this.$refs.lbar.addEventListener('mousedown', this.onLbarDown);
300 }
301 if (!this.interactive.rightButtonDisabled) {
302 this.$refs.rbar.removeEventListener('mousedown', this.onRbarDown);
303 this.$refs.rbar.addEventListener('mousedown', this.onRbarDown);
304 }
305 if (!this.interactive.slideButtonDisabled) {
306 this.$refs.slide.removeEventListener('mousedown', this.onSlideDown);
307 this.$refs.slide.addEventListener('mousedown', this.onSlideDown);
308 }
309 window.removeEventListener('resize', this.onResize);
310 document.removeEventListener('mousemove', this.onDocMove);
311 document.removeEventListener('mouseup', this.onDocUp);
312 },
313 _redraw() {
314 this.dirty = true;
315 },
316 _updateDisplayList() {
317 if (this.dirty) {
318 this._validateDisplayList();
319
320 const startTime = this.st;
321 const endTime = this.et;
322 if (this.pst != startTime || this.pet != endTime) {
323 this.$emit('changed', { startTime, endTime });
324 }
325 this.pst = this.st;
326 this.pet = this.et;
327
328 this.dirty = false;
329 }
330
331 window.requestAnimationFrame(this._updateDisplayList);
332 },
333 _validateData() {
334 this._min = this.min || this.data.startTime;
335 this._max = this.max || this.data.endTime;
336 this.st = this.data.startTime;
337 this.et = this.data.endTime;
338
339 return this._min && this._max && this.st && this.et;
340 },
341 _validateDisplayList() {
342 const cw = this.$refs.line.clientWidth;
343 this.$refs.pgs.style.width = cw + 'px';
344
345 this.maxWidth = this.$refs.pgs.clientWidth;
346 this.allDays = this._getDaycount_(this._min, this._max);
347
348 const ldays = this._getDaycount_(this._min, this.st);
349 const rdays = this._getDaycount_(this._min, this.et);
350
351 this.lbarLeft = this.maxWidth * (ldays / this.allDays);
352 this.rbarLeft = this.maxWidth * (rdays / this.allDays);
353 },
354 _checkRange(draw = true) {
355 if (this.range > 0) {
356 const delta = this._getDaycount_(this.st, this.et);
357 if (delta > this.range) {
358 if (this.barType === BAR_TYPE_LEFT) {
359 this.st = this._getDate_(this.et, -this.range + 1);
360 } else if (this.barType === BAR_TYPE_RIGHT) {
361 this.et = this._getDate_(this.st, this.range - 1);
362 } else {
363 }
364 if(draw) {
365 this._validateDisplayList();
366 }
367 }
368 }
369 },
370 _initDatePrototype() {
371 Date.prototype.toLocaleString = function() {
372 return this.getFullYear() + '/' + (this.getMonth() + 1) + '/' + this.getDate() + ' ' + this.getHours() + ':' + this.getMinutes() + ':' + this.getSeconds();
373 };
374 },
375 _getDaycount_(time1, time2) {
376 const aa = new Date(time1).getTime();
377 const bb = new Date(time2).getTime();
378 const mm = 24 * 60 * 60 * 1000;
379 const count = (bb - aa) / mm;
380 return count;
381 },
382 _getDate_(time1, count) {
383 const aa = new Date(time1).getTime();
384 const mm = 24 * 60 * 60 * 1000;
385 const bb = count * mm + aa;
386 const tm = new Date(bb).toLocaleString().split(' ')[0];
387 const tm2 = tm.split('/');
388 const year = tm2[0];
389 const month = parseInt(tm2[1]) < 10 ? '0' + parseInt(tm2[1]) : tm2[1];
390 const day = parseInt(tm2[2]) < 10 ? '0' + parseInt(tm2[2]) : tm2[2];
391 return year + '/' + month + '/' + day;
392 }
393 }
394 };
395 </script>
396
397 <style lang="scss" scoped>
398 .timeline {
399 display: flex;
400 -webkit-transition: all 0.3s ease 0s;
401 transition: all 0.3s ease 0s;
402 border: 1px solid rgba(62, 62, 62, 1);
403 background-color: rgba(0, 0, 0, 0.9);
404 background-image: url('./assets/texture_small.png');
405 backdrop-filter: blur(10px);
406 -webkit-backdrop-filter: blur(10px);
407 // border-radius: 5px;
408 height: 40px;
409 line-height: 40px;
410 -moz-user-select: none;
411 -webkit-user-select: none;
412 user-select: none;
413 &:hover {
414 background-color: rgba(0, 0, 0, 1);
415 }
416 .start {
417 flex: 0 0 120px;
418 input {
419 background: transparent;
420 border: none;
421 width: 80px;
422 color: white;
423 // text-align: center;
424 letter-spacing: 1px;
425 font-weight: bold;
426 outline: none;
427 margin-left: 20px;
428 }
429 }
430 .end {
431 flex: 0 0 120px;
432 // text-align: center;
433 letter-spacing: 1px;
434 font-weight: bold;
435 input {
436 background: transparent;
437 border: none;
438 width: 80px;
439 color: white;
440 // text-align: center;
441 letter-spacing: 1px;
442 font-weight: bold;
443 outline: none;
444 margin-left: 20px;
445 }
446 }
447 .line {
448 height: 100%;
449 flex: 1;
450 .progress {
451 position: absolute;
452 // width: calc(100% - 280px);
453 height: 10px;
454 margin-top: 15px;
455 // border-radius: 5px;
456 background-color: rgba(62, 62, 62, 1);
457 // background-image: url('../assets/texture_small.png');
458 font-size: 0;
459 .leftbar {
460 // -webkit-transition: all 0.15s ease 0s;
461 // transition: all 0.15s ease 0s;
462 position: absolute;
463 top: -6px;
464 width: 6px;
465 height: 20px;
466 background-color: white;
467 border: 1px solid rgba(62, 62, 62, 1);
468 cursor: url('./assets/move.png') 15 15, default;
469 }
470 .slidebar {
471 // -webkit-transition: all 0.15s ease 0s;
472 // transition: all 0.15s ease 0s;
473 position: absolute;
474 height: 10px;
475 cursor: pointer;
476 background: url('./assets/slider_pattern2.png');
477 }
478 .rightbar {
479 // -webkit-transition: all 0.15s ease 0s;
480 // transition: all 0.15s ease 0s;
481 position: absolute;
482 top: -6px;
483 width: 6px;
484 height: 20px;
485 background-color: white;
486 border: 1px solid rgba(62, 62, 62, 1);
487 cursor: url('./assets/move.png') 15 15, default;
488 }
489 }
490 }
491 }
492 </style>

date-axis:

  1 <template>
2 <div class="timeline" :style="{ 'background-color': themeObject.backgroudColor }">
3 <div class="start"><input :value="st" @keyup="excute" :style="{ color: themeObject.color }" disabled /></div>
4 <div ref="line" class="line">
5 <div ref="pgs" class="progress" :style="{ 'background-color': themeObject.progressColor }">
6 <div ref="sbar" class="scalebar">
7 <div v-for="(item, index) in segment" class="scale"
8 :style="{ 'border': themeObject.scaleBorder }"
9 @mouseover="onScaleMouseover(index)"
10 @mouseout="onScaleMouseout(index)"
11 @click="onScaleClick(index)">
12 </div>
13 </div>
14 <div ref="slide" class="slidebar" :style="{ width: slideWidth + 'px', left: slideLeft + 'px', background: themeObject.slideBackground }"></div>
15 </div>
16 </div>
17 <div class="end"><input :value="et" @keyup="excute" :style="{ color: themeObject.color }" disabled /></div>
18 </div>
19 </template>
20
21 <script>
22 import { debounce } from '../../../src/utils';
23
24 const THEME_DARK = 'dark';
25 const THEME_LIGHT = 'light';
26
27 export default {
28 name: 'LiloDateAxis',
29 model: {
30 prop: 'data',
31 event: 'changed'
32 },
33 props: {
34 data: {
35 type: Object,
36 required: false,
37 default() {
38 return {
39 startTime: null,
40 endTime: null
41 };
42 }
43 },
44 min: {
45 type: String,
46 required: true,
47 default: null
48 },
49 max: {
50 type: String,
51 required: false,
52 default: null
53 },
54 theme: {
55 type: String,
56 default: THEME_LIGHT
57 },
58 customTheme: {
59 type: Object,
60 default: null
61 },
62 interactive: {
63 type: Object,
64 required: false,
65 default() {
66 return {
67 slideButtonDisabled: false
68 };
69 }
70 }
71 },
72 data() {
73 return {
74 st: '',
75 et: '',
76 range: 0,
77 allDays: 0,
78 segment: 0,
79 scales: [],
80 slideWidth: 0,
81 slideLeft: 0
82 };
83 },
84 created() {},
85 mounted() {
86 this._addEvents();
87 this._initDatePrototype();
88
89 if (this._validateData()) {
90 this._redraw();
91 }
92
93 window.requestAnimationFrame(this._updateDisplayList);
94 },
95 beforeDestroy() {
96 this._removeEvents();
97 },
98 computed: {
99 themeObject() {
100 if (this.customTheme) {
101 return this.customTheme;
102 } else {
103 switch (this.theme) {
104 case THEME_DARK:
105 return {
106 color: '#ffffff',
107 backgroudColor: '#000000',
108 progressColor: '#3e3e3e',
109 barColor: '#ffffff',
110 slideBackground: `url(${require('./assets/slider_pattern2.png')})`,
111 scaleBorder: '1px solid #000000'
112 };
113 case THEME_LIGHT:
114 return {
115 color: '#000000',
116 backgroudColor: '#ffffff',
117 progressColor: '#ababab',
118 barColor: '#ffffff',
119 slideBackground: '#072C4C',
120 // slideBackground: `url(${require('./assets/slider_pattern2.png')})`
121 scaleBorder: '1px solid #072C4C'
122 };
123 default:
124 return {
125 color: '#ffffff',
126 backgroudColor: '#000000',
127 progressColor: '#3e3e3e',
128 barColor: '#ffffff',
129 slideBackground: '#072C4C',
130 // slideBackground: `url(${require('./assets/slider_pattern2.png')})`
131 scaleBorder: '1px solid #072C4C'
132 };
133 }
134 }
135 }
136 },
137 watch: {
138 // ================================== watch ================================== //
139 data: {
140 handler: function(newVal, oldVal) {
141 if (newVal.startTime && newVal.endTime) {
142 if (newVal.startTime !== oldVal.startTime || newVal.endTime !== oldVal.endTime) {
143 if (this._validateData()) {
144 this._redraw();
145 }
146 }
147 }
148 },
149 deep: false
150 },
151 min(newVal, oldVal) {
152 if (newVal) {
153 if (this._validateData()) {
154 this._redraw();
155 }
156 }
157 },
158 max(newVal, oldVal) {
159 if (newVal) {
160 if (this._validateData()) {
161 this._redraw();
162 }
163 }
164 }
165 },
166 methods: {
167 onScaleClick(index) {
168 if (this.interactive.slideButtonDisabled) {
169 return;
170 }
171
172 const o = this.scales[index];
173 this.st = o.startTime;
174 this.et = o.endTime;
175
176 this._redraw();
177 },
178 onScaleMouseover(index) {
179 const o = this.scales[index];
180 this.st = o.startTime;
181 this.et = o.endTime;
182 },
183 onScaleMouseout(index) {
184 this.st = this.pst;
185 this.et = this.pet;
186 },
187 excute: debounce(function() {}, 2000),
188 onResize() {
189 this._redraw();
190 },
191
192 // ================================== private ================================== //
193
194 _addEvents() {
195 window.addEventListener('resize', this.onResize);
196 },
197 _removeEvents() {
198 window.removeEventListener('resize', this.onResize);
199 },
200 _redraw() {
201 this.dirty = true;
202 },
203 _updateDisplayList() {
204 if (this.dirty) {
205 this._validateDisplayList();
206
207 const startTime = this.st;
208 const endTime = this.et;
209 if (this.pst != startTime || this.pet != endTime) {
210 this.$emit('changed', { startTime, endTime });
211 }
212 this.pst = this.st;
213 this.pet = this.et;
214 this.dirty = false;
215 }
216
217 window.requestAnimationFrame(this._updateDisplayList);
218 },
219 _validateData() {
220 this._min = this.min || this.data.startTime;
221 this._max = this.max || this.data.endTime;
222 this.st = this.data.startTime;
223 this.et = this.data.endTime;
224
225 return this._min && this._max && this.st && this.et;
226 },
227 _validateDisplayList() {
228 this.range = this._getDaycount_(this.st, this.et) + 1;
229 this.allDays = this._getDaycount_(this._min, this._max) + 1;
230 this.segment = this.allDays / this.range;
231 if ((this.segment | 0) !== this.segment) {
232 throw new Error('总天数必须被时间段天数整除,例如一共20天,每个时间段2天,则合理。');
233 }
234 this.scales = [];
235 for (let i = 0; i < this.allDays; i += this.range) {
236 const startTime = this._getDate_(this._min, i);
237 const endTime = this._getDate_(this._min, i + this.range - 1);
238 this.scales.push({ startTime, endTime });
239 }
240
241 const startIndex = this._findIndex(this.st, 'startTime');
242 const endIndex = this._findIndex(this.et, 'endTime');
243 if (startIndex === -1 || endIndex === -1) {
244 throw new Error('[min-max]区间段内找不到[startTime,endTime]起始日期。');
245 }
246
247 this.slideWidth = this.$refs.line.clientWidth / this.segment;
248 this.slideLeft = startIndex * this.slideWidth;
249 },
250 _findIndex(time, key) {
251 for (let i = 0; i < this.scales.length; i++) {
252 const o = this.scales[i];
253 if (o[key] === time) {
254 return i;
255 }
256 }
257 return -1;
258 },
259 _initDatePrototype() {
260 Date.prototype.toLocaleString = function() {
261 return this.getFullYear() + '/' + (this.getMonth() + 1) + '/' + this.getDate() + ' ' + this.getHours() + ':' + this.getMinutes() + ':' + this.getSeconds();
262 };
263 },
264 _getDaycount_(time1, time2) {
265 const aa = new Date(time1).getTime();
266 const bb = new Date(time2).getTime();
267 const mm = 24 * 60 * 60 * 1000;
268 const count = (bb - aa) / mm;
269 return count;
270 },
271 _getDate_(time1, count) {
272 const aa = new Date(time1).getTime();
273 const mm = 24 * 60 * 60 * 1000;
274 const bb = count * mm + aa;
275 const tm = new Date(bb).toLocaleString().split(' ')[0];
276 const tm2 = tm.split('/');
277 const year = tm2[0];
278 const month = parseInt(tm2[1]) < 10 ? '0' + parseInt(tm2[1]) : tm2[1];
279 const day = parseInt(tm2[2]) < 10 ? '0' + parseInt(tm2[2]) : tm2[2];
280 return year + '/' + month + '/' + day;
281 }
282 }
283 };
284 </script>
285
286 <style lang="scss" scoped>
287 .timeline {
288 display: flex;
289 -webkit-transition: all 0.3s ease 0s;
290 transition: all 0.3s ease 0s;
291 border: 1px solid rgba(62, 62, 62, 1);
292 background-color: rgba(0, 0, 0, 0.9);
293 background-image: url('./assets/texture_small.png');
294 backdrop-filter: blur(10px);
295 -webkit-backdrop-filter: blur(10px);
296 // border-radius: 5px;
297 height: 40px;
298 line-height: 40px;
299 -moz-user-select: none;
300 -webkit-user-select: none;
301 user-select: none;
302 &:hover {
303 background-color: rgba(0, 0, 0, 1);
304 }
305 .start {
306 flex: 0 0 120px;
307 input {
308 background: transparent;
309 border: none;
310 width: 80px;
311 color: white;
312 // text-align: center;
313 letter-spacing: 1px;
314 font-weight: bold;
315 outline: none;
316 margin-left: 20px;
317 }
318 }
319 .end {
320 flex: 0 0 120px;
321 // text-align: center;
322 letter-spacing: 1px;
323 font-weight: bold;
324 input {
325 background: transparent;
326 border: none;
327 width: 80px;
328 color: white;
329 // text-align: center;
330 letter-spacing: 1px;
331 font-weight: bold;
332 outline: none;
333 margin-left: 20px;
334 }
335 }
336 .line {
337 height: 100%;
338 flex: 1;
339 .progress {
340 position: absolute;
341 // width: calc(100% - 280px);
342 left: 120px;
343 right: 120px;
344 height: 30%;
345 top: 35%;
346 // border-radius: 5px;
347 // background-color: rgba(62, 62, 62, 1);
348 // background-image: url('../assets/texture_small.png');
349 font-size: 0;
350 .slidebar {
351 -webkit-transition: all 0.25s ease-out 0s;
352 transition: all 0.15s ease-out 0s;
353 position: absolute;
354 height: 100%;
355 cursor: pointer;
356 background: url('./assets/slider_pattern2.png');
357 // border-radius: 10px;
358 box-sizing: border-box;
359 border: 1px solid #000000;
360 }
361 .scalebar {
362 position: absolute;
363 width: 100%;
364 height: 100%;
365 cursor: pointer;
366 display: flex;
367 justify-content: flex-end;
368 align-items: center;
369 .scale {
370 -webkit-transition: all 0.15s ease-out 0s;
371 transition: all 0.15s ease-out 0s;
372 flex: 1;
373 height: 100%;
374 box-sizing: border-box;
375 // border-radius: 10px;
376 &:hover {
377 background-color: rgba($color: #ffffff, $alpha: 0.4) !important;
378 }
379 }
380 }
381 }
382 }
383 }
384 </style>

调用示例和参数说明

  1 <template>
2 <div class="root">
3 <div>
4 <div class="time-title">1.【lilo-time-axis】基础用法</div>
5 <el-button @click="setTime('001')">绑定方式修改时间</el-button>
6 <lilo-time-axis
7 v-model="example001.data"
8 :min="example001.min"
9 class="timeline"
10 :customTheme="example001.customTheme"
11 @changed="timeChanged">
12 </lilo-time-axis>
13 <div class="time-text">开始时间:{{ example001.data.startTime }}</div>
14 <div class="time-text">结束时间:{{ example001.data.endTime }}</div>
15 </div>
16
17 <div>
18 <div class="time-title">2.【lilo-time-axis】锁定时间轴,禁用起始按钮和时间条</div>
19 <el-button @click="setTime('002')">绑定方式修改时间</el-button>
20 <lilo-time-axis
21 v-model="example002.data"
22 :interactive="example002.interactive"
23 :min="example002.min"
24 :max="example002.max"
25 class="timeline"
26 :theme="example002.theme"
27 @changed="timeChanged"
28 >
29 <!-- :customTheme="customTheme"-->
30 <!-- :theme="theme"-->
31 </lilo-time-axis>
32 <div class="time-text">开始时间:{{ example002.data.startTime }}</div>
33 <div class="time-text">结束时间:{{ example002.data.endTime }}</div>
34 </div>
35
36 <div>
37 <div class="time-title">3.【lilo-date-axis】初始化的起始时间间隔为步长,请保证[时间间隔]能被max-min[时间段]整除,且[时间间隔]不要跨区间,例如下面例子:总时间段60天,时间间隔为2天,30个小时间段</div>
38 <!-- <el-button @click="setTheme('003')">绑定方式修改时间</el-button> -->
39 <lilo-date-axis
40 v-model="example003.data"
41 :interactive="example003.interactive"
42 :min="example003.min"
43 :max="example003.max"
44 class="timeline"
45 :theme="example003.theme"
46 @changed="timeChanged"
47 >
48 <!-- :customTheme="customTheme"-->
49 <!-- :theme="theme"-->
50 </lilo-date-axis>
51 <div class="time-text">开始时间:{{ example003.data.startTime }}</div>
52 <div class="time-text">结束时间:{{ example003.data.endTime }}</div>
53 </div>
54
55 <div>
56 <div class="time-title">4.【lilo-time-axis】设置最大时间范围 (range = 5)</div>
57 <lilo-time-axis
58 v-model="example004.data"
59 :range="example004.range"
60 :min="example004.min"
61 class="timeline"
62 @changed="timeChanged">
63 </lilo-time-axis>
64 <div class="time-text">开始时间:{{ example004.data.startTime }}</div>
65 <div class="time-text">结束时间:{{ example004.data.endTime }}</div>
66 </div>
67
68 </div>
69 </template>
70
71 <script>
72 export default {
73 name: 'example-time-date-axis',
74 data() {
75 return {
76 example001: {
77 data: {
78 startTime: '2021/06/01',
79 endTime: '2022/06/01'
80 },
81 min: '2021/01/01',
82 // max: '2022/08/01', //max如果在组件上未声明,则不参与绑定,默认取endTime
83 // theme: 'light', //dark,light(default light)
84 customTheme: {
85 //if not null, be first
86 color: '#000000',
87 backgroudColor: '#BBDAFA',
88 progressColor: '#8d8d8d',
89 barColor: '#ffffff',
90 // slideBackground: `url(${require('../../../assets/slider_pattern2.png')})`
91 slideBackground: '#00417a'
92 }
93 },
94 example002: {
95 data: {
96 startTime: '2021/06/01',
97 endTime: '2022/06/01'
98 },
99 interactive: {
100 inputDisabled: true,
101 leftButtonDisabled: true,
102 rightButtonDisabled: true,
103 slideButtonDisabled: true
104 },
105 min: '2021/01/01',
106 max: '2022/08/01',
107 theme: 'dark' //dark,light(default light)
108 },
109 example003: {
110 data: {
111 startTime: '2022/08/21',
112 endTime: '2022/08/22'
113 },
114 interactive: {
115 slideButtonDisabled: false
116 },
117 min: '2022/08/01',
118 max: '2022/08/30',
119 theme: 'dark' //dark,light(default light)
120 },
121 example004: {
122 data: {
123 startTime: '2022/09/17',
124 endTime: '2022/09/27'
125 },
126 range: 5,
127 min: '2022/09/13',
128 theme: 'dark' //dark,light(default light)
129 }
130 };
131 },
132 mounted() {},
133 methods: {
134 setTime(type) {
135 const date = {
136 startTime: '2022/04/01',
137 endTime: '2022/08/01'
138 };
139 const min = '2022/02/01';
140 const max = '2022/08/26';
141 this[`example${type}`].data = date;
142 this[`example${type}`].min = min;
143 this[`example${type}`].max = max;
144 },
145 timeChanged(val) {
146 console.log(val);
147 }
148 }
149 };
150 </script>
151
152 <style>
153 .root {
154 padding: 10px;
155 }
156 .time-title {
157 margin-top: 10px;
158 margin-bottom: 5px;
159 /* color: #034631; */
160 font-weight: bold;
161 }
162 .time-text {
163 margin-top: 10px;
164 }
165 </style>

Vue原创】时间轴 【time-axis】&【date-axis】的相关教程结束。