720 lines
21 KiB
JavaScript
720 lines
21 KiB
JavaScript
import { global } from "../../utility";
|
||
import { createElement } from "../../functions";
|
||
import { createIcon } from "../icon";
|
||
import { createCheckbox } from "../checkbox";
|
||
// import { setTooltip } from "../tooltip";
|
||
import { Dropdown } from "../dropdown";
|
||
import { convertCssStyle } from "../extension";
|
||
import { createDateInput, formatDate, setDateValue, getDateValue } from "../date";
|
||
// definition
|
||
import { DropdownOptions, GridItemBooleanCallback, GridDropdownSourceCallback, DateFormatterCallback, GridSourceItem, GridItemWrapper, Grid } from "./grid";
|
||
|
||
/**
|
||
* @ignore
|
||
* @callback DropExpandedCallback
|
||
* @param {Map<string, ValueItem>} item - 行数据对象
|
||
* @param {Dropdown} drop - 下拉框对象
|
||
* @this GridColumnDefinition
|
||
*/
|
||
|
||
/**
|
||
* 列定义接口
|
||
* @ignore
|
||
* @typedef GridColumnDefinition
|
||
* @property {string} key - 列关键字,默认以该关键字从行数据中提取单元格值,行数据的关键字属性值里包含 DisplayValue 则优先显示此值
|
||
* @property {(boolean | string | GridItemBooleanCallback)} [enabled] - 列是否可用(可编辑),允许以下类型
|
||
*
|
||
* * `boolean` 则直接使用该值
|
||
* * `string` 则以该值为关键字从行数据中取值作为判断条件
|
||
* * `GridItemBooleanCallback` 则调用如下回调,以返回值作为判断条件
|
||
* @property {DropdownOptions} [dropOptions] - 列为下拉列表类型时以该值设置下拉框的参数
|
||
* @property {(GridSourceItem[] | Promise<GridSourceItem[]> | GridDropdownSourceCallback)} [source] - 列为下拉列表类型时以该值设置下拉列表数据源,支持返回异步对象,也支持如下函数返回
|
||
* @property {boolean} [sourceCache=false] - 下拉列表数据源是否缓存结果(即行数据未发生变化时仅从source属性获取一次值)
|
||
* @property {("fa-light" | "fa-regular" | "fa-solid")} [iconType=fa-light] - 列为图标类型时以该值设置图标样式
|
||
* @property {string} [dateMin] - 列为日期类型时以该值作为最小可选日期值
|
||
* @property {string} [dateMax] - 列为日期类型时以该值作为最大可选日期值
|
||
* @property {DateFormatterCallback} [dateValueFormatter] - 列为日期类型时自定义日期格式化函数
|
||
* @property {DropExpandedCallback} [onDropExpanded] - 列为下拉框类型时在下拉列表展开时触发的事件
|
||
*/
|
||
|
||
/**
|
||
* 列定义基类
|
||
*
|
||
* _函数调用流程图示_<br/>
|
||
* <img src="./assets/column-refresh.jpg" alt="Column Refresh"/>
|
||
* @class
|
||
* @static
|
||
* @hideconstructor
|
||
*/
|
||
export class GridColumn {
|
||
/**
|
||
* 设置该类型是否支持触发 {@linkcode GridColumnDefinition}`.onInputEnded` 方法<br/>
|
||
* 该属性返回 `true` 后,在任意事件中修改行包装对象的 `__editing` 值,则会在行列元素变动时及时触发 [onInputEnded]{@linkcode GridColumnDefinition#onInputEnded} 方法,避免例如文本框还未触发 `onchange` 事件就被移除元素而导致的问题
|
||
*
|
||
* 更多例子参考代码中 {@linkcode GridInputColumn} 的实现
|
||
* @member
|
||
* @name GridColumn.editing
|
||
* @readonly
|
||
* @type {boolean}
|
||
*/
|
||
|
||
/**
|
||
* 创建显示单元格时调用的方法
|
||
* @param {GridColumnDefinition} col - 列定义对象
|
||
* @param {number} index - 行元素索引(需要配合 [startIndex]{@linkcode Grid#startIndex} 相加得到真实数据索引)
|
||
* @param {Grid} grid - Grid 实例
|
||
* @returns {HTMLElement} 返回创建的单元格元素
|
||
* @virtual
|
||
*/
|
||
static create() {
|
||
return createElement('span');
|
||
}
|
||
|
||
/**
|
||
* 创建编辑单元格时调用的方法
|
||
*
|
||
* 元素修改后设置行包装对象的 `__editing` 后,支持在离开编辑状态时及时触发 [leaveEdit]{@linkcode GridColumn.leaveEdit} 方法<br/>
|
||
* 更多例子参考代码中 {@linkcode GridDropdownColumn} 的实现。
|
||
* @method
|
||
* @name GridColumn.createEdit
|
||
* @param {Function} trigger - 编辑事件回调函数,`e` 参数会传递给 [getValue]{@linkcode GridColumn.getValue} 方法
|
||
* @param {GridColumnDefinition} col - 列定义对象
|
||
* @param {HTMLElement} container - 父容器元素
|
||
* @param {GridItemWrapper} wrapper - 行包装对象,其 `values` 属性为行数据对象
|
||
* @returns {HTMLElement} 返回创建的编辑状态的单元格元素
|
||
* @virtual
|
||
*/
|
||
|
||
/**
|
||
* 创建列头时调用的方法
|
||
* @method
|
||
* @name GridColumn.createCaption
|
||
* @param {GridColumnDefinition} col - 列定义对象
|
||
* @returns {HTMLElement} 返回创建的列头元素
|
||
* @virtual
|
||
*/
|
||
|
||
/**
|
||
* 获取编辑状态单元格值时调用的方法
|
||
* @method
|
||
* @name GridColumn.getValue
|
||
* @param {any} e - 由 [createEdit]{@linkcode GridColumn.createEdit} 方法中 `trigger` 函数传递来的对象
|
||
* @param {GridColumnDefinition} col - 列定义对象
|
||
* @returns {(string | boolean | number)} 返回单元格的值
|
||
* @virtual
|
||
*/
|
||
|
||
/**
|
||
* 设置单元格值时调用的方法
|
||
* @param {HTMLElement} element - 单元格元素
|
||
* @param {(string | boolean | number)} val - 待设置的单元格值
|
||
* @param {GridItemWrapper} wrapper - 行包装对象
|
||
* @param {GridColumnDefinition} col - 列定义对象
|
||
* @param {Grid} grid - Grid 对象
|
||
* @virtual
|
||
*/
|
||
static setValue(element, val) {
|
||
element.innerText = val;
|
||
}
|
||
|
||
/**
|
||
* 设置单元格样式时调用的方法
|
||
* @param {HTMLElement} element - 单元格元素
|
||
* @param {object} style - 样式对象
|
||
* @virtual
|
||
*/
|
||
static setStyle(element, style) {
|
||
// for (let css of Object.entries(style)) {
|
||
// element.style.setProperty(css[0], css[1]);
|
||
// }
|
||
element.style.cssText = convertCssStyle(style);
|
||
}
|
||
|
||
/**
|
||
* 设置单元格类名时调用的方法
|
||
* @param {HTMLElement} element - 单元格元素
|
||
* @param {string} name - 要设置的类名
|
||
* @virtual
|
||
*/
|
||
static setClass(element, name) {
|
||
element.className = name ?? '';
|
||
}
|
||
|
||
/**
|
||
* 设置单元格可用性时调用的方法
|
||
* @param {HTMLElement} element - 单元格元素
|
||
* @param {boolean} enabled - 启用值,为 `false` 时代表禁用
|
||
* @virtual
|
||
*/
|
||
static setEnabled(element, enabled) {
|
||
const tooltip = element.querySelector('.ui-tooltip-wrapper');
|
||
if (tooltip != null) {
|
||
tooltip.style.display = enabled === false ? 'none' : '';
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 单元格离开编辑元素时触发,需要由行包装对象的 `__editing` 来确定是否触发。
|
||
* @method
|
||
* @name GridColumn.leaveEdit
|
||
* @param {HTMLElement} element - 单元格元素
|
||
* @param {HTMLElement} container - 父容器元素
|
||
* @virtual
|
||
*/
|
||
|
||
/**
|
||
* @ignore
|
||
*/
|
||
static toString() { return '[object Column]' }
|
||
}
|
||
|
||
/**
|
||
* 单行文本输入列
|
||
* @class
|
||
* @static
|
||
* @extends GridColumn
|
||
* @hideconstructor
|
||
*/
|
||
export class GridInputColumn extends GridColumn {
|
||
static get editing() { return true };
|
||
|
||
/**
|
||
* @ignore
|
||
* @param {Function} trigger
|
||
* @param {GridColumnDefinition} col
|
||
* @param {HTMLElement} _container
|
||
* @param {GridItemWrapper} wrapper
|
||
* @returns {HTMLElement}
|
||
*/
|
||
static createEdit(trigger, col, _container, wrapper) {
|
||
const input = createElement('input');
|
||
input.setAttribute('type', 'text');
|
||
if (typeof trigger === 'function') {
|
||
input.addEventListener('change', trigger);
|
||
}
|
||
input.addEventListener('input', () => {
|
||
if (wrapper.__editing == null) {
|
||
wrapper.__editing = {
|
||
[col.key]: true
|
||
}
|
||
} else {
|
||
wrapper.__editing[col.key] = true;
|
||
}
|
||
});
|
||
return input;
|
||
}
|
||
|
||
/**
|
||
* @ignore
|
||
* @param {HTMLElement} element
|
||
* @param {string} val
|
||
*/
|
||
static setValue(element, val) {
|
||
if (element.tagName !== 'INPUT') {
|
||
super.setValue(element, val);
|
||
} else {
|
||
element.value = val;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* @ignore
|
||
* @param {Event} e
|
||
* @returns {string}
|
||
*/
|
||
static getValue(e) { return e.target.value }
|
||
|
||
/**
|
||
* @ignore
|
||
* @param {HTMLElement} element
|
||
* @param {boolean} enabled
|
||
*/
|
||
static setEnabled(element, enabled) {
|
||
super.setEnabled(element, enabled);
|
||
element.disabled = enabled === false;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 多行文本输入列
|
||
* @class
|
||
* @static
|
||
* @extends GridInputColumn
|
||
* @hideconstructor
|
||
* @ignore
|
||
*/
|
||
export class GridTextColumn extends GridInputColumn {
|
||
/**
|
||
* @ignore
|
||
* @param {Function} trigger
|
||
* @param {GridColumnDefinition} col
|
||
* @param {HTMLElement} _container
|
||
* @param {GridItemWrapper} wrapper
|
||
* @returns {HTMLElement}
|
||
*/
|
||
static createEdit(trigger, col, _container, wrapper) {
|
||
const input = createElement('textarea');
|
||
if (typeof trigger === 'function') {
|
||
input.addEventListener('change', trigger);
|
||
}
|
||
input.addEventListener('input', () => {
|
||
if (wrapper.__editing == null) {
|
||
wrapper.__editing = {
|
||
[col.key]: true
|
||
}
|
||
} else {
|
||
wrapper.__editing[col.key] = true;
|
||
}
|
||
});
|
||
return input;
|
||
}
|
||
|
||
/**
|
||
* @ignore
|
||
* @param {HTMLElement} element
|
||
* @param {string} val
|
||
* @param {GridItemWrapper} _wrapper
|
||
* @param {GridColumnDefinition} _col
|
||
* @param {Grid} grid
|
||
*/
|
||
static setValue(element, val, _wrapper, _col, grid) {
|
||
if (element.tagName !== 'TEXTAREA') {
|
||
super.setValue(element, val);
|
||
} else {
|
||
element.value = val;
|
||
if (val != null) {
|
||
const lines = String(val).split('\n').length;
|
||
element.style.height = `${lines * grid.lineHeight + 12}px`;
|
||
}
|
||
// TODO: bad performance
|
||
}
|
||
}
|
||
}
|
||
|
||
const SymbolDropdown = Symbol.for('ui-dropdown');
|
||
|
||
/**
|
||
* 下拉选择列
|
||
* @class
|
||
* @static
|
||
* @extends GridColumn
|
||
* @hideconstructor
|
||
*/
|
||
export class GridDropdownColumn extends GridColumn {
|
||
/**
|
||
* @ignore
|
||
* @param {Function} trigger
|
||
* @param {GridColumnDefinition} col
|
||
* @param {HTMLElement} container
|
||
* @param {GridItemWrapper} wrapper
|
||
* @returns {HTMLElement}
|
||
*/
|
||
static createEdit(trigger, col, container, wrapper) {
|
||
const drop = new Dropdown({
|
||
...col.dropOptions,
|
||
wrapper: container.parentElement
|
||
});
|
||
drop.onSelected = trigger;
|
||
drop.onExpanded = () => {
|
||
if (wrapper.__editing == null) {
|
||
wrapper.__editing = {
|
||
[col.key]: true
|
||
}
|
||
} else {
|
||
wrapper.__editing[col.key] = true;
|
||
}
|
||
if (typeof col.onDropExpanded === 'function') {
|
||
col.onDropExpanded.call(col, wrapper.values, drop);
|
||
}
|
||
};
|
||
return drop.create();
|
||
}
|
||
|
||
/**
|
||
* @private
|
||
* @param {HTMLElement} element
|
||
* @returns {Dropdown}
|
||
*/
|
||
static _getDrop(element) {
|
||
/**
|
||
* @type {Map<string, Dropdown>}
|
||
*/
|
||
const dropGlobal = global[SymbolDropdown];
|
||
if (dropGlobal == null) {
|
||
return null;
|
||
}
|
||
const dropId = element.dataset.dropId;
|
||
const drop = dropGlobal[dropId];
|
||
if (drop == null) {
|
||
return null;
|
||
}
|
||
return drop;
|
||
}
|
||
|
||
/**
|
||
* @private
|
||
* @param {GridItemWrapper} wrapper
|
||
* @param {GridColumnDefinition} col
|
||
* @returns {GridSourceItem[]}
|
||
*/
|
||
static _getSource(wrapper, col) {
|
||
let source;
|
||
if (col.sourceCache !== false) {
|
||
source = wrapper.source?.[col.key];
|
||
if (source != null) {
|
||
return source;
|
||
}
|
||
}
|
||
source = col.source;
|
||
if (typeof source === 'function') {
|
||
source = source(wrapper.values);
|
||
}
|
||
if (col.sourceCache !== false) {
|
||
if (wrapper.source == null) {
|
||
wrapper.source = { [col.key]: source };
|
||
} else {
|
||
wrapper.source[col.key] = source;
|
||
}
|
||
}
|
||
return source;
|
||
}
|
||
|
||
/**
|
||
* @private
|
||
* @param {GridSourceItem[]} source
|
||
* @param {HTMLElement} element
|
||
* @param {any} val
|
||
* @param {DropdownOptions} opts
|
||
*/
|
||
static _setValue(source, element, val, opts) {
|
||
const data = source?.find(v => v[opts?.valueKey ?? 'value'] === val);
|
||
if (data != null) {
|
||
val = data[opts?.textKey ?? 'text'];
|
||
}
|
||
super.setValue(element, val);
|
||
}
|
||
|
||
/**
|
||
* @ignore
|
||
* @param {HTMLElement} element
|
||
* @param {any} val
|
||
* @param {GridItemWrapper} wrapper
|
||
* @param {GridColumnDefinition} col
|
||
*/
|
||
static setValue(element, val, wrapper, col) {
|
||
if (element.tagName !== 'DIV') {
|
||
let source = this._getSource(wrapper, col);
|
||
if (source instanceof Promise) {
|
||
source.then(s => this._setValue(s, element, val, col.dropOptions));
|
||
} else {
|
||
this._setValue(source, element, val, col.dropOptions);
|
||
}
|
||
return;
|
||
}
|
||
const drop = this._getDrop(element);
|
||
if (drop == null) {
|
||
return;
|
||
}
|
||
if (drop.source == null || drop.source.length === 0) {
|
||
let source = this._getSource(wrapper, col);
|
||
if (source instanceof Promise) {
|
||
source.then(s => {
|
||
drop.source = s;
|
||
drop.select(val, true);
|
||
})
|
||
return;
|
||
} else if (source != null) {
|
||
drop.source = source;
|
||
}
|
||
}
|
||
drop.select(val, true);
|
||
}
|
||
|
||
/**
|
||
* @ignore
|
||
* @param {GridSourceItem} e
|
||
* @param {GridColumnDefinition} col
|
||
* @returns {any}
|
||
*/
|
||
static getValue(e, col) {
|
||
return e[col.dropOptions?.valueKey ?? 'value'];
|
||
}
|
||
|
||
/**
|
||
* @ignore
|
||
* @param {HTMLElement} element
|
||
* @param {string} name
|
||
*/
|
||
static setClass(element, name) {
|
||
if (element.tagName === 'DIV') {
|
||
element.className = `ui-drop-wrapper ${name ?? ''}`;
|
||
} else {
|
||
super.setClass(element, name);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* @ignore
|
||
* @param {HTMLElement} element
|
||
* @param {boolean} enabled
|
||
*/
|
||
static setEnabled(element, enabled) {
|
||
super.setEnabled(element, enabled);
|
||
const drop = this._getDrop(element);
|
||
if (drop == null) {
|
||
return;
|
||
}
|
||
drop.disabled = enabled === false;
|
||
}
|
||
|
||
/**
|
||
* @ignore
|
||
* @param {HTMLElement} element
|
||
* @param {HTMLElement} container
|
||
*/
|
||
static leaveEdit(element, container) {
|
||
container.parentElement.querySelectorAll('.ui-drop-box.active').forEach(e => {
|
||
if (e != null) {
|
||
e.classList.remove('active');
|
||
}
|
||
});
|
||
const drop = this._getDrop(element);
|
||
if (drop == null) {
|
||
return;
|
||
}
|
||
if (drop?.multiSelect && typeof drop.onCollapsed === 'function') {
|
||
drop.onCollapsed();
|
||
}
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 复选框列
|
||
* @class
|
||
* @static
|
||
* @extends GridColumn
|
||
* @hideconstructor
|
||
* @ignore
|
||
*/
|
||
export class GridCheckboxColumn extends GridColumn {
|
||
/**
|
||
* @ignore
|
||
* @param {Function} trigger
|
||
* @returns {HTMLElement}
|
||
*/
|
||
static createEdit(trigger) {
|
||
const check = createCheckbox({
|
||
onchange: typeof trigger === 'function' ? trigger : null
|
||
});
|
||
return check;
|
||
}
|
||
|
||
/**
|
||
* @ignore
|
||
* @param {HTMLElement} element
|
||
* @param {boolean} val
|
||
*/
|
||
static setValue(element, val) {
|
||
element.querySelector('input').checked = val;
|
||
}
|
||
|
||
/**
|
||
* @ignore
|
||
* @param {Event} e
|
||
* @returns {boolean}
|
||
*/
|
||
static getValue(e) { return e.target.checked }
|
||
|
||
/**
|
||
* @ignore
|
||
* @param {HTMLElement} element
|
||
* @param {string} name
|
||
*/
|
||
static setClass(element, name) {
|
||
if (element.tagName === 'LABEL') {
|
||
element.className = `ui-check-wrapper ${name ?? ''}`;
|
||
} else {
|
||
super.setClass(element, name);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* @ignore
|
||
* @param {HTMLElement} element
|
||
* @param {boolean} enabled
|
||
*/
|
||
static setEnabled(element, enabled) {
|
||
super.setEnabled(element, enabled);
|
||
element.querySelector('input').disabled = enabled === false;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 图标列
|
||
* @class
|
||
* @static
|
||
* @extends GridColumn
|
||
* @hideconstructor
|
||
* @ignore
|
||
*/
|
||
export class GridIconColumn extends GridColumn {
|
||
/**
|
||
* @ignore
|
||
* @returns {HTMLElement}
|
||
*/
|
||
static create() { return createElement('span', 'col-icon') }
|
||
|
||
/**
|
||
* @ignore
|
||
* @param {HTMLElement} element
|
||
* @param {string} val
|
||
* @param {GridItemWrapper} wrapper
|
||
* @param {GridColumnDefinition} col
|
||
*/
|
||
static setValue(element, val, wrapper, col) {
|
||
// let className = col.iconClassName;
|
||
// if (typeof className === 'function') {
|
||
// className = className.call(col, wrapper.values);
|
||
// }
|
||
// if (className == null) {
|
||
// element.className = 'col-icon';
|
||
// } else {
|
||
// element.className = `col-icon ${className}`;
|
||
// }
|
||
let type = col.iconType;
|
||
if (typeof type === 'function') {
|
||
type = type.call(col, wrapper.values);
|
||
}
|
||
type ??= 'fa-light';
|
||
if (element.dataset.type !== type || element.dataset.icon !== val) {
|
||
const icon = createIcon(type, val);
|
||
// const layer = element.children[0];
|
||
element.replaceChildren(icon);
|
||
// !nullOrEmpty(col.tooltip) && setTooltip(element, col.tooltip, false, grid.element);
|
||
element.dataset.type = type;
|
||
element.dataset.icon = val;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* @ignore
|
||
* @param {HTMLElement} element
|
||
* @param {string} name
|
||
*/
|
||
static setClass(element, name) {
|
||
element.className = `col-icon ${name ?? ''}`;
|
||
}
|
||
|
||
/**
|
||
* @ignore
|
||
* @param {HTMLElement} element
|
||
* @param {boolean} enabled
|
||
*/
|
||
static setEnabled(element, enabled) {
|
||
super.setEnabled(element, enabled);
|
||
if (enabled === false) {
|
||
element.classList.add('disabled');
|
||
} else {
|
||
element.classList.remove('disabled');
|
||
}
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 日期选择列
|
||
* @class
|
||
* @static
|
||
* @extends GridColumn
|
||
* @hideconstructor
|
||
*/
|
||
export class GridDateColumn extends GridColumn {
|
||
static get editing() { return true };
|
||
|
||
/**
|
||
* @ignore
|
||
* @param {Function} trigger
|
||
* @param {GridColumnDefinition} col
|
||
* @param {HTMLElement} _container
|
||
* @param {GridItemWrapper} wrapper
|
||
* @returns {HTMLElement}
|
||
*/
|
||
static createEdit(trigger, col, _container, wrapper) {
|
||
let enabled = col.enabled;
|
||
if (typeof enabled === 'string') {
|
||
enabled = wrapper.values[enabled];
|
||
} else if (typeof enabled === 'function') {
|
||
enabled = col.enabled(wrapper.values);
|
||
}
|
||
if (enabled === false) {
|
||
return super.create();
|
||
}
|
||
const date = createDateInput(col.dateMin, col.dateMax);
|
||
date.addEventListener('change', () => {
|
||
if (wrapper.__editing == null) {
|
||
wrapper.__editing = {
|
||
[col.key]: true
|
||
}
|
||
} else {
|
||
wrapper.__editing[col.key] = true;
|
||
}
|
||
});
|
||
date.addEventListener('blur', trigger);
|
||
return date;
|
||
}
|
||
|
||
/**
|
||
* @ignore
|
||
* @param {HTMLElement} element
|
||
* @param {(string | number | Date)} val
|
||
*/
|
||
static setValue(element, val) {
|
||
setDateValue(element, val);
|
||
}
|
||
|
||
/**
|
||
* @ignore
|
||
* @param {Event} e
|
||
* @param {GridColumnDefinition} col
|
||
* @returns {string}
|
||
*/
|
||
static getValue(e, col) {
|
||
return getDateValue(e.target, col.dateValueFormatter);
|
||
}
|
||
|
||
/**
|
||
* @ignore
|
||
* @param {HTMLElement} element
|
||
* @param {string} name
|
||
*/
|
||
static setClass(element, name) {
|
||
if (element.tagName === 'INPUT') {
|
||
element.className = `ui-date-cell ${name ?? ''}`;
|
||
} else {
|
||
super.setClass(element, name);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* @ignore
|
||
* @param {HTMLElement} element
|
||
* @param {boolean} enabled
|
||
*/
|
||
static setEnabled(element, enabled) {
|
||
element.disabled = enabled === false;
|
||
}
|
||
|
||
/**
|
||
* 格式化日期字符串
|
||
* @param {(string | number | Date)} date - 要格式化的日期值
|
||
*
|
||
* 支持以下几种数据类型
|
||
* * `"2024-01-26"`
|
||
* * `"1/26/2024"`
|
||
* * `"638418240000000000"`
|
||
* * `new Date('2024-01-26')`
|
||
* @returns {string} 格式化为 M/d/yyyy 的日期字符串
|
||
*/
|
||
static formatDate(date) {
|
||
return formatDate(date);
|
||
}
|
||
} |