change to jsdoc

This commit is contained in:
2024-01-30 17:28:18 +08:00
parent 0b897cae8a
commit a38af7577b
11 changed files with 1347 additions and 43 deletions

View File

@ -7,15 +7,71 @@ import { Dropdown } from "../dropdown";
import { convertCssStyle } from "../extension";
import { createDateInput, formatDate, setDateValue, getDateValue } from "../date";
/**
* 列定义基类
* @class
*/
export class GridColumn {
/**
* 创建显示单元格时调用的方法
* @param {GridColumnDefinition} col - 列定义对象
* @returns {HTMLElement} 返回创建的单元格元素
* @virtual
*/
static create() {
return createElement('span');
}
/**
* 创建编辑单元格时调用的方法
*
* 元素修改后设置行包装对象的 `__editing` 后,支持在离开编辑状态时及时触发 [leaveEdit]{@linkcode GridColumn.leaveEdit} 方法<br/>
* 更多例子参考代码中 {@linkcode GridDropdownColumn} 的实现。
* @param {Function} trigger - 编辑事件回调函数,`e` 参数会传递给 [getValue]{@linkcode GridColumn.getValue} 方法
* @param {GridColumnDefinition} col - 列定义对象
* @param {HTMLElement} container - 父容器元素
* @param {GridItemWrapper} vals - 行包装对象,其 `values` 属性为行数据对象
* @returns {HTMLElement} 返回创建的编辑状态的单元格元素
* @virtual
*/
static createEdit() { }
/**
* 创建列头时调用的方法
* @param {GridColumnDefinition} col - 列定义对象
* @returns {HTMLElement} 返回创建的列头元素
* @virtual
*/
static createCaption() { }
/**
* 设置单元格值时调用的方法
* @param {HTMLElement} element - 单元格元素
* @param {(string | boolean | number)} val - 待设置的单元格值
* @param {GridItemWrapper} vals - 行包装对象
* @param {GridColumnDefinition} col - 列定义对象
* @param {Grid} grid - Grid 对象
* @virtual
*/
static setValue(element, val) {
element.innerText = val;
}
/**
* 获取编辑状态单元格值时调用的方法
* @param {any} `e` 由 [createEdit]{@linkcode GridColumn.createEdit} 方法中 `trigger` 函数传递来的对象
* @param {GridColumnDefinition} col - 列定义对象
* @returns {(string | boolean | number)} 返回单元格的值
* @virtual
*/
static getValue() { }
/**
* 设置单元格样式时调用的方法
* @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]);
@ -23,6 +79,12 @@ export class GridColumn {
element.style.cssText = convertCssStyle(style);
}
/**
* 设置单元格可用性时调用的方法
* @param {HTMLElement} element - 单元格元素
* @param {boolean} enabled - 启用值,为 `false` 时代表禁用
* @virtual
*/
static setEnabled(element, enabled) {
const tooltip = element.querySelector('.ui-tooltip-wrapper');
if (tooltip != null) {
@ -30,10 +92,29 @@ export class GridColumn {
}
}
/**
* 单元格离开编辑元素时触发,需要由行包装对象的 `__editing` 来确定是否触发。
* @param {HTMLElement} element - 单元格元素
* @param {HTMLElement} container - 父容器元素
* @virtual
*/
static leaveEdit() { }
static toString() { return '[object Column]' }
}
/**
* 单行文本列
* @extends GridColumn
*/
export class GridInputColumn extends GridColumn {
/**
* 设置该类型是否支持触发 [onInputEnded]{@linkcode GridColumnDefinition.onInputEnded} 方法<br/>
* 该属性返回 `true` 后,在任意事件中修改行包装对象的 `__editing` 值,则会在行列元素变动时及时触发 [onInputEnded]{@linkcode GridColumnDefinition.onInputEnded} 方法,避免例如文本框还未触发 `onchange` 事件就被移除元素而导致的问题<br/>
* 更多例子参考代码中 {@linkcode GridInputColumn} 的实现
* @readonly
* @type {boolean}
*/
static get editing() { return true };
static createEdit(trigger, col, _wrapper, vals) {

View File

@ -2,11 +2,11 @@ import { GridColumnDefinition } from "./column"
/**
* 单元格点击回调函数
*
* @callback cellClickedCallback
* @param {number} index - 点击的行索引
* @param {number} colIndex - 点击的列索引
* @returns {boolean} 返回 `false` 则取消事件冒泡
*/
declare function cellClickedCallback(index: number, colIndex: number): boolean;
/** 列数据接口 */
interface GridItem {
@ -159,10 +159,9 @@ export class Grid {
willSelect?: (index: number, colIndex: number) => boolean;
/**
* 单元格单击时触发colIndex 为 -1 则表示点击的是行的空白处,返回 false 则取消事件冒泡
* @property {cellClickedCallback}
* @eventProperty
*/
cellClicked?: (index: number, colIndex: number) => boolean;
cellClicked?: typeof cellClickedCallback;
/**
* 选中行发生变化时触发的事件

View File

@ -35,7 +35,7 @@ function indexOfParent(target) {
return Array.prototype.indexOf.call(target.parentElement.children, target);
}
const ColumnTypes = {
const ColumnTypeDefs = {
0: GridColumn,
1: GridInputColumn,
2: GridDropdownColumn,
@ -47,6 +47,246 @@ const ColumnTypes = {
let r = lang;
/**
* 行数据接口
* @typedef {object} GridItem
* @property {any} Value - 值
* @property {string} DisplayValue - 显示值
*/
/**
* 行数据包装接口
* @typedef GridItemWrapper
* @property {object} values - 真实数据对象
* @property {(GridItem | any)} values.[key]] 数据属性
* @property {object} source - 下拉数据源缓存对象
* @property {GridSourceItem[]} source.[key]] 数据源
*/
/**
* 下拉框数据源接口
* @typedef {object} GridSourceItem
* @property {string} value - 值
* @property {string} text - 显示文本
*/
/**
* 行数据可用性回调函数
* @callback GridItemBooleanCallback
* @param {GridItem} item - 行数据对象
* @returns {boolean} 返回是否可用
* @this GridColumnDefinition
*/
/**
* 行数据过滤回调函数
* @callback GridItemFilterCallback
* @param {GridItem} item - 行数据对象
* @param {boolean} editing - 是否处于编辑状态
* @param {HTMLElement} [body] - Grid 控件的 `<tbody>` 部分
* @this GridColumnDefinition
*/
/**
* 行数据处理回调函数
* @callback GridItemObjectCallback
* @param {GridItem} item - 行数据对象
* @returns {object} 返回任意对象
* @this GridColumnDefinition
*/
/**
* 行数据字符串回调函数
* @callback GridItemStringCallback
* @param {GridItem} item - 行数据对象
* @returns {string} 返回字符串
* @this GridColumnDefinition
*/
/**
* 列过滤器数据源回调函数
* @callback GridColumnFilterSourceCallback
* @param {GridColumnDefinition} col - 列定义对象
* @returns {GridItem[]} 返回过滤器的数据数组
* @this Grid
*/
/**
* 行数据排序回调函数
* @callback GridItemSortCallback
* @param {GridItem} a - 对比行数据1
* @param {GridItem} b - 对比行数据2
* @returns {number} 返回大小对比结果
*/
/**
* 下拉列表数据源回调函数
* @callback GridDropdownSourceCallback
* @param {GridItem} item - 行数据对象
* @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 {object} GridColumnDefinition
* @property {string} key - 列关键字,默认以该关键字从行数据中提取单元格值,行数据的关键字属性值里包含 DisplayValue 则优先显示此值
* @property {(GridColumnTypeEnum | GridColumn)} [type=Grid.ColumnTypes.Common] - 列的类型,可以为 {@linkcode GridColumn} 的子类,或者内置类型 {@linkcode GridColumnTypeEnum}
* @property {string} [caption] - 列标题文本
* @property {object} [captionStyle] - 列标题的元素样式
* @property {number} [width] - 大于 0 则设置为该宽度,否则根据列内容自动调整列宽
* @property {("left" |"center" | "right")} [align=left] 列对齐方式
* @property {(boolean | string | GridItemBooleanCallback)} [enabled] - 列是否可用(可编辑),允许以下类型
*
* * `boolean` 则直接使用该值
* * `string` 则以该值为关键字从行数据中取值作为判断条件
* * `(item: GridItem) => boolean` 则调用该函数(上下文为列定义对象),以返回值作为判断条件
* @property {GridItemFilterCallback} [filter] - 单元格取值采用该函数返回的值
* @property {string} [text] - 单元格以该值填充内容忽略filter与关键字属性
* @property {boolean} [visible=true] - 列是否可见
* @property {boolean} [resizable=true] - 列是否允许调整宽度
* @property {boolean} [sortable=true] - 列是否允许排序
* @property {boolean} [orderable=true] - 列是否允许重排顺序
* @property {boolean} [allcheck=false] - 列为复选框类型时是否在列头增加全选复选框
* @property {object} [css] - 单元格css样式对象仅在重建行元素时读取
* @property {GridItemObjectCallback} [styleFilter] - 根据返回值填充单元格样式(填充行列数据时读取)
* @property {GridItemStringCallback} [bgFilter] - 根据返回值设置单元格背景色
* @property {object} [events] - 给单元格元素附加事件(事件函数上下文为数据行对象)
* @property {Function} events.[event]] - 事件回调函数
* @property {(object | GridItemObjectCallback)} [attrs] - 根据返回值设置单元格元素的附加属性,允许直接设置对象也支持函数返回对象
* @property {boolean} [allowFilter=false] - 是否允许进行列头过滤
* @property {(GridItem[] | GridColumnFilterSourceCallback)} [filterSource] - 自定义列过滤器的数据源函数上下文为Grid
* @property {GridItemSortCallback} [sortFilter] - 自定义列排序函数
* @property {DropdownOptions} [dropOptions] - 列为下拉列表类型时以该值设置下拉框的参数
* @property {(GridSourceItem[] | GridDropdownSourceCallback | Promise<GridSourceItem[]>)} [source] - 列为下拉列表类型时以该值设置下拉列表数据源,支持函数返回,也支持返回异步对象
* @property {boolean} [sourceCache=false] - 下拉列表数据源是否缓存结果即行数据未发生变化时仅从source属性获取一次值
* @property {("fa-light" | "fa-regular" | "fa-solid")} [iconType=fa-light] - 列为图标类型时以该值设置图标样式(函数上下文为列定义对象)
* @property {(string | GridItemStringCallback)} [iconClassName] - 列为图标类型时以该值作为单元格元素的额外样式类型(函数上下文为列定义对象)
* @property {string} [dateMin] - 列为日期类型时以该值作为最小可选日期值
* @property {string} [dateMax] - 列为日期类型时以该值作为最大可选日期值
* @property {DateFormatterCallback} [dateValueFormatter] - 列为日期类型时自定义日期格式化函数
* @property {(string | GridItemStringCallback)} [tooltip] - 以返回值额外设置单元格的tooltip函数上下文为列定义对象
* @property {GridColumnCheckedCallback} [onAllChecked] - 列头复选框改变时触发
* @property {GridColumnDefinition} onAllChecked.col - 列定义对象
* @property {boolean} onAllChecked.flag - 是否选中
* @property {GridCellChangedCallback} [onChanged] - 单元格发生变化时触发
* @property {GridCellInputEndedCallback} [onInputEnded] - 文本单元格在输入完成时触发的事件
* @property {GridColumnFilterOkCallback} [onFilterOk] - 列过滤点击 `OK` 时触发的事件
* @property {GridColumnFilteredCallback} [onFiltered] - 列过滤后触发的事件
* @property {GridColumnDropExpandedCallback} [onDropExpanded] - 列为下拉框类型时在下拉列表展开时触发的事件
*/
/**
* 判断复选框列的回调函数
* @callback ColumnTypesEnumIsCheckbox
* @param {number} type - 列类型
* @returns {boolean} 返回是否为复选框列
*/
/**
* 列类型枚举
* @enum {number}
*/
const GridColumnTypeEnum = {
/** 0 - 通用列(只读) */
Common: 0,
/** 1 - 单行文本列 */
Input: 1,
/** 2 - 下拉选择列 */
Dropdown: 2,
/** 3 - 复选框列 */
Checkbox: 3,
/** 4 - 图标列 */
Icon: 4,
/** 5 - 多行文本列 */
Text: 5,
/** 6 - 日期选择列 */
Date: 6,
/**
* 判断列是否为复选框列
* @type {ColumnTypesEnumIsCheckbox}
*/
isCheckbox(type) { return type === 3 }
};
/**
* 列排序枚举
* @enum {number}
*/
const GridColumnDirection = {
/** -1 - 倒序 */
Descending: -1,
/** 1 - 升序 */
Ascending: 1
};
/**
* 列排序定义接口
* @typedef GridColumnSortDefinition
* @property {string} column - 排序列的关键字
* @property {("asc" | "desc")} order - 升序或降序
*/
/**
* 多语言文本资源回调函数
* @callback GridLanguageCallback
* @param {string} id - 资源 ID
* @param {string} [def] - 默认资源
* @returns 返回获取的多语言资源
*/
/**
* Grid 控件基础类
* @class
*/
export class Grid {
_var = {
selectedColumnIndex: -1,
@ -74,44 +314,189 @@ export class Grid {
// _var.colAttrs = {};
// _var.vtable = [];
/**
* 列定义的数组
* @type {GridColumnDefinition[]}
*/
columns = [];
/**
* 多语言资源对象
* @type {object}
* @property {string} [all=( All )]
* @property {string} [ok=OK]
* @property {string} [reset=Reset]
* @property {string} [cancel=Cancel]
* @property {string} [null=( Null )]
* @property {string} [addLevel=Add Level]
* @property {string} [deleteLevel=Delete Level]
* @property {string} [copyLevel=Copy Level]
* @property {string} [asc=Ascending]
* @property {string} [desc=Descending]
* @property {string} [column=Column]
* @property {string} [order=Order]
* @property {string} [sort=Sort]
* @property {string} [requirePrompt=All sort criteria must have a column specified. Check the selected sort criteria and try again.]
* @property {string} [duplicatePrompt={column} is being sorted more than once. Delete the duplicate sort criteria and try again.]
*/
langs = {};
/**
* 行数大于等于该值则启用虚模式
* @type {number}
* @default 100
*/
virtualCount = 100;
/**
* 表格行高
* @type {number}
* @default 36
*/
rowHeight = 36;
/**
* 文本行高
* @type {number}
* @default 24
*/
lineHeight = 24;
/**
* 列表底部留出额外的空白行
* @type {number}
* @default 0
*/
extraRows = 0;
/**
* 过滤条件列表的行高
* @type {number}
* @default 30
*/
filterRowHeight = 30;
/**
* 列表高度值,为 0 时列表始终显示全部内容(自增高),为非数字或者小于 0 则根据容器高度来确定虚模式的渲染行数
* @type {number | null}
*/
height;
/**
* 列表是否为只读
* @type {boolean}
*/
readonly;
/**
* 是否允许多选
* @type {boolean}
* @default false
*/
multiSelect = false;
/**
* 为 `false` 时只有点击在单元格内才会选中行
* @type {boolean}
* @default true
*/
fullrowClick = true;
/**
* 单元格 tooltip 是否禁用
* @type {boolean}
* @default false
*/
tooltipDisabled = false;
/**
* 列头是否显示
* @type {boolean}
* @default true
*/
headerVisible = true;
/**
* 监听事件的窗口载体
* @type {(Window | HTMLElement)}
* @default window
*/
window = global;
/**
* 排序列的索引
* @type {number}
* @default -1
*/
sortIndex = -1;
sortDirection = 1;
/**
* 排序方式,正数升序,负数倒序
* @type {GridColumnDirection}
* @default GridColumnDirection.Ascending
*/
sortDirection = GridColumnDirection.Ascending;
/**
* 排序列数组
* @type {GridColumnSortDefinition[]}
* @default null
*/
sortArray = null;
/**
* 即将选中行时触发
* @event
* @param {number} index - 即将选中的行索引
* @param {number} colIndex - 即将选中的列索引
* @returns {boolean} 返回 `false`、`null`、`undefined`、`0` 等则取消选中动作
*/
willSelect;
/**
* 单元格单击时触发colIndex 为 -1 则表示点击的是行的空白处
* @event
* @param {number} index - 点击的行索引
* @param {number} colIndex - 点击的列索引
* @returns {boolean} 返回 false 则取消事件冒泡
*/
cellClicked;
/**
* 选中行发生变化时触发的事件
* @event
* @param {number} index - 选中的行索引
*/
onSelectedRowChanged;
/**
* 单元格双击时触发的事件colIndex 为 -1 则表示点击的是行的空白处
* @event
* @param {number} index - 双击的行索引
* @param {number} colIndex - 双击的列索引
*/
onCellDblClicked;
/**
* 行双击时触发的事件
* @event
* @param {number} index - 双击的行索引
*/
onRowDblClicked;
/**
* 列发生变化时触发的事件
* @event
* @param {("reorder" | "resize" | "sort")} type - 事件类型
*
* * "reorder" 为发生列重排事件,此时 value 为目标列索引
* * "resize" 为发生列宽调整事件,此时 value 为列宽度值
* * "sort" 为发生列排序事件,此时 value 为 1升序或 -1倒序
* @param {number} colIndex - 发生变化事件的列索引
* @param {number | GridColumnDirection} value - 变化的值
*/
onColumnChanged;
/**
* 列滚动时触发的事件
* @event
* @param {Event} e - 滚动事件对象
*/
onBodyScrolled;
static ColumnTypes = {
Common: 0,
Input: 1,
Dropdown: 2,
Checkbox: 3,
Icon: 4,
Text: 5,
Date: 6,
isCheckbox(type) { return type === 3 }
};
/**
* 列类型枚举
* @readonly
* @type {GridColumnTypeEnum}
*/
static get ColumnTypes() { return GridColumnTypeEnum }
/**
*
* @param {(string | HTMLElement)} container Grid 控件所在的父容器,可以是 string 表示选择器,也可以是 HTMLElement 对象
* Grid 控件构造函数
* _构造时可以不进行赋值但是调用 init 函数时则必须进行赋值_
* @param {GridLanguageCallback} [getText] 获取多语言文本的函数代理
*/
constructor(container, getText) {
this._var.parent = typeof container === 'string' ? document.querySelector(container) : container;
if (typeof getText === 'function') {
@ -123,21 +508,31 @@ export class Grid {
reset: r('reset', 'Reset'),
cancel: r('cancel', 'Cancel'),
null: r('null', '( Null )'),
addLevel: r('', 'Add level'),
deleteLevel: r('', 'Delete level'),
copyLevel: r('', 'Copy level'),
asc: r('', 'Ascending'),
desc: r('', 'Descending'),
column: r('', 'Column'),
order: r('', 'Order'),
sort: r('', 'Sort'),
requirePrompt: r('', 'Column required.'),
duplicatePrompt: r('', 'Column duplicated: "{column}"')
addLevel: r('addLevel', 'Add level'),
deleteLevel: r('deleteLevel', 'Delete level'),
copyLevel: r('copyLevel', 'Copy level'),
asc: r('asc', 'Ascending'),
desc: r('desc', 'Descending'),
column: r('column', 'Column'),
order: r('order', 'Order'),
sort: r('sort', 'Sort'),
requirePrompt: r('requirePrompt', 'All sort criteria must have a column specified. Check the selected sort criteria and try again.'),
duplicatePrompt: r('duplicatePrompt', '{column} is being sorted more than once. Delete the duplicate sort criteria and try again.')
};
}
/**
* 获取 Grid 的页面元素
* @readonly
* @type {HTMLDivElement}
*/
get element() { return this._var.el }
/**
* 获取当前 Grid 是否已发生改变
* @readonly
* @type {boolean}
*/
get changed() {
const source = this._var.source;
if (source == null) {
@ -146,8 +541,17 @@ export class Grid {
return source.find(r => r.__changed) != null;
}
/**
* 返回所有数据的数据(未过滤)
* @readonly
* @type {GridItem[]}
*/
get allSource() { return this._var.source?.map(s => s.values) }
/**
* 获取已过滤的数据数组,或者设置数据并刷新列表
* @type {GridItem[]}
*/
get source() { return this._var.currentSource?.map(s => s.values) }
set source(list) {
if (this._var.el == null) {
@ -166,6 +570,11 @@ export class Grid {
this._refreshSource(list);
}
/**
* 设置单行数据
* @param {number} index - 行索引
* @param {GridItem} item - 待设置的行数据对象
*/
setItem(index, item) {
if (this._var.currentSource == null) {
throw new Error('no source');
@ -174,9 +583,21 @@ export class Grid {
// clear dropdown source cache
delete it.source;
it.values = item;
this.refresh();
if (this.sortIndex >= 0) {
this.sortColumn();
} else if (this.sortArray?.length > 0) {
this.sort();
} else {
this.refresh();
}
}
/**
* 添加行数据
* @param {GridItem} item - 待添加的行数据值
* @param {number} [index] - 待添加的行索引
* @returns {GridItem} 返回已添加的行数据
*/
addItem(item, index) {
if (this._var.currentSource == null) {
throw new Error('no source');
@ -199,10 +620,22 @@ export class Grid {
this._var.source.push(newIt);
}
}
this.reload();
if (this.sortIndex >= 0) {
this.sortColumn();
} else if (this.sortArray?.length > 0) {
this.sort();
} else {
this.reload();
}
return item;
}
/**
* 批量添加行数据
* @param {GridItem[]} array - 待添加的行数据数组
* @param {number} [index] - 待添加的行索引
* @returns {GridItem[]} 返回已添加的行数据数组
*/
addItems(array, index) {
if (this._var.currentSource == null) {
throw new Error('no source');
@ -230,10 +663,21 @@ export class Grid {
this._var.source.push(...items);
}
}
this.reload();
if (this.sortIndex >= 0) {
this.sortColumn();
} else if (this.sortArray?.length > 0) {
this.sort();
} else {
this.reload();
}
return array;
}
/**
* 删除行数据
* @param {number} index - 待删除的行索引
* @returns {GridItem} 返回已删除的行数据
*/
removeItem(index) {
if (this._var.currentSource == null) {
throw new Error('no source');
@ -257,6 +701,11 @@ export class Grid {
return it.values;
}
/**
* 批量删除行数据
* @param {number[]} [indexes] - 待删除的行索引数组,未传值时删除所有行
* @returns {GridItem[]} 返回已删除的行数据数组
*/
removeItems(indexes) {
if (this._var.currentSource == null) {
throw new Error('no source');
@ -334,8 +783,18 @@ export class Grid {
this.resize();
}
/**
* 获取当前是否为虚模式状态
* @readonly
* @type {boolean}
*/
get virtual() { return this._var.currentSource?.length > this.virtualCount }
/**
* 获取当前排序的列关键字,为 null 则当前无排序列
* @readonly
* @type {string | null}
*/
get sortKey() {
if (this.columns == null) {
return null;
@ -348,6 +807,10 @@ export class Grid {
return Array.prototype.slice.call(this._var.refs.body.children);
}
/**
* 获取或设置当前选中的行索引的数组,设置后会刷新列表
* @type {number[]}
*/
get selectedIndexes() { return this._var.selectedIndexes }
set selectedIndexes(indexes) {
const startIndex = this._var.startIndex;
@ -368,8 +831,17 @@ export class Grid {
}
}
/**
* 获取当前选中行的索引,为 -1 则当前没有选中行
* @readonly
* @type {number}
*/
get selectedIndex() { return (this._var.selectedIndexes && this._var.selectedIndexes[0]) ?? -1 }
/**
* 获取或设置 Grid 当前的加载状态
* @type {boolean}
*/
get loading() { return this._var.refs.loading?.style?.visibility === 'visible' }
set loading(flag) {
if (this._var.refs.loading == null) {
@ -384,6 +856,10 @@ export class Grid {
}
}
/**
* 获取或设置 Grid 当前滚动的偏移量
* @type {number}
*/
get scrollTop() { return this._var.el?.scrollTop; }
set scrollTop(top) {
if (this._var.el == null) {
@ -393,6 +869,10 @@ export class Grid {
this.reload(true);
}
/**
* 初始化Grid控件
* @param {HTMLElement} [container=.ctor#container] - 父容器元素,若未传值则采用构造方法中传入的父容器元素
*/
init(container = this._var.parent) {
this._var.el = null;
this._var.refs = {};
@ -488,15 +968,28 @@ export class Grid {
}
}
/**
* 设置数据列表,该方法为 [source]{@linkcode Grid#source} 属性的语法糖
* @param {GridItem[]} source - 待设置的数据列表
*/
setData(source) {
this.source = source;
}
/**
* 滚动到指定行的位置
* @param {number} index - 待滚动至的行索引
*/
scrollToIndex(index) {
const top = this._scrollToTop(index * (this.rowHeight + 1), true);
this._var.el.scrollTop = top;
}
/**
* 调整 Grid 元素的大小,一般需要在宽度变化时(如页面大小发生变化时)调用
* @param {boolean} [force] - 是否强制 [reload]{@linkcode Grid#reload},默认只有待渲染的行数发生变化时才会调用
* @param {boolean} [keep] - 是否保持当前滚动位置
*/
resize(force, keep) {
if (this._var.rendering || this._var.el == null) {
return;
@ -518,6 +1011,10 @@ export class Grid {
this._var.bodyClientWidth = body.clientWidth;
}
/**
* 重新计算需要渲染的行,并载入元素,一般需要在高度变化时调用
* @param {boolean} [keep] - 是否保持当前滚动位置
*/
reload(keep) {
const filtered = this.columns.some(c => c.filterValues != null);
if ((filtered ^ this._var.colAttrs.__filtered) === 1) {
@ -552,6 +1049,9 @@ export class Grid {
this.refresh();
}
/**
* 重新填充Grid单元格数据
*/
refresh() {
if (this._var.refs.body == null) {
throw new Error('body has not been created.');
@ -575,6 +1075,9 @@ export class Grid {
}
}
/**
* 把所有行重置为未修改的状态
*/
resetChange() {
if (this._var.source == null) {
return;
@ -608,6 +1111,10 @@ export class Grid {
return (a, b) => col.sortFilter(a.values, b.values) * direction;
}
/**
* 根据当前排序字段进行列排序
* @param {boolean} [reload] - 为 `true` 则在列排序后调用 [reload]{@linkcode Grid#reload} 方法
*/
sortColumn(reload) {
const index = this.sortIndex;
const col = this.columns[index];
@ -642,6 +1149,10 @@ export class Grid {
}
}
/**
* 根据当前排序列数组进行多列排序
* @param {boolean} [reload] - 为 `true` 则在多列排序后调用 [reload]{@linkcode Grid#reload} 方法
*/
sort(reload) {
const sortArray = this.sortArray;
if (sortArray == null || sortArray.length === 0) {
@ -689,11 +1200,17 @@ export class Grid {
});
}
/**
* 清除列头复选框的选中状态
*/
clearHeaderCheckbox() {
const boxes = this._var.refs.header.querySelectorAll('.ui-check-wrapper>input');
boxes.forEach(box => box.checked = false);
}
/**
* 显示多列排序设置面板
*/
showSortPanel() {
const content = createElement('div', 'ui-sort-panel-content');
const buttonWrapper = createElement('div', 'ui-sort-panel-buttons');
@ -811,7 +1328,7 @@ export class Grid {
key: 'column',
caption: this.langs.column,
width: 270,
type: Grid.ColumnTypes.Dropdown,
type: GridColumnTypeEnum.Dropdown,
dropOptions: {
textKey: 'caption',
valueKey: 'key'
@ -824,7 +1341,7 @@ export class Grid {
key: 'order',
caption: this.langs.order,
width: 150,
type: Grid.ColumnTypes.Dropdown,
type: GridColumnTypeEnum.Dropdown,
source: [
{ value: 'asc', text: this.langs.asc },
{ value: 'desc', text: this.langs.desc }
@ -915,13 +1432,13 @@ export class Grid {
continue;
}
// style
const isCheckbox = Grid.ColumnTypes.isCheckbox(col.type);
const isCheckbox = GridColumnTypeEnum.isCheckbox(col.type);
let type = this._var.colTypes[col.key];
if (type == null) {
if (isNaN(col.type)) {
type = col.type;
} else {
type = ColumnTypes[col.type];
type = ColumnTypeDefs[col.type];
}
type ??= GridColumn;
this._var.colTypes[col.key] = type;
@ -1097,7 +1614,7 @@ export class Grid {
if (style !== '') {
cell.style.cssText = style;
}
if (Grid.ColumnTypes.isCheckbox(col.type)) {
if (GridColumnTypeEnum.isCheckbox(col.type)) {
cell.appendChild(GridCheckboxColumn.createEdit(e => this._onRowChanged(e, exists + i, col, e.target.checked, cell)));
// this._var.colTypes[col.key] = GridCheckboxColumn;
} else {
@ -1106,7 +1623,7 @@ export class Grid {
if (isNaN(col.type)) {
type = col.type;
} else {
type = ColumnTypes[col.type];
type = ColumnTypeDefs[col.type];
}
type ??= GridColumn;
this._var.colTypes[col.key] = type;
@ -1184,7 +1701,7 @@ export class Grid {
const bgColor = col.bgFilter(item);
cell.style.backgroundColor = bgColor ?? '';
}
const isCheckbox = Grid.ColumnTypes.isCheckbox(col.type);
const isCheckbox = GridColumnTypeEnum.isCheckbox(col.type);
const type = isCheckbox ? GridCheckboxColumn : this._var.colTypes[col.key] ?? GridColumn;
let element;
if (!isCheckbox && typeof type.createEdit === 'function') {