日期选择组件的设计

日期选择组件是一个很常见、又挺复杂的组件,很值得好好研究一番。

一、日期的组成

2017-09-28 22:08:06
年、月、日、时、分、秒

二、日期的格式



三、基本日期选择组件的构成


主要由两部分构成:
日历表格(核心)
头部(切换月份和年份)

四、日历模式

日模式(基本模式)

月模式

年模式

世纪模式

五、衍生日期选择组件

选择日期区间

六、交互

基本日期选择组件

日历表格:选中某个日期、当前月份改变
头部:上一月/下一月/上一年/下一年、切换日历模式

日期区间选择组件

  • 开始时间和结束时间的选择在一个流程中,两次选择为一个流程,第一次选的是开始时间还是结束时间,取决于第二次选择的时间比其早还是晚。第二次选择完则时间区间确定,选择流程结束。继续选择进入下一个流程。
  • 左侧的日历表格选开始时间,右侧的表格选结束时间,可反复选择,选好点击确定按钮结束选择流程,确定时间区间。

七、日期选择限制

总体可选范围限制

只能选最近一年的数据(包括今天):[-365, 0]
只能选未来一个月的数据(包括今天):[0, 30]

可选时间段限制

只能选三个月的数据:90

日期区间选择组件中选一天(小时数据)的范围限制

只能选最近三个月(包括今天)的小时数据:[-90, 0]

开始日期和结束日期限制的规则

开始时间小于或等于结束时间

八、日期选择组件的实现

日历表格的展示(核心模块)

  • DateTable
    • DateTHead
    • DateTBody

获取日历数组的算法(核心算法):

输入:一个具体的日期
输出:6X7的二维日历数组(月模式)
例如:
输入:2017-09-28
输出:
[
    [28, 29, 30, 31, 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, 1],
    [2, 3, 4, 5, 6, 7, 8]
]

在实际的实现中,数组的值一般是Date格式或者Moment格式(Moment.js库:http://momentjs.com/),方便取各种格式的日期。

具体实现如下:


import moment from 'moment';

const DATE_ROW_COUNT = 6;

/**
 * 获取某一周的周数组
 * @param {某个日期} date 
 * @param {第几周} num 
 * @param {数组的值的格式} format 
 */
export function getWeekArr(date, num, format) {
    let weekArr = [];
    let dateMoment = date;
    if(!moment.isMoment(date)){
        dateMoment = moment(date);
    }
    let index = dateMoment.format('d');
    let firstDay = -index+num*7;
    let lastDay = 7-index+num*7;
    for(let day=firstDay;day<lastDay;day++){
        let weekItem = moment(dateMoment).add(day, 'days');
        let formatWeekItem = weekItem;
        if(format){
            formatWeekItem = weekItem.format(format);
        }
        weekArr.push(formatWeekItem);
    }
    return weekArr;
}

/**
 * 获取一个月的第一天
 * @param {某个日期} date 
 */
export function getFirstDayOfMonth(date, monthNum, yearNum) {
    let dateMoment = date;
    if(!moment.isMoment(date)){
        dateMoment = moment(date);
    }
    let year = moment(dateMoment).add(yearNum, 'years').add(monthNum, 'months').format('YYYY');
    let month = moment(dateMoment).add(yearNum, 'years').add(monthNum, 'months').format('MM');
    // let month = dateMoment.format('MM');
    let day = '01';
    let firstDayOfMonth = year+'-'+month+'-'+day;
    return firstDayOfMonth;
}

/**
 * 获取日历数组
 * @param {某个日期} date 
 */
export function getCalendarArr(date, monthNum, yearNum) {
    let calendarArr = [];
    monthNum = monthNum || 0;
    yearNum = yearNum || 0;
    let firstDayOfMonth = getFirstDayOfMonth(date, monthNum, yearNum);
    for(let row=0;row<DATE_ROW_COUNT;row++){
        let rowArr = getWeekArr(firstDayOfMonth, row);
        calendarArr.push(rowArr);
    }
    return calendarArr;
}

还有头部操作区、日期的选择、月份/年份的加减、日历模式的切换等模块的实现,可以参考另一篇文章:

posted @ 2017-10-01 11:52  Kagol  阅读(597)  评论(0编辑  收藏  举报