WeUI时间选择器实现(年、月、日、时、分、秒)
最近做移动端页面时有这么一个需求,时间选择器需要精确到时、分、秒。但WeUI的时间选择器只能支持年、月、日。
研究了下WeUI的时间选择器部分的代码,其实 datePicker() 时间选择器,是由 picker() 拓展而来,在控件开头的注释就已经提到了。picker() 的数据格式其实就是每个选择项的 children() 属性下加入下一级选项的数据,子选项的children属性继续加入下一级选项的数据,这样一层一层的嵌套下去。
WeUI时间选择器相关代码:
/** * datePicker 时间选择器,由picker拓展而来,提供年、月、日的选择。 * @param options 配置项 * @param {string=} [options.id=datePicker] 作为picker的唯一标识 * @param {number=|string|Date} [options.start=2000] 起始年份,如果是 `Number` 类型,表示起始年份;如果是 `String` 类型,格式为 'YYYY-MM-DD';如果是 `Date` 类型,就传一个 Date * @param {number=|string|Date} [options.end=2030] 结束年份,同上 * @param {string=} [options.cron=* * *] cron 表达式,三位,分别是 dayOfMonth[1-31],month[1-12] 和 dayOfWeek[0-6](周日-周六) * @param {string=} [options.className] 自定义类名 * @param {array=} [options.defaultValue] 默认选项的value数组, 如 [1991, 6, 9] * @param {function=} [options.onChange] 在picker选中的值发生变化的时候回调 * @param {function=} [options.onConfirm] 在点击"确定"之后的回调。回调返回选中的结果(Array),数组长度依赖于picker的层级。 * *@example * // 示例1: * weui.datePicker({ * start: 1990, * end: 2000, * defaultValue: [1991, 6, 9], * onChange: function(result){ * console.log(result); * }, * onConfirm: function(result){ * console.log(result); * }, * id: 'datePicker' * }); * * // 示例2: * weui.datePicker({ * start: new Date(), // 从今天开始 * end: 2030, * defaultValue: [2020, 6, 9], * onChange: function(result){ * console.log(result); * }, * onConfirm: function(result){ * console.log(result); * }, * id: 'datePicker' * }); * * // 示例3: * weui.datePicker({ * start: new Date(), // 从今天开始 * end: 2030, * cron: '* * 0,6', // 每逢周日、周六 * onChange: function(result){ * console.log(result); * }, * onConfirm: function(result){ * console.log(result); * }, * id: 'datePicker' * }); * * // 示例4: * weui.datePicker({ * start: new Date(), // 从今天开始 * end: 2030, * cron: '1-10 * *', // 每月1日-10日 * onChange: function(result){ * console.log(result); * }, * onConfirm: function(result){ * console.log(result); * }, * id: 'datePicker' * }); */ function datePicker(options) { var nowDate = new Date(); var defaults = _util2.default.extend({ id: 'datePicker', onChange: _util2.default.noop, onConfirm: _util2.default.noop, start: nowDate.getFullYear() - 20, end: nowDate.getFullYear() + 20, defaultValue: [nowDate.getFullYear(), nowDate.getMonth() + 1, nowDate.getDate()], cron: '* * *', depth: 3 }, options); // 约束depth if (defaults.depth > 3) { console.warn('max depth is 3, but you passed depth = ' + defaults.depth + ', set depth = 3'); defaults.depth = 3; } if (defaults.depth < 1) { console.warn('min depth is 1, but you passed depth = ' + defaults.depth + ', set depth = 1'); defaults.depth = 1; } // 兼容原来的 start、end 传 Number 的用法 if (typeof defaults.start === 'number') { defaults.start = new Date(defaults.start + '/01/01'); } else if (typeof defaults.start === 'string') { defaults.start = new Date(defaults.start.replace(/-/g, '/')); } if (typeof defaults.end === 'number') { defaults.end = new Date(defaults.end + '/12/31'); } else if (typeof defaults.end === 'string') { defaults.end = new Date(defaults.end.replace(/-/g, '/')); } var findBy = function findBy(array, key, value) { for (var i = 0, len = array.length; i < len; i++) { var _obj = array[i]; if (_obj[key] == value) { return _obj; } } }; var date = []; var interval = _cron2.default.parse(defaults.cron, defaults.start, defaults.end); var obj = void 0; do { obj = interval.next(); var year = obj.value.getFullYear(); var month = obj.value.getMonth() + 1; var day = obj.value.getDate(); var Y = findBy(date, 'value', year); if (!Y) { Y = { label: year + '年', value: year, children: [] }; date.push(Y); } // 如果深度是大于1,加入月份 if (defaults.depth > 1) { var M = findBy(Y.children, 'value', month); if (!M) { M = { label: month + '月', value: month, children: [] }; Y.children.push(M); } // 如果深度大于2,加入日期 if (defaults.depth > 2) { M.children.push({ label: day + '日', value: day }); } } } while (!obj.done); return picker(date, defaults); } exports.default = { picker: picker, datePicker: datePicker }; module.exports = exports['default'];
要改进这个时间选择器,可以显示时、分、秒,其实也很简单。我们只需要在日的选项下加入一个children,把时、分、秒加进去。由于每天24小时、每小时60分、每分钟60秒这些都是固定的,我们就不需要在他那个 do{...}while(...) 循环里进行建立时分秒的数组了,这样会很耗浏览器资源,我们直接在循环的外面定义好时分秒的数据,然后在每日的children里面插入这个数组就可以了。
由于 picker() 不支持多列和级联混用,时分秒的数组也只能用级联的方式来添加。
建立时分秒数组的代码如下:
// 加入时分秒 var dateHours = [],dateMinutes = [],dateSeconds = []; // 如果深度大于5,加入秒 if(defaults.depth > 5){ if(!(defaults.defaultValue[5] > 0 && defaults.defaultValue[5] < 60) ){ defaults.defaultValue[5] = 0; } for (var i = 0 ; i < 60; i++){ dateSeconds.push({ label: i + '秒', value: i }) }; }; // 如果深度大于4,加入分 if(defaults.depth > 4){ if(!(defaults.defaultValue[4] > 0 && defaults.defaultValue[4] < 60) ){ defaults.defaultValue[4] = 0; } for (var i = 0 ; i < 60; i++){ dateMinutes.push({ label: i + '分', value: i, children: dateSeconds }) }; }; // 如果深度大于3,加入时 if(defaults.depth > 3){ if(!(defaults.defaultValue[3] > 0 && defaults.defaultValue[3] < 24) ){ defaults.defaultValue[3] = 0; } for (var i = 0 ; i < 24; i++){ dateHours.push({ label: i + '时', value: i, children: dateMinutes }) }; };
然后把 dateHours 加入到每日的children下
// 如果深度大于2,加入日期 if (defaults.depth > 2) { M.children.push({ label: day + '日', value: day, children: dateHours }); }
虽然加上了时分秒的选项,但我们发现时间选择器调用时还是只有年月日,那是因为有个depth深度的约束。这里默认是3层,所以就只有年月日。我们还需要把时间默认值、默认显示层级、约束depth进行修改
默认时间:
defaultValue: [nowDate.getFullYear(), nowDate.getMonth() + 1, nowDate.getDate()], // 改为 defaultValue: [nowDate.getFullYear(), nowDate.getMonth() + 1, nowDate.getDate(), nowDate.getHours(), nowDate.getMinutes(), nowDate.getSeconds()],
默认层级:
depth: 3 // 改为 depth: 6
约束depth:
// 约束depth if (defaults.depth > 3) { console.warn('max depth is 3, but you passed depth = ' + defaults.depth + ', set depth = 3'); defaults.depth = 3; } // 改为 if (defaults.depth > 6) { console.warn('max depth is 6, but you passed depth = ' + defaults.depth + ', set depth = 6'); defaults.depth = 6; }
这样WeUI的时间选择器就可以显示到时分秒了
修改后的时间选择器部分代码:
/** * datePicker 时间选择器,由picker拓展而来,提供年、月、日的选择。 * @param options 配置项 * @param {string=} [options.id=datePicker] 作为picker的唯一标识 * @param {number=|string|Date} [options.start=2000] 起始年份,如果是 `Number` 类型,表示起始年份;如果是 `String` 类型,格式为 'YYYY-MM-DD';如果是 `Date` 类型,就传一个 Date * @param {number=|string|Date} [options.end=2030] 结束年份,同上 * @param {string=} [options.cron=* * *] cron 表达式,三位,分别是 dayOfMonth[1-31],month[1-12] 和 dayOfWeek[0-6](周日-周六) * @param {string=} [options.className] 自定义类名 * @param {array=} [options.defaultValue] 默认选项的value数组, 如 [1991, 6, 9] * @param {function=} [options.onChange] 在picker选中的值发生变化的时候回调 * @param {function=} [options.onConfirm] 在点击"确定"之后的回调。回调返回选中的结果(Array),数组长度依赖于picker的层级。 * *@example * // 示例1: * weui.datePicker({ * start: 1990, * end: 2000, * defaultValue: [1991, 6, 9], * onChange: function(result){ * console.log(result); * }, * onConfirm: function(result){ * console.log(result); * }, * id: 'datePicker' * }); * * // 示例2: * weui.datePicker({ * start: new Date(), // 从今天开始 * end: 2030, * defaultValue: [2020, 6, 9], * onChange: function(result){ * console.log(result); * }, * onConfirm: function(result){ * console.log(result); * }, * id: 'datePicker' * }); * * // 示例3: * weui.datePicker({ * start: new Date(), // 从今天开始 * end: 2030, * cron: '* * 0,6', // 每逢周日、周六 * onChange: function(result){ * console.log(result); * }, * onConfirm: function(result){ * console.log(result); * }, * id: 'datePicker' * }); * * // 示例4: * weui.datePicker({ * start: new Date(), // 从今天开始 * end: 2030, * cron: '1-10 * *', // 每月1日-10日 * onChange: function(result){ * console.log(result); * }, * onConfirm: function(result){ * console.log(result); * }, * id: 'datePicker' * }); */ function datePicker(options) { var nowDate = new Date(); var defaults = _util2.default.extend({ id: 'datePicker', onChange: _util2.default.noop, onConfirm: _util2.default.noop, start: nowDate.getFullYear() - 20, end: nowDate.getFullYear() + 20, defaultValue: [nowDate.getFullYear(), nowDate.getMonth() + 1, nowDate.getDate(), nowDate.getHours(), nowDate.getMinutes(), nowDate.getSeconds()], cron: '* * *', depth: 6 }, options); // 约束depth if (defaults.depth > 6) { console.warn('max depth is 6, but you passed depth = ' + defaults.depth + ', set depth = 6'); defaults.depth = 6; } if (defaults.depth < 1) { console.warn('min depth is 1, but you passed depth = ' + defaults.depth + ', set depth = 1'); defaults.depth = 1; } // 兼容原来的 start、end 传 Number 的用法 if (typeof defaults.start === 'number') { defaults.start = new Date(defaults.start + '/01/01'); } else if (typeof defaults.start === 'string') { defaults.start = new Date(defaults.start.replace(/-/g, '/')); } if (typeof defaults.end === 'number') { defaults.end = new Date(defaults.end + '/12/31'); } else if (typeof defaults.end === 'string') { defaults.end = new Date(defaults.end.replace(/-/g, '/')); } var findBy = function findBy(array, key, value) { for (var i = 0, len = array.length; i < len; i++) { var _obj = array[i]; if (_obj[key] == value) { return _obj; } } }; var date = []; var interval = _cron2.default.parse(defaults.cron, defaults.start, defaults.end); var obj = void 0; // 加入时分秒 var dateHours = [],dateMinutes = [],dateSeconds = []; // 如果深度大于5,加入秒 if(defaults.depth > 5){ if(!(defaults.defaultValue[5] > 0 && defaults.defaultValue[5] < 60) ){ defaults.defaultValue[5] = 0; } for (var i = 0 ; i < 60; i++){ dateSeconds.push({ label: i + '秒', value: i }) }; }; // 如果深度大于4,加入分 if(defaults.depth > 4){ if(!(defaults.defaultValue[4] > 0 && defaults.defaultValue[4] < 60) ){ defaults.defaultValue[4] = 0; } for (var i = 0 ; i < 60; i++){ dateMinutes.push({ label: i + '分', value: i, children: dateSeconds }) }; }; // 如果深度大于3,加入时 if(defaults.depth > 3){ if(!(defaults.defaultValue[3] > 0 && defaults.defaultValue[3] < 24) ){ defaults.defaultValue[3] = 0; } for (var i = 0 ; i < 24; i++){ dateHours.push({ label: i + '时', value: i, children: dateMinutes }) }; }; do { obj = interval.next(); var year = obj.value.getFullYear(); var month = obj.value.getMonth() + 1; var day = obj.value.getDate(); var Y = findBy(date, 'value', year); if (!Y) { Y = { label: year + '年', value: year, children: [] }; date.push(Y); } // 如果深度是大于1,加入月份 if (defaults.depth > 1) { var M = findBy(Y.children, 'value', month); if (!M) { M = { label: month + '月', value: month, children: [] }; Y.children.push(M); } // 如果深度大于2,加入日期 if (defaults.depth > 2) { M.children.push({ label: day + '日', value: day, children: dateHours }); } } } while (!obj.done); return picker(date, defaults); } exports.default = { picker: picker, datePicker: datePicker }; module.exports = exports['default'];
注意:由于 picker() 方法不支持多列级联同时使用,时分秒只能通过级联方式添加到每日的 children 里,年份跨度太大会用性能问题,要严格控制年份的跨度,尽量控制在100年以内。
用户登录
还没有账号?
立即注册