优化批量流量图形展示页面Echarts图表X轴数据缩进逻辑,提升展示效果、单页面多路由缓存问题

1、优化批量流量图形展示页面Echarts图表X轴数据缩进逻辑,提升展示效果
2、添加代码注释,移除冗余代码,优化代码体积与执行效率
3、优化自定义日期时间区间组件,完善功能与视觉表现
4、优化路由匹配逻辑,解决单页面适配多路由场景下的 keep-alive 缓存错乱问题
This commit is contained in:
康冉冉
2026-03-16 18:06:58 +08:00
parent 936b4dd885
commit ac163a126a
7 changed files with 223 additions and 149 deletions
@@ -107,7 +107,7 @@
v-for="(day, index) in days"
:key="index"
class="day-cell"
:class="getDayClass(day)"
:class="getDayClass(day, index)"
@click="selectDate(day)"
>
<div class="day-content">
@@ -185,7 +185,7 @@
},
pickerOptions: {
type: Object,
default: () => {shortcuts: []}
default: () => ({shortcuts: []})
},
placement: {
type: String,
@@ -210,7 +210,11 @@
startTime: '',
endTime: '',
panelStyle: {opacity: 0},
actualPlacement: this.placement
actualPlacement: this.placement,
updatePanelPositionDebounced: null, // 防抖函数引用
calendarCache: {}, // 日历数据缓存
focusedDayIndex: -1, // 当前焦点日期的索引
isKeyboardNavigating: false // 是否正在使用键盘导航
};
},
computed: {
@@ -222,8 +226,13 @@
return [start, end]
}
return [];
},
// 缓存键,用于判断是否需要重新生成日历
calendarCacheKey() {
return `${this.currentMonth}-${this.currentDate}`;
}
},
watch: {
value: {
immediate: true,
@@ -250,29 +259,58 @@
if (val) {
this.generateCalendar();
document.addEventListener('click', this.handleClickOutside);
document.addEventListener('scroll', this.updatePanelPosition, true);
window.addEventListener('resize', this.updatePanelPosition);
document.addEventListener('scroll', this.updatePanelPositionDebounced, true);
window.addEventListener('resize', this.updatePanelPositionDebounced);
document.addEventListener('keydown', this.handleKeydown);
// 初始化焦点到第一个当前月份的日期
this.$nextTick(() => {
this.focusFirstCurrentMonthDay();
setTimeout(() => {
this.updatePanelPosition();
},500);
});
} else {
document.removeEventListener('click', this.handleClickOutside);
document.removeEventListener('scroll', this.updatePanelPosition, true);
window.removeEventListener('resize', this.updatePanelPosition);
document.removeEventListener('scroll', this.updatePanelPositionDebounced, true);
window.removeEventListener('resize', this.updatePanelPositionDebounced);
document.removeEventListener('keydown', this.handleKeydown);
this.focusedDayIndex = -1;
this.isKeyboardNavigating = false;
}
}
},
mounted() {
this.generateCalendar();
// 创建防抖函数
this.updatePanelPositionDebounced = this.debounce(this.updatePanelPosition, 100);
},
beforeDestroy() {
document.removeEventListener('click', this.handleClickOutside);
document.removeEventListener('scroll', this.updatePanelPosition, true);
window.removeEventListener('resize', this.updatePanelPosition);
document.removeEventListener('scroll', this.updatePanelPositionDebounced, true);
window.removeEventListener('resize', this.updatePanelPositionDebounced);
document.removeEventListener('keydown', this.handleKeydown);
},
methods: {
// 简单的防抖函数实现
debounce(func, wait) {
let timeout;
return function executedFunction(...args) {
const later = () => {
clearTimeout(timeout);
func.apply(this, args);
};
clearTimeout(timeout);
timeout = setTimeout(later, wait);
};
},
// 解析时间字符串为Date对象
parseTimeString(timeStr) {
if (!timeStr) return new Date(0, 0, 0, 0, 0, 0);
const parts = timeStr.split(':').map(Number);
return new Date(0, 0, 0, parts[0] || 0, parts[1] || 0, parts[2] || 0);
},
// 更新面板位置
updatePanelPosition() {
if (!this.showPanel || !this.$refs.triggerRef || !this.$refs.panelRef) {
@@ -306,6 +344,13 @@
}
},
generateCalendar() {
// 检查缓存
const cacheKey = this.calendarCacheKey;
if (this.calendarCache[cacheKey]) {
this.days = this.calendarCache[cacheKey];
return;
}
const year = this.currentMonth;
const month = this.currentDate - 1;
const firstDayOfMonth = new Date(year, month, 1);
@@ -313,12 +358,12 @@
const daysInMonth = new Date(year, month + 1, 0).getDate();
const prevMonthDays = new Date(year, month, 0).getDate();
this.days = [];
const days = [];
// 添加上个月的天数
for (let i = 0; i < firstDayWeek; i++) {
const day = prevMonthDays - firstDayWeek + i + 1;
this.days.push({
days.push({
date: day,
month: 'prev',
fullDate: new Date(year, month - 1, day)
@@ -327,7 +372,7 @@
// 添加当月天数
for (let i = 1; i <= daysInMonth; i++) {
this.days.push({
days.push({
date: i,
month: 'current',
fullDate: new Date(year, month, i)
@@ -337,13 +382,23 @@
// 添加下个月的天数
const totalCells = 42; // 6行 * 7天
const nextMonthDay = 1;
while (this.days.length < totalCells) {
this.days.push({
date: nextMonthDay + (this.days.length - daysInMonth - firstDayWeek),
while (days.length < totalCells) {
days.push({
date: nextMonthDay + (days.length - daysInMonth - firstDayWeek),
month: 'next',
fullDate: new Date(year, month + 1, nextMonthDay + (this.days.length - daysInMonth - firstDayWeek))
fullDate: new Date(year, month + 1, nextMonthDay + (days.length - daysInMonth - firstDayWeek))
});
}
// 更新数据和缓存
this.days = days;
this.calendarCache[cacheKey] = days;
// 限制缓存大小,避免内存泄漏
const cacheKeys = Object.keys(this.calendarCache);
if (cacheKeys.length > 10) {
delete this.calendarCache[cacheKeys[0]];
}
},
selectDate(day) {
@@ -372,12 +427,12 @@
this.endDate = null;
}
if (this.startDate && this.endDate && this.dateType === 'datetimerange') {
this.startTime = this.startTime ? this.startTime : new Date(0,0,0,this.defaultTime[0].split(':').map(Number)[0],this.defaultTime[0].split(':').map(Number)[1],this.defaultTime[0].split(':').map(Number)[2]);
this.endTime = this.endTime ? this.endTime : new Date(0,0,0,this.defaultTime[1].split(':').map(Number)[0],this.defaultTime[1].split(':').map(Number)[1],this.defaultTime[1].split(':').map(Number)[2]);
this.startTime = this.startTime ? this.startTime : this.parseTimeString(this.defaultTime[0]);
this.endTime = this.endTime ? this.endTime : this.parseTimeString(this.defaultTime[1]);
}
},
getDayClass(day) {
getDayClass(day, index) {
const classes = [];
if (day.month !== 'current') {
@@ -399,6 +454,11 @@
if (this.isInRange(day.fullDate)) {
classes.push('in-range');
}
// 添加焦点样式
if (this.isKeyboardNavigating && index === this.focusedDayIndex) {
classes.push('focused');
}
return classes;
},
@@ -508,6 +568,93 @@
}
},
// 键盘事件处理
handleKeydown(event) {
if (!this.showPanel) return;
this.isKeyboardNavigating = true;
switch(event.key) {
case 'ArrowLeft':
event.preventDefault();
this.moveFocus(-1); // 向左移动
break;
case 'ArrowRight':
event.preventDefault();
this.moveFocus(1); // 向右移动
break;
case 'ArrowUp':
event.preventDefault();
this.moveFocus(-7); // 向上移动
break;
case 'ArrowDown':
event.preventDefault();
this.moveFocus(7); // 向下移动
break;
case 'Enter':
event.preventDefault();
this.selectFocusedDay();
break;
case 'Escape':
event.preventDefault();
this.closePanel();
break;
case 'Tab':
// 允许Tab键正常导航
this.isKeyboardNavigating = false;
break;
}
},
// 聚焦到第一个当前月份的日期
focusFirstCurrentMonthDay() {
const firstCurrentMonthIndex = this.days.findIndex(day => day.month === 'current');
if (firstCurrentMonthIndex !== -1) {
this.focusedDayIndex = firstCurrentMonthIndex;
} else {
this.focusedDayIndex = 0;
}
},
// 移动焦点
moveFocus(delta) {
if (this.days.length === 0) return;
let newIndex = this.focusedDayIndex + delta;
// 边界检查
if (newIndex < 0) {
// 移动到上个月
this.prevMonth();
this.$nextTick(() => {
newIndex = this.days.length - 7 + (newIndex % 7);
if (newIndex < 0) newIndex = 0;
this.focusedDayIndex = newIndex;
});
return;
}
if (newIndex >= this.days.length) {
// 移动到下个月
this.nextMonth();
this.$nextTick(() => {
newIndex = newIndex % 7;
this.focusedDayIndex = newIndex;
});
return;
}
this.focusedDayIndex = newIndex;
},
// 选择当前焦点的日期
selectFocusedDay() {
if (this.focusedDayIndex >= 0 && this.focusedDayIndex < this.days.length) {
const day = this.days[this.focusedDayIndex];
this.selectDate(day);
}
},
formatDateTime(date) {
if (!date) return '';
const d = new Date(date);
@@ -785,6 +932,12 @@
font-weight: 600;
}
.day-cell.focused .day-content {
box-shadow: 0 0 0 2px #409eff;
outline: none;
z-index: 2;
}
.day-cell.in-range:before {
content: '';
position: absolute;