DateRangePicker: 实现周/星期选择器

说明

期望：点击某一天，自动选中这一天所在星期的开始和结束日期。

现状：这是一个选择时间范围的需求，Date Range Picker 自身并没有实现周选择的功能，对于日期范围，需要点一次开始，再点一次结束。

所以需要自己实现，步骤如下。

引入 week-picker.css

Copy
.daterangepicker .calendar-table th,
.daterangepicker .calendar-table td { /* tighter */
min-width: 20px !important;
}

.daterangepicker tr td.week { /* wider */
width: 44px;
color: #1a6cb3;
}

.daterangepicker tbody tr:hover {
background-color: #f2f2f2;
}

.daterangepicker td.off {
background-color: transparent !important;
}

.daterangepicker td.off.in-range {
/*background-color: #ebf4f8 !important;*/
background-color: #e4eaec !important;
}

.daterangepicker td.off.start-date,
.daterangepicker td.off.end-date {
background-color: #5188b7 !important;
}

.daterangepicker tbody tr.active td.week {
color: #357ebd !important;
background-color: #f2f2f2 !important;
font-weight: bold;
}

.daterangepicker td.today,
.daterangepicker td.today.off {
background-color: #ecf6f9 !important;
}

引入 week-picker.js

Copy
/*
代码源自：https://jsfiddle.net/dj_floyd/f2hoygdw/

使用方式：
1. 引入 week-picker.css
2. 引入 week-picker.js
3. 页面上添加一个 input 元素，设置 id 为 week-dp

4. 在页面的 js 文件中，调用 initWeekPicker 函数，传入 '#week-dp' 作为参数

获取值：$('#week-dp').val()
*/

//moment.locale('ru') //depending on locale you can move start of week
/**
* 初始化 周选择器
*
* 因为异步设置显示的值，所以获取值的方式变成了：
* $(domSelector).data('weekStart');
* $(domSelector).data('weekEnd');
* @param {any} domSelector '#week-dp'
* @param {any} format 默认 'YYYY-MM-DD'
*/
function initWeekPicker(domSelector, format) {
const set_picker_start_end = (picker, when) => {
//console.log('set_picker_start_end')
let m = (when == 'now') ? moment() : moment(when); //moment

let week_start = m.startOf('isoweek');
let week_end = m.clone().endOf('isoweek');

// 因为 setStartDate、setEndDate 之后会格式化显示选择的日期，
// 但因为我们将 singleDatePicker设置为true，所以它在格式化的时候就不会带上结束日期
// 因此，这里设置一个延时，让它在 setStartDate、setEndDate 之后设置值
// 就是会出现一个闪烁的问题，不过影响不大，就当是动画效果了
setTimeout(() => {
$(domSelector).val(week_start.format(format ?? 'YYYY-MM-DD') + ' ~ ' + week_end.format(format ??'YYYY-MM-DD'));
}, 0);

// 因为上面是延迟设置值，导致外部 initWeekPicker 之后，获取 $(domSelector).val() 只有 week_start 的值（因为singleDatePicker设置为true，setEndDate不再生效)
// 所以这里将真正的值放在 data 中，页面上异步显示，外部获取值的时候从 data 取，就不会出现调用 initWeekPicker 之后拿不到周范围值的问题
$(domSelector).data({
weekStart: week_start.format(format ?? 'YYYY-MM-DD'),
weekEnd: week_end.format(format ?? 'YYYY-MM-DD'),
});

//console.log(week_start.format('YYYY-MM-DD'), week_end.format('YYYY-MM-DD'));
picker.setStartDate(week_start);
picker.setEndDate(week_end);
};

$(domSelector).daterangepicker({
"showDropdowns": true,
"showISOWeekNumbers": false,
"autoApply": true,
"showCustomRangeLabel": false,
//"startDate": '', //not work because of one calendar. will be set further
//"endDate": '', //not work because of one calendar. will be set further
"drops": "down",
// daterangepicker 这个组件选日期范围的需要点开始和结束两次，为了实现点一次就选中一周的效果，设置为单选
// 但这会导致一个问题，就是 /picker.setStartDate(week_start);picker.setEndDate(week_end); 之后，format 的格式只有week_start
// 因为我们将 singleDatePicker设置为true，所以它在格式化的时候就不会带上结束日期
"singleDatePicker": true, //to make one click and one calendar
"locale": {
"format": "YYYY-MM-DD",
//"weekLabel": "#",
},
});

set_picker_start_end($(domSelector).data('daterangepicker'), 'now') //set current week selected

$(domSelector).on('show.daterangepicker', function (ev, picker) {
//console.log('show.daterangepicker', ev, picker);
let active_cell = picker.container[0].querySelector('td.start-date');
active_cell.parentElement.classList.add('active'); //tr goes active
});

// fix:解决 daterangepicker 显示后，没有点击日期，点击其他地方后，因为 autoApply：true，会自动关闭 picker，然后日期变成只有 startDate 的问题
$(domSelector).on('hide.daterangepicker', function (ev, picker) {
//console.log('hide.daterangepicker', ev, picker);

set_picker_start_end(picker, picker.startDate);
});

$(domSelector).on('apply.daterangepicker', function (ev, picker) {
//console.log('apply.daterangepicker', ev, picker);
set_picker_start_end(picker, picker.startDate);
});
}

使用方式

html：

Copy


js：

Copy
initWeekPicker('#week-dp');

参考