add more comments

This commit is contained in:
2024-02-02 16:02:34 +08:00
parent 5d199a2bfb
commit bed5c1aca1
5 changed files with 237 additions and 125 deletions

View File

@ -128,55 +128,6 @@ let r = lang;
* @returns {GridSourceItem[]} 行下拉列表数据源
*/
/**
* 列头复选框改变时的回调函数
* @callback GridColumnCheckedCallback
* @param {GridColumnDefinition} col - 列定义对象
* @param {boolean} flag - 是否选中
* @this Grid
*/
/**
* 单元格发生变化时的回调函数
* @callback GridCellChangedCallback
* @param {GridItem} item - 行数据对象
* @param {(boolean | string | number)} value - 修改后的值
* @param {(boolean | string | number)} oldValue - 修改前的值
* @param {any} [e] - 列修改事件传递过来的任意对象
* @this Grid
*/
/**
* 文本单元格输入完成时的回调函数
* @callback GridCellInputEndedCallback
* @param {GridColumnDefinition} col - 列定义对象
* @param {string} value - 修改后的文本框值
* @this Grid
*/
/**
* 列过滤点 `OK` 时的回调函数
* @callback GridColumnFilterOkCallback
* @param {GridColumnDefinition} col - 列定义对象
* @param {GridItem[]} selected - 选中的过滤项
* @this Grid
*/
/**
* 列过滤后的回调函数
* @callback GridColumnFilteredCallback
* @param {GridColumnDefinition} col - 列定义对象
* @this Grid
*/
/**
* 下拉框列表展开时的回调函数
* @callback GridColumnDropExpandedCallback
* @param {GridItem} item - 行数据对象
* @param {Dropdown} drop - 拉框对象
* @this GridColumnDefinition
*/
/**
* 下拉列表参数对象
* @typedef DropdownOptions
@ -207,7 +158,7 @@ let r = lang;
/**
* 列定义接口
* @typedef {object} GridColumnDefinition
* @class
* @property {string} key - 列关键字,默认以该关键字从行数据中提取单元格值,行数据的关键字属性值里包含 DisplayValue 则优先显示此值
* @property {(GridColumnTypeEnum | GridColumn)} [type=Grid.ColumnTypes.Common] - 列的类型,可以为 {@linkcode GridColumn} 的子类,或者如下内置类型 {@linkcode Grid.ColumnTypes}
* @property {number} type.Common=0 - 通用列(只读)
@ -241,15 +192,19 @@ let r = lang;
* @property {boolean} [sortable=true] - 列是否允许排序
* @property {boolean} [orderable=true] - 列是否允许重排顺序
* @property {boolean} [allcheck=false] - 列为复选框类型时是否在列头增加全选复选框
* @property {boolean} [shrink=false] - 列为收缩列,禁用自动调整大小
* @property {string} [class] - 单元格元素的额外样式类型字符串(仅在重建行元素时读取)
* @property {object} [css] - 单元格css样式对象仅在重建行元素时读取
* @property {GridItemObjectCallback} [styleFilter] - 根据返回值填充单元格样式(填充行列数据时读取
* @property {GridColumnDefinition} styleFilter.{this} - 上下文为列定义对象
* @property {GridItem} styleFilter.item - 行数据对象
* @property {object} styleFilter.{returns} - 返回样式对象
* @property {GridItemStringCallback} [bgFilter] - 根据返回值设置单元格背景色
* @property {GridColumnDefinition} bgFilter.{this} - 上下文为列定义对象
* @property {GridItem} bgFilter.item - 行数据对象
* @property {string} bgFilter.{returns} - 返回单元格背景色字符串
* @property {(object | GridItemObjectCallback)} [style] - 单元格样式(填充行列数据时读取),支持直接返回样式对象或调用函数返回(若赋值则忽略 [styleFilter]{@linkcode GridColumnDefinition#styleFilter}
* @property {GridColumnDefinition} style.{this} - 上下文为列定义对象
* @property {GridItem} style.item - 行数据对象
* @property {object} style.{returns} - 返回样式对象
* @property {(@deprecated)} [styleFilter] - **已过时**<br/>_根据返回值填充单元格样式填充行列数据时读取_
* @property {(string | GridItemStringCallback)} [background] - 设置单元格背景色(填充行列数据时读取),支持直接设置颜色字符串或调用函数返回(若赋值则忽略 [bgFilter]{@linkcode GridColumnDefinition#bgFilter}
* @property {GridColumnDefinition} background.{this} - 上下文为列定义对象
* @property {GridItem} background.item - 行数据对象
* @property {string} background.{returns} - 返回单元格背景色字符串
* @property {(@deprecated)} [bgFilter] - **已过时**<br/>_根据返回值设置单元格背景色_
* @property {object} [events] - 给单元格元素附加事件(事件函数上下文为数据行对象)
* @property {Function} events.{event} - 事件回调函数
* @property {(object | GridItemObjectCallback)} [attrs] - 根据返回值设置单元格元素的附加属性,允许直接设置对象也支持调用如下函数返回对象
@ -271,10 +226,6 @@ let r = lang;
* @property {GridSourceItem[]} source.{returns} - 返回行下拉列表数据源
* @property {boolean} [sourceCache=false] - 下拉列表数据源是否缓存结果即行数据未发生变化时仅从source属性获取一次值
* @property {("fa-light" | "fa-regular" | "fa-solid")} [iconType=fa-light] - 列为图标类型时以该值设置图标样式
* @property {(string | GridItemStringCallback)} [iconClassName] - 列为图标类型时以该值作为单元格元素的额外样式类型,支持直接使用字符串或者调用如下函数
* @property {GridColumnDefinition} iconClassName.{this} - 上下文为列定义对象
* @property {GridItem} iconClassName.item - 行数据对象
* @property {string} iconClassName.{returns} - 返回额外样式类型字符串
* @property {string} [dateMin] - 列为日期类型时以该值作为最小可选日期值
* @property {string} [dateMax] - 列为日期类型时以该值作为最大可选日期值
* @property {DateFormatterCallback} [dateValueFormatter] - 列为日期类型时自定义日期格式化函数
@ -284,32 +235,59 @@ let r = lang;
* @property {GridColumnDefinition} tooltip.{this} - 上下文为列定义对象
* @property {GridItem} tooltip.item - 行数据对象
* @property {string} tooltip.{returns} - 返回额外 tooltip 字符串
* @property {GridColumnCheckedCallback} [onAllChecked] - 列头复选框改变时触发
* @property {Grid} onAllChecked.{this} - 上下文为 Grid
* @property {GridColumnDefinition} onAllChecked.col - 列定义对象
* @property {boolean} onAllChecked.flag - 是否选中
* @property {GridCellChangedCallback} [onChanged] - 单元格发生变化时触发
* @property {Grid} onChanged.{this} - 上下文为 Grid
* @property {GridItem} onChanged.item - 行数据对象
* @property {(boolean | string | number)} onChanged.value - 修改后的值
* @property {(boolean | string | number)} onChanged.oldValue - 修改前的值
* @property {any} [onChanged.e] - 列修改事件传递过来的任意对象
* @property {GridCellInputEndedCallback} [onInputEnded] - 文本单元格在输入完成时触发的事件
* @property {Grid} onInputEnded.{this} - 上下文为 Grid
* @property {GridColumnDefinition} onInputEnded.col - 列定义对象
* @property {string} onInputEnded.value - 修改后的文本框值
* @property {GridColumnFilterOkCallback} [onFilterOk] - 列过滤点击 `OK` 时触发的事件
* @property {Grid} onFilterOk.{this} - 上下文为 Grid
* @property {GridColumnDefinition} onFilterOk.col - 列定义对象
* @property {GridItem[]} onFilterOk.selected - 选中的过滤项
* @property {GridColumnFilteredCallback} [onFiltered] - 列过滤后触发的事件
* @property {Grid} onFiltered.{this} - 上下文为 Grid
* @property {GridColumnDefinition} onFiltered.col - 列定义对象
* @property {GridColumnDropExpandedCallback} [onDropExpanded] - 列为下拉框类型时在下拉列表展开时触发的事件
* @property {GridColumnDefinition} onDropExpanded.{this} - 上下文为列定义对象
* @property {GridItem} onDropExpanded.item - 行数据对象
* @property {Dropdown} onDropExpanded.drop - 拉框对象
*/
class GridColumnDefinition {
/**
* 列头复选框改变时触发
* @type {Function}
* @event
* @param {GridColumnDefinition} col - 列定义对象
* @param {boolean} flag - 是否选中
* @this Grid
*/
onAllChecked;
/**
* 单元格发生变化时触发
* @event
* @param {GridItem} item - 行数据对象
* @param {(boolean | string | number)} value - 修改后的值
* @param {(boolean | string | number)} oldValue - 修改前的值
* @param {any} [e] - 列修改事件传递过来的任意对象
* @this Grid
*/
onChanged;
/**
* 文本单元格在输入完成时触发的事件
* @event
* @param {GridColumnDefinition} col - 列定义对象
* @param {string} value - 修改后的文本框值
* @this Grid
*/
onInputEnded;
/**
* 列过滤点击 `OK` 时触发的事件
* @event
* @param {GridColumnDefinition} col - 列定义对象
* @param {GridItem[]} selected - 选中的过滤项
* @this Grid
*/
onFilterOk;
/**
* 列过滤后触发的事件
* @event
* @param {GridColumnDefinition} col - 列定义对象
* @this Grid
*/
onFiltered;
/**
* 列为下拉框类型时在下拉列表展开时触发的事件
* @event
* @param {GridItem} item - 行数据对象
* @param {Dropdown} drop - 拉框对象
* @this GridColumnDefinition
*/
onDropExpanded;
}
/**
* 判断复选框列的回调函数
@ -424,73 +402,92 @@ const GridColumnDirection = {
* ];
*/
export class Grid {
/**
* 内部引用变量
* @private
*/
_var = {
/**
* 父容器元素
* @type {HTMLElement}
* @private
*/
parent: null,
/**
* Grid 元素 - `div.ui-grid`
* @type {HTMLDivElement}
* @private
*/
el: null,
/**
* 全部数据数组
* @type {GridItemWrapper[]}
* @private
*/
source: null,
/**
* 当前已过滤显示的数据数组
* @type {GridItemWrapper[]}
* @private
*/
currentSource: null,
/**
* 当前选中的列索引
* @type {number}
* @private
*/
selectedColumnIndex: -1,
/**
* 当前选中的行索引数组
* @type {number[]}
* @private
*/
selectedIndexes: null,
/**
* 虚模式头部索引
* @type {number}
* @private
*/
startIndex: 0,
/**
* 旧选择索引数组
* @type {number[]}
* @private
*/
oldSelectedIndexes: null,
/**
* 旧虚模式头部索引
* @type {number}
* @private
*/
oldIndex: null,
/**
* 当前滚动上边距
* @private
* @type {number}
*/
scrollTop: 0,
/**
* 当前滚动左边距
* @private
* @type {number}
*/
scrollLeft: 0,
/**
* 一页高度可显示的行数
* @private
* @type {number}
*/
rowCount: -1,
/**
* 列类型缓存字典
* @private
* @property {GridColumn} {key} - 关键字对应列的类型缓存对象
*/
colTypes: {},
/**
* 列属性字典
* @private
* @property {object} {key} - 关键字对应列的拖拽、调整大小暂存对象
* @property {boolean} {key}.dragging - 列正在拖拽
* @property {number} {key}.offset - 列拖拽偏移
@ -508,81 +505,103 @@ export class Grid {
/**
* 有已过滤的列
* @type {boolean}
* @private
*/
__filtered: false,
/**
* 过滤面板已打开
* @type {boolean}
* @private
*/
__filtering: false,
/**
* 上一个目标排序列索引
* @type {number}
* @private
*/
__orderIndex: -1,
},
/**
* 是否处于渲染中
* @type {boolean}
* @private
*/
rendering: false,
/**
* 头部高度
* @type {number}
* @private
*/
headerHeight: null,
/**
* 正文高度
* @type {number}
* @private
*/
containerHeight: null,
/**
* 正文宽度
* @type {number}
* @private
*/
bodyClientWidth: null,
/**
* 是否需要 resize
* @type {boolean}
* @private
*/
needResize: null,
/**
* 页面元素引用
* @private
*/
refs: {
/**
* 表格引用 - table.ui-grid-table
* @type {HTMLTableElement}
* @private
*/
table: null,
/**
* 表格正文引用 - tbody
* @type {HTMLTableSectionElement}
* @private
*/
body: null,
/**
* 表格头部引用 - thead>tr
* @type {HTMLTableSectionElement}
* @private
*/
header: null,
/**
* 加载状态元素引用 - div.ui-grid-loading
* @type {HTMLDivElement}
* @private
*/
loading: null,
/**
* 大小计算元素引用 - span.ui-grid-sizer
* @type {HTMLSpanElement}
* @private
*/
sizer: null,
/**
* 包装元素引用 - div.ui-grid-wrapper
* @type {HTMLDivElement}
* @private
*/
wrapper: null,
/**
* 拖拽块引用 - div.dragger
* @type {HTMLDivElement}
* @private
*/
dragger: null,
/**
* 拖拽光标引用 - layer.dragger-cursor
* @type {HTMLElement}
* @private
*/
draggerCursor: null,
}
@ -955,9 +974,9 @@ export class Grid {
}
}
if (this.sortIndex >= 0) {
this.sortColumn();
this.sortColumn(true);
} else if (this.sortArray?.length > 0) {
this.sort();
this.sort(true);
} else {
this.reload();
}
@ -998,9 +1017,9 @@ export class Grid {
}
}
if (this.sortIndex >= 0) {
this.sortColumn();
this.sortColumn(true);
} else if (this.sortArray?.length > 0) {
this.sort();
this.sort(true);
} else {
this.reload();
}
@ -1109,12 +1128,15 @@ export class Grid {
this._var.scrollLeft = 0;
this._var.rowCount = -1;
if (this.sortIndex >= 0) {
this.sortColumn();
} else if (this.sortArray?.length > 0) {
this.sort();
}
this.resize();
this.resize(true, null, () => {
if (this.sortIndex >= 0) {
this.sortColumn(true);
} else if (this.sortArray?.length > 0) {
this.sort(true);
} else {
this.reload();
}
});
}
/**
@ -1145,6 +1167,13 @@ export class Grid {
return Array.prototype.slice.call(this._var.refs.header.querySelectorAll('&>th.column'));
}
/**
* 获取虚模式起始索引
* @readonly
* @type {number}
*/
get startIndex() { return this._var.startIndex }
/**
* 获取或设置当前选中的行索引的数组,设置后会刷新列表
* @type {number[]}
@ -1331,9 +1360,9 @@ export class Grid {
this._var.rendering = false;
if (this._var.source != null) {
if (this.sortIndex >= 0) {
this.sortColumn();
this.sortColumn(true);
} else if (this.sortArray?.length > 0) {
this.sort();
this.sort(true);
}
}
}
@ -1359,8 +1388,10 @@ export class Grid {
* 调整 Grid 元素的大小,一般需要在宽度变化时(如页面大小发生变化时)调用
* @param {boolean} [force] - 是否强制 [reload]{@linkcode Grid#reload},默认只有待渲染的行数发生变化时才会调用
* @param {boolean} [keep] - 是否保持当前滚动位置
* @param {Function} [callback] - 计算大小后的回调函数
* @param {Grid} callback.{this} - 上下文为 Grid
*/
resize(force, keep) {
resize(force, keep, callback) {
if (this._var.rendering || this._var.el == null) {
return;
}
@ -1376,7 +1407,11 @@ export class Grid {
const count = truncate((height - 1) / (this.rowHeight + 1)) + (RedumCount * 2) + 1;
if (force || count !== this._var.rowCount) {
this._var.rowCount = count;
this.reload(keep);
if (typeof callback === 'function') {
callback.call(this);
} else {
this.reload(keep);
}
}
this._var.bodyClientWidth = body.clientWidth;
}
@ -1408,13 +1443,14 @@ export class Grid {
if (this.extraRows > 0) {
length += this.extraRows;
}
this._var.containerHeight = (length + 1) * (this.rowHeight + 1);
this._var.containerHeight = length * (this.rowHeight + 1);
if (!keep) {
this._var.el.scrollTop = 0;
// this._var.el.scrollLeft = 0;
this._var.refs.table.style.top = '0px';
}
this._var.refs.wrapper.style.height = `${this._var.containerHeight}px`;
const headerHeight = this._var.headerHeight || this.rowHeight;
this._var.refs.wrapper.style.height = `${this._var.containerHeight + headerHeight}px`;
this._adjustRows(this._var.refs.body);
this.refresh();
}
@ -1442,6 +1478,8 @@ export class Grid {
this._changeColumnWidth(i, width);
}
});
} else {
this._var.headerHeight = this._var.refs.table.children[0].offsetHeight;
}
}
@ -1825,7 +1863,7 @@ export class Grid {
type ??= GridColumn;
this._var.colTypes[col.key] = type;
}
if (col.width > 0 || typeof type.createCaption === 'function') {
if (col.width > 0 || col.shrink || typeof type.createCaption === 'function') {
// col.autoResize = false;
} else {
this._set(col.key, 'autoResize', true);
@ -1847,13 +1885,18 @@ export class Grid {
if (col.sortable !== false) {
col.sortable = true;
}
const w = `${col.width}px`;
const style = {
'width': w,
'max-width': w,
'min-width': w,
'text-align': col.align
};
let style;
if (col.shrink) {
style = { 'text-align': col.align };
} else {
const w = `${col.width}px`;
style = {
'width': w,
'max-width': w,
'min-width': w,
'text-align': col.align
};
}
this._set(col.key, 'style', style);
// element
const th = createElement('th', 'column');
@ -2015,7 +2058,11 @@ export class Grid {
type ??= GridColumn;
this._var.colTypes[col.key] = type;
}
cell.appendChild(type.create(col));
const element = type.create(col, i, this);
if (typeof col.class === 'string') {
type.setClass(element, col.class);
}
cell.appendChild(element);
}
} else {
cell.style.display = 'none';
@ -2135,7 +2182,13 @@ export class Grid {
}
val ??= '';
// fill
if (typeof col.bgFilter === 'function') {
let bg = col.background;
if (bg != null) {
if (typeof bg === 'function') {
bg = col.background(item);
}
cell.style.backgroundColor = bg ?? '';
} else if (typeof col.bgFilter === 'function') {
const bgColor = col.bgFilter(item);
cell.style.backgroundColor = bgColor ?? '';
}
@ -2155,7 +2208,10 @@ export class Grid {
if (stateChanged) {
element = selected ?
type.createEdit(e => this._onRowChanged(e, i, col, type.getValue(e, col), cell), col, this._var.el, vals) :
type.create(col);
type.create(col, i, this);
if (typeof col.class === 'string') {
type.setClass(element, col.class);
}
cell.replaceChildren(element);
} else {
element = cell.children[0];
@ -2195,7 +2251,17 @@ export class Grid {
widths.flag = true;
}
}
if (typeof col.styleFilter === 'function') {
let style = col.style;
if (style != null) {
if (typeof style === 'function') {
style = col.style(item);
}
if (style != null) {
type.setStyle(element, style);
} else {
element.style.cssText = '';
}
} else if (typeof col.styleFilter === 'function') {
const style = col.styleFilter(item);
if (style != null) {
type.setStyle(element, style);
@ -2273,6 +2339,7 @@ export class Grid {
}
}
}
this._var.headerHeight = this._var.refs.table.children[0].offsetHeight;
}
_changingColumnOrder(index, offset, mouse, draggerCellLeft) {