魔改antd日期范围选择器组件


功能要求日期选择组件只保留一个日历面板。常见的日期范围组件默认一左一右展示2个日历面板,ant-design-vue": "4.x"目前也不支持展示单日历面板,
看了文档提供的事件,感觉这事可以做,那么只能自己动手试试课。
顺便推荐一个支持单日历展示的插件。vue2-daterange-picker

常见的日期范围组件

最终效果

代码示例

1
2
3
4
5
6
7
8
9
10
11
12
13
<div class="container">
时间:
<a-range-picker
v-model:value="dateRangeValue"
format="YYYY-MM-DD"
:placeholder="['开始日期', '结束日期']"
class="customer-date-range-picker"
@change="handleDateRangeChange"
@openChange="handlePickerOpenChange"
allow-clear="false"
/>
<div> {{start}} ~ {{end}}</div>
</div>
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
import { ref, nextTick } from 'vue';
import dayjs from 'dayjs';

const dateRangeValue = ref([]);
const isPickerOpen = ref(false);
const activePickerInput = ref('start'); // 当前激活的输入框:'start' | 'end'
const start = ref("");
const end = ref("");

const handleDateRangeChange = (dates) => {
start.value = dayjs(dates[0]).format("YYYY-MM-DD");
end.value = dayjs(dates[1]).format("YYYY-MM-DD");

};

// 日期选择器打开/关闭状态变化
const handlePickerOpenChange = (open) => {
isPickerOpen.value = open;
if (open) {
nextTick(() => {
setupPickerPanelSwitcher();
});
} else {
activePickerInput.value = 'start';
}
};

// 设置面板切换监听器
const setupPickerPanelSwitcher = () => {
nextTick(() => {
const pickerInputs = document.querySelectorAll('.customer-date-range-picker .ant-picker-input input');
const panelContainer = document.querySelector('.ant-picker-dropdown .ant-picker-panel-container');

if (pickerInputs.length >= 2 && panelContainer) {
const startInput = pickerInputs[0];
const endInput = pickerInputs[1];

// 检查当前焦点
if (document.activeElement === endInput) {
// 判断是否应该在第一个面板显示
if (shouldShowFirstPanelForEndDate()) {
panelContainer.classList.remove('show-end-panel');
activePickerInput.value = 'start';
} else {
panelContainer.classList.add('show-end-panel');
activePickerInput.value = 'end';
}
} else {
panelContainer.classList.remove('show-end-panel');
activePickerInput.value = 'start';
}

// 监听开始日期输入框焦点
const handleStartFocus = () => {
panelContainer.classList.remove('show-end-panel');
activePickerInput.value = 'start';
};

// 监听结束日期输入框焦点
const handleEndFocus = () => {
// 判断是否应该在第一个面板显示
if (shouldShowFirstPanelForEndDate()) {
panelContainer.classList.remove('show-end-panel');
activePickerInput.value = 'start';
} else {
panelContainer.classList.add('show-end-panel');
activePickerInput.value = 'end';
}
};

startInput?.addEventListener('focus', handleStartFocus, { once: false });
endInput?.addEventListener('focus', handleEndFocus, { once: false });
}
});
};

// 判断结束日期是否应该在第一个面板显示
const shouldShowFirstPanelForEndDate = () => {
// 如果没有选择日期范围,默认显示第一个面板
if (!dateRangeValue.value || !Array.isArray(dateRangeValue.value)) {
return true;
}

const startDate = dateRangeValue.value[0];
const endDate = dateRangeValue.value[1];

// 如果没有开始日期,默认显示第一个面板
if (!startDate) {
return true;
}

// 如果没有结束日期,默认显示第一个面板(让用户从第一个面板开始选择)
if (!endDate) {
return true;
}

// 如果已经选择了结束日期,判断逻辑:
// 1. 如果结束日期在开始日期的月份,显示第一个面板
// 2. 如果结束日期不在开始日期的月份,显示第二个面板(结束日期所在的月份)
// 这样当用户再次点击结束日期时,会看到结束日期所在的月份
const startDateMonth = dayjs(startDate).startOf('month');
const endDateMonth = dayjs(endDate).startOf('month');
console.log(startDateMonth,endDateMonth)
// 如果结束日期在开始日期的月份,显示第一个面板
if (endDateMonth.isSame(startDateMonth, 'month')) {
return true;
}
return false;
};
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
.container {
width: 500px;
margin: 300px auto;
}

.ant-picker-dropdown {
.ant-picker-panel-container {
// 默认显示第一个面板,隐藏第二个
.ant-picker-panel:last-child {
display: none !important;
}

// 调整单个日历面板的样式
.ant-picker-panel:first-child {
border-right: none !important;

// 确保第一个面板的翻页按钮可见
.ant-picker-header {
display: flex !important;

button {
display: inline-block !important;
visibility: visible !important;
opacity: 1 !important;
pointer-events: auto !important;
}
}
}

// 当结束日期输入框激活时,显示第二个面板,隐藏第一个
&.show-end-panel {
.ant-picker-panel:first-child {
display: none !important;
}

.ant-picker-panel:last-child {
display: block !important;
border-left: none !important;

// 确保第二个面板的翻页按钮可见
.ant-picker-header {
display: flex !important;

button {
display: inline-block !important;
visibility: visible !important;
opacity: 1 !important;
pointer-events: auto !important;
}
}
}
}
display: flex;
justify-content: center;
}
}

总结

我们通过css来控制具体显示哪个面板,如果结束日期和开始日期在同一个月,那么无论聚焦哪个input都显示开始日期面板,反之显示结束日期面板即可。

哦对了,我最近开发了一个叫牛马工作器的chrome拓展插件,很好玩哦,感兴趣的话,给我的公众号回复牛马即可免费获取。

我的微信公众号: 梨的前端小屋


文章作者: 梨啊梨
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 梨啊梨 !
  目录