import { createElement } from "../functions"; /** * 创建或转换日期选择框 * @param {string} [min] - 最小可选日期 * @param {string} [max] - 最大可选日期 * @param {HTMLInputElement | string} [element] - 转换该元素为日期选择框 * @returns {HTMLInputElement} 返回创建或转换的日期选择框 */ export function createDateInput(min, max, element) { let date; if (typeof element === 'string') { element = document.querySelector(element); } if (element instanceof HTMLInputElement) { date = element; date.classList.add('ui-date-cell'); } else { date = createElement('input', 'ui-date-cell'); } date.required = true; date.type = 'date'; if (min != null) { date.min = min; } if (max != null) { date.max = max; } return date; } /** * 将日期转换为 `yyyy-MM-dd` 格式的字符串 * @param {Date} dt 要转换的日期值 * @param {boolean} [local] 是否视日期为本地时间 * @returns 返回 `yyyy-MM-dd` 格式的字符串 */ export function toDateValue(dt, local) { if (isNaN(dt)) { return ''; } const year = local ? dt.getFullYear() : dt.getUTCFullYear(); const month = String((local ? dt.getMonth() : dt.getUTCMonth()) + 1).padStart(2, '0'); const date = String(local ? dt.getDate() : dt.getUTCDate()).padStart(2, '0'); return `${year}-${month}-${date}`; } /** * 格式化日期为 M/d/yyyy 格式的字符串 * @param {Date | number | string} date - 需要格式化的日期值,支持的格式如下: * * * `"2024-01-26"` * * `"2024-01-26T00:00:00"` * * `"1/26/2024"` * * `"638418240000000000"` * * `new Date('2024-01-26')` * @returns {string} 返回格式化后的日期字符串 */ export function formatDate(date) { if (date instanceof Date) { return `${date.getMonth() + 1}/${date.getDate()}/${date.getFullYear()}`; } const ticks = Number(date); if (!isNaN(ticks) && ticks > 0) { date = new Date((ticks - 621355968e9) / 1e4); return `${date.getUTCMonth() + 1}/${date.getUTCDate()}/${date.getUTCFullYear()}`; } return date; } /** * 设置显示日期 * @param {HTMLElement} element - 要设置显示日期的元素 * @param {Date | number | string} val - 日期值,支持格式参见 {@linkcode formatDate} */ export function setDateValue(element, val) { if (element.tagName === 'INPUT') { if (val === '') { element.value = ''; } else if (isNaN(val)) { if (/^\d{4}-\d{2}-\d{2}/.test(val)) { element.value = String(val).substring(0, 10); } else { const e = /^(\d{1,2})\/(\d{1,2})\/(\d{4})$/.exec(val); if (e != null) { const month = e[1].padStart(2, '0'); const day = e[2].padStart(2, '0'); const year = e[3]; element.value = `${year}-${month}-${day}`; } else { element.value = ''; } } } else { if (val instanceof Date) { element.value = toDateValue(val); } else { const ticks = Number(val); if (!isNaN(ticks) && ticks > 0) { element.value = toDateValue(new Date((ticks - 621355968e9) / 1e4)); } else { element.value = ''; } } } } else { element.innerText = formatDate(val); } } /** * 自定义日期格式化回调函数 * @callback DateFormatterCallback * @param {Date} date - 日期值 * @returns {any} 返回格式化后的结果 */ /** * 从日期选择框获取日期值 * @param {HTMLInputElement} element - 要获取的日期选择框 * @param {DateFormatterCallback} [formatter] - 自定义格式化函数,传入参数为 `Date` 类型 * @returns {string | any} 默认返回日期 `ticks` 的字符串 */ export function getDateValue(element, formatter) { const date = element?.valueAsDate; if (date instanceof Date && !isNaN(date)) { const year = date.getUTCFullYear(); if (year < 1900 || year > 9999) { return ''; } if (typeof formatter === 'function') { const month = String(date.getUTCMonth() + 1).padStart(2, '0'); const day = String(date.getUTCDate()).padStart(2, '0'); // 使外部 formatter 不需要再处理 `getUTCDate` 亦或是 `getDate` return formatter(new Date(`${year}-${month}-${day}T00:00:00`)); } return String(date.getTime() * 1e4 + 621355968e9); } return ''; } /** * 日期选择框类 * @class */ export class DateSelector { _var = { /** * @type {HTMLInputElement} * @private */ el: null, options: { /** * @type {boolean?} * @private */ enabled: true, /** * @type {string?} * @private */ minDate: null, /** * @type {string?} * @private */ maxDate: null, /** * @type {DateFormatterCallback?} * @private */ valueFormatter: null } }; /** * 日期发生变化时触发的事件 * @event * @param {Date} date - 修改后的日期值 * @this DateSelector */ onDateChanged; /** * 日期选择框构造函数 * @constructor * @param {object} [opts] - 日期选择框初始化参数 * @param {boolean} [opts.enabled] - 是否可用 * @param {string} [opts.minDate] - 最小可选择日期 * @param {string} [opts.maxDate] - 最大可选择日期 * @param {DateFormatterCallback} [opts.valueFormatter] - 自定义格式化函数 * @example