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

效果图:

时间轴分为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】的更多相关文章

  1. vue使用iview Timeline 时间轴不显示问题

    vue Timeline 时间轴不显示渲染的效果 官网代码 <Timeline pending> <TimelineItem>发布1.0版本</TimelineItem& ...

  2. [原创]首次制作JQueryUI插件-Timeline时间轴

    特点: 1. 支持多左右滚动,左右拖动. 2. 时间轴可上下两种显示方式. 3. 支持两种模式的平滑滚动/拖动. 4. 行压缩(后续版本此处可设置是否开启,上传的代码不带这个功能). 5. 支持hov ...

  3. [原创]一个纯css实现兼容各种主流移动pc浏览器的时间轴

    废话不多说 Demo 高度完全的自适应 中心思想是table 和第二列行高的50%的上下绝对定位竖线 第一次用codepen less完全不能用啊 连node png之类的都是关键词会被去掉... 马 ...

  4. Jquery实现的几款漂亮的时间轴

    引言 最近项目中使用了很多前端的东西,对于我一个做后台开发的人员,这是一个很好的锻炼的机会.经过这段时间的学习,感觉前端的东西太多了,太强大了,做出来的东西太炫酷了.现在有很多开源的前端框架,做的都非 ...

  5. echart 时间轴、以及y轴值过大但是变化不大显示感觉不出变化的问题+弹出框拖动div事件

    1.时间轴 echart 提供了一种图表,如果x轴是一个时间范围,并且是连续的,如果用传统的数据驱动会很慢,所以用时间轴的方式 function initCurve(_data){ var resul ...

  6. extjs 4 chart 时间轴格式的处理

    var dayStore = Ext.create('Ext.data.JsonStore', { fields: [{ name: 'name', type: 'date', dateFormat: ...

  7. ECharts实例开发学习笔记二——时间轴

    记录一下ECharts时间轴的使用,首先是照着官方的示例做一遍,在这里不要忘了引入timelineOption.js,后面介绍如何动态创建时间轴的记录数,即根据需求可伸缩显示有多少天或者年月等轴标记数 ...

  8. PHP通用函数 - 日期生成时间轴

    /** * 时间轴函数, Unix 时间戳 * @param int $time 时间 */ function TranTime($time) { //$time = strtotime($time) ...

  9. 4-Highcharts曲线图之时间轴折线图

    鼠标按住左键 左右移动可以试试<!DOCTYPE> <html lang='en'> <head> <title>4-Highcharts曲线图之时间轴 ...

  10. Sencha Touch2 时间轴ListPanel

    直接贴代码 timeline.html <!DOCTYPE html> <html> <head> <meta charset="UTF-8&quo ...

随机推荐

  1. Windows 10 v2022-L.1345 神州网信政府版

    Windows 10 v2022-L.1345 神州网信政府版 Windows 10 神州网信政府版(以下简称CMGE)V2022-L是在 Windows 10 21H2的基础上,根据中国有关法律.法 ...

  2. GPT-4多态大模型研究

    1.概述 GPT-4是OpenAI最新的系统,能够产生更安全和更有用的回应.它是一个大型的多模态模型(接受图像和文本输入,输出文本),在各种专业和学术的基准测试中展现了人类水平的表现.例如,它在模拟的 ...

  3. SpringBoot整合OSS文件上传

    一.注册阿里云账号并开通OSS服务 1.登录阿里云账号 2.创建一个bucket 3.创建子用户 对自用户分配权限,打开操作OSS的全部权限(也可根据业务需求进行更改) 4.配置上传跨域规则 任何来源 ...

  4. GPT大模型下,如何实现网络自主防御

    GPT大模型下,如何实现网络自主防御 本期解读专家  李智华 华为安全AI算法专家    近年来,随着GPT大模型的出现,安全领域的攻防对抗变得更加激烈.RSAC2023人工智能安全议题重点探讨了人工 ...

  5. C++面试八股文:如何在堆上和栈上分配一块内存?

    某日二师兄参加XXX科技公司的C++工程师开发岗位6面: 面试官: 如何在堆上申请一块内存? 二师兄:常用的方法有malloc,new等. 面试官:两者有什么区别? 二师兄:malloc是向操作系统申 ...

  6. 自然语言处理(NLP)

    "自然语言处理(Natural Language Processing, NLP)是计算机科学领域与人工智能领域中的一个重要方向.它研究能实现人与计算机之间用自然语言进行有效通信的各种理论和 ...

  7. Spring Boot实现高质量的CRUD-2

    (续前文) 5.Dao类 ​ ​ Dao类提供操作访问数据库表的接口方法.常规的CRUD,将考虑下列接口方法: ​ 1)插入单条对象记录: ​ 2)批量插入对象记录: ​ 3)修改单条对象记录: ​ ...

  8. C++内敛函数,构造函数,析构函数,浅拷贝

    inline //inline函数可以有声明和实现,但是必须在同一文件//inline函数不能分成头文件和实现文件 inline int add(int x, int y){ //一般不要放循环语句 ...

  9. WPF在win10/11上启用模糊特效 适配Dark/Light Mode

    先看效果图 win11: win10: 大佬们已经总结了许多在WPF上开启亚克力效果的方法,本文只是做一些填坑和适配工作. 正文开始 先来看看部分版本Windows的模糊效果和我的适配方案: 1).早 ...

  10. [ARM 汇编]高级部分—性能优化与调试—3.4.3 使用模拟器进行调试与测试

    在ARM汇编程序开发过程中,使用模拟器(emulator)进行调试和测试是一种非常有效的方法.模拟器可以在不同的处理器上测试代码,帮助我们发现潜在的问题,并提供丰富的调试功能.本节将介绍如何使用QEM ...