mirror of
https://github.com/VisActor/VTable
synced 2024-11-21 09:30:54 +00:00
Merge pull request #2766 from VisActor/2026-multiple-rowSelected-highlight
Some checks are pending
Unit test CI / build (18.x) (push) Waiting to run
Some checks are pending
Unit test CI / build (18.x) (push) Waiting to run
[WIP] 2026 multiple row selected highlight
This commit is contained in:
commit
e6acbdce1e
3
.vscode/settings.json
vendored
3
.vscode/settings.json
vendored
@ -32,5 +32,6 @@
|
||||
"[python]": {
|
||||
"editor.defaultFormatter": "ms-python.black-formatter"
|
||||
},
|
||||
"python.formatting.provider": "none"
|
||||
"python.formatting.provider": "none",
|
||||
"nuxt.isNuxtApp": false
|
||||
}
|
||||
|
@ -20,4 +20,4 @@
|
||||
#
|
||||
|
||||
registry=https://registry.npmjs.org/
|
||||
always-auth=false
|
||||
always-auth=false
|
||||
|
@ -245,6 +245,10 @@ Whether to cancel the selection when clicking outside the table.
|
||||
|
||||
Whether to disable dragging selection.
|
||||
|
||||
##${prefix} highlightInRange(boolean) = false
|
||||
|
||||
Will the entire row or column be highlighted when select in multiple rows or columns?
|
||||
|
||||
#${prefix} theme(Object)
|
||||
|
||||
{{ use: common-theme(
|
||||
|
@ -240,6 +240,10 @@ hover 交互响应模式:十字交叉、整列、整行或者单个单元格
|
||||
|
||||
拖拽选择单元格时是否禁用框选。
|
||||
|
||||
##${prefix} highlightInRange(boolean) = false
|
||||
|
||||
是否在多行或者多列时展示整行或整列高亮效果。
|
||||
|
||||
#${prefix} theme(Object)
|
||||
|
||||
{{ use: common-theme(
|
||||
|
267
packages/vtable/__tests__/listTable-highlightInRange.test.ts
Normal file
267
packages/vtable/__tests__/listTable-highlightInRange.test.ts
Normal file
@ -0,0 +1,267 @@
|
||||
// @ts-nocheck
|
||||
// 有问题可对照demo unitTestListTable
|
||||
import records from './data/marketsales.json';
|
||||
import { ListTable } from '../src';
|
||||
import { createDiv } from './dom';
|
||||
global.__VERSION__ = 'none';
|
||||
describe('listTable init test', () => {
|
||||
const containerDom: HTMLElement = createDiv();
|
||||
containerDom.style.position = 'relative';
|
||||
containerDom.style.width = '1000px';
|
||||
containerDom.style.height = '800px';
|
||||
const columns = [
|
||||
{
|
||||
field: '订单 ID',
|
||||
caption: '订单 ID',
|
||||
sort: true,
|
||||
width: 'auto',
|
||||
description: '这是订单的描述信息',
|
||||
style: {
|
||||
fontFamily: 'Arial',
|
||||
fontSize: 14
|
||||
}
|
||||
},
|
||||
{
|
||||
field: '订单日期',
|
||||
caption: '订单日期'
|
||||
},
|
||||
{
|
||||
field: '发货日期',
|
||||
caption: '发货日期'
|
||||
},
|
||||
{
|
||||
field: '客户名称',
|
||||
caption: '客户名称',
|
||||
style: {
|
||||
padding: [10, 0, 10, 60]
|
||||
}
|
||||
},
|
||||
{
|
||||
field: '邮寄方式',
|
||||
caption: '邮寄方式'
|
||||
},
|
||||
{
|
||||
field: '省/自治区',
|
||||
caption: '省/自治区'
|
||||
},
|
||||
{
|
||||
field: '产品名称',
|
||||
caption: '产品名称'
|
||||
},
|
||||
{
|
||||
field: '类别',
|
||||
caption: '类别'
|
||||
},
|
||||
{
|
||||
field: '子类别',
|
||||
caption: '子类别'
|
||||
},
|
||||
{
|
||||
field: '销售额',
|
||||
caption: '销售额'
|
||||
},
|
||||
{
|
||||
field: '数量',
|
||||
caption: '数量'
|
||||
},
|
||||
{
|
||||
field: '折扣',
|
||||
caption: '折扣'
|
||||
},
|
||||
{
|
||||
field: '利润',
|
||||
caption: '利润'
|
||||
}
|
||||
];
|
||||
const option = {
|
||||
columns,
|
||||
defaultColWidth: 150,
|
||||
allowFrozenColCount: 5,
|
||||
select: {
|
||||
highlightInRange: true
|
||||
}
|
||||
};
|
||||
|
||||
option.container = containerDom;
|
||||
option.records = records;
|
||||
const listTable = new ListTable(option);
|
||||
test('listTable getCellValue', () => {
|
||||
expect(listTable.getCellValue(6, 3)).toBe('Cardinal 孔加固材料, 回收');
|
||||
});
|
||||
test('listTable getCellOverflowText', () => {
|
||||
expect(listTable.getCellOverflowText(6, 3)).toBe('Cardinal 孔加固材料, 回收');
|
||||
});
|
||||
test('listTable getHeaderDescription', () => {
|
||||
expect(listTable.getHeaderDescription(0, 0)).toBe('这是订单的描述信息');
|
||||
});
|
||||
test('listTable setScrollTop getScrollTop', () => {
|
||||
listTable.setScrollTop(100);
|
||||
expect(listTable.getScrollTop()).toBe(100);
|
||||
});
|
||||
test('listTable setScrollLeft getScrollLeft', () => {
|
||||
listTable.setScrollLeft(100);
|
||||
expect(listTable.getScrollLeft()).toBe(100);
|
||||
});
|
||||
test('listTable scrollToCell', () => {
|
||||
listTable.scrollToCell({ col: 4, row: 28 });
|
||||
expect(listTable.getScrollLeft()).toBe(601);
|
||||
expect(listTable.getScrollTop()).toBe(802);
|
||||
});
|
||||
test('listTable updateTheme', () => {
|
||||
listTable.heightMode = 'autoHeight';
|
||||
listTable.updateTheme({
|
||||
bodyStyle: {
|
||||
fontFamily: 'Calibri',
|
||||
fontSize: 28,
|
||||
color: 'red'
|
||||
}
|
||||
});
|
||||
listTable.scrollToCell({ col: 6, row: 16 });
|
||||
|
||||
expect(listTable.getScrollLeft()).toBe(901);
|
||||
expect(listTable.getScrollTop()).toBe(720);
|
||||
expect(listTable.getCellStyle(6, 16)).toStrictEqual({
|
||||
strokeColor: undefined,
|
||||
textAlign: 'left',
|
||||
textBaseline: 'middle',
|
||||
bgColor: '#FFF',
|
||||
color: 'red',
|
||||
fontFamily: 'Calibri',
|
||||
fontSize: 28,
|
||||
fontStyle: undefined,
|
||||
fontVariant: undefined,
|
||||
fontWeight: undefined,
|
||||
lineHeight: 28,
|
||||
autoWrapText: false,
|
||||
lineClamp: 'auto',
|
||||
textOverflow: 'ellipsis',
|
||||
borderColor: '#000',
|
||||
borderLineWidth: 1,
|
||||
borderLineDash: [],
|
||||
underline: false,
|
||||
underlineDash: undefined,
|
||||
underlineOffset: undefined,
|
||||
underlineWidth: undefined,
|
||||
lineThrough: false,
|
||||
lineThroughLineWidth: undefined,
|
||||
padding: [10, 16, 10, 16],
|
||||
_linkColor: '#3772ff',
|
||||
_strokeArrayColor: undefined,
|
||||
_strokeArrayWidth: undefined
|
||||
});
|
||||
});
|
||||
test('listTable updateOption records&autoWidth&widthMode', () => {
|
||||
columns.shift();
|
||||
const recordDeleted = records.slice(10, 30);
|
||||
const option1 = {
|
||||
columns,
|
||||
records: recordDeleted,
|
||||
defaultColWidth: 150,
|
||||
allowFrozenColCount: 5,
|
||||
heightMode: 'autoHeight',
|
||||
autoWrapText: true,
|
||||
widthMode: 'autoWidth',
|
||||
limitMaxAutoWidth: 170,
|
||||
dragHeaderMode: 'all'
|
||||
};
|
||||
listTable.updateOption(option1);
|
||||
expect(listTable.rowCount).toBe(21);
|
||||
expect(listTable.colCount).toBe(12);
|
||||
expect(listTable.getScrollTop()).toBe(0);
|
||||
expect(listTable.getColWidth(0)).toBe(122);
|
||||
expect(listTable.getColWidth(5)).toBe(170);
|
||||
});
|
||||
test('listTable selectCell', () => {
|
||||
listTable.selectCell(4, 5);
|
||||
expect(listTable.stateManager?.select.ranges).toEqual([
|
||||
{
|
||||
start: {
|
||||
col: 4,
|
||||
row: 5
|
||||
},
|
||||
end: {
|
||||
col: 4,
|
||||
row: 5
|
||||
}
|
||||
}
|
||||
]);
|
||||
const scrollTop = listTable.scrollTop;
|
||||
listTable.selectCells([
|
||||
{ start: { col: 1, row: 3 }, end: { col: 4, row: 6 } },
|
||||
{ start: { col: 0, row: 4 }, end: { col: 7, row: 4 } },
|
||||
{ start: { col: 4, row: 36 }, end: { col: 7, row: 36 } }
|
||||
]);
|
||||
|
||||
expect(listTable.stateManager?.select.ranges).toEqual([
|
||||
{ start: { col: 1, row: 3 }, end: { col: 4, row: 6 }, skipBodyMerge: true },
|
||||
{ start: { col: 0, row: 4 }, end: { col: 7, row: 4 }, skipBodyMerge: true },
|
||||
{ start: { col: 4, row: 36 }, end: { col: 7, row: 36 }, skipBodyMerge: true }
|
||||
]);
|
||||
expect(listTable.getScrollTop()).toBe(scrollTop);
|
||||
});
|
||||
test('listTable measureTextWidth', () => {
|
||||
const measureTextWdith = listTable.measureText("家里方大化工撒个福建师大看哈 fdsfgj! *-+&5%#.,'.,。、", {
|
||||
fontFamily: 'Arial',
|
||||
fontSize: 15,
|
||||
fontWeight: 'bold'
|
||||
});
|
||||
expect(measureTextWdith).toEqual({
|
||||
width: 390.0501427283655,
|
||||
height: 15
|
||||
});
|
||||
});
|
||||
// test('listTable API getAllCells', () => {
|
||||
// expect(JSON.parse(JSON.stringify(listTable.getCellInfo(5, 5)))).toEqual({
|
||||
// col: 5,
|
||||
// row: 5,
|
||||
// field: '省/自治区',
|
||||
// cellHeaderPaths: {
|
||||
// colHeaderPaths: [
|
||||
// {
|
||||
// field: '省/自治区'
|
||||
// }
|
||||
// ],
|
||||
// rowHeaderPaths: []
|
||||
// },
|
||||
// caption: '省/自治区',
|
||||
// cellType: 'text',
|
||||
// originData: {
|
||||
// '行 ID': '5',
|
||||
// '订单 ID': 'CN-2018-2975416',
|
||||
// 订单日期: '2018/5/31',
|
||||
// 发货日期: '2018/6/2',
|
||||
// 邮寄方式: '二级',
|
||||
// '客户 ID': '万兰-15730',
|
||||
// 客户名称: '万兰',
|
||||
// 细分: '消费者',
|
||||
// 城市: '汕头',
|
||||
// '省/自治区': '广东',
|
||||
// '国家/地区': '中国',
|
||||
// 地区: '中南',
|
||||
// '产品 ID': '办公用-器具-10003452',
|
||||
// 类别: '办公用品',
|
||||
// 子类别: '器具',
|
||||
// 产品名称: 'KitchenAid 搅拌机, 黑色',
|
||||
// 销售额: '1375.92',
|
||||
// 数量: '3',
|
||||
// 折扣: '0',
|
||||
// 利润: '550.2'
|
||||
// },
|
||||
// cellRange: {
|
||||
// bounds: {
|
||||
// x1: 762,
|
||||
// y1: 200,
|
||||
// x2: 912,
|
||||
// y2: 240
|
||||
// }
|
||||
// },
|
||||
// value: '广东',
|
||||
// dataValue: '广东',
|
||||
// cellType: 'body',
|
||||
// scaleRatio: 1
|
||||
// });
|
||||
// });
|
||||
// setTimeout(() => {
|
||||
// listTable.release();
|
||||
// }, 1000);
|
||||
});
|
274
packages/vtable/examples/list/list-highlightInRange.ts
Normal file
274
packages/vtable/examples/list/list-highlightInRange.ts
Normal file
@ -0,0 +1,274 @@
|
||||
import * as VTable from '../../src';
|
||||
import { bindDebugTool } from '../../src/scenegraph/debug-tool';
|
||||
const CONTAINER_ID = 'vTable';
|
||||
const generatePersons = count => {
|
||||
return Array.from(new Array(count)).map((_, i) => ({
|
||||
id: i + 1,
|
||||
email1: `${i + 1}@xxx.com`,
|
||||
name: `小明${i + 1}`,
|
||||
lastName: '王',
|
||||
date1: '2022年9月1日',
|
||||
tel: '000-0000-0000',
|
||||
sex: i % 2 === 0 ? 'boy' : 'girl',
|
||||
work: i % 2 === 0 ? 'back-end engineer' + (i + 1) : 'front-end engineer' + (i + 1),
|
||||
city: 'beijing'
|
||||
}));
|
||||
};
|
||||
|
||||
VTable.register.icon('sort_normal', {
|
||||
type: 'svg',
|
||||
svg: `<svg t="1669210412838" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="5700" width="200" height="200"><path d="M420.559974 72.98601l-54.855 0 0 774.336c-52.455014-69.163008-121.619046-123.762995-201.120051-157.052006l0 61.968c85.838029 41.401958 156.537958 111.337984 201.120051 198.221005l0 0.208 54.855 0 0-13.047c0.005018-0.00297 0.010035-0.005018 0.01495-0.007987-0.005018-0.010035-0.010035-0.019968-0.01495-0.030003L420.559974 72.986zM658.264986 73.385984l0-0.4L603.41 72.985984l0 877.68 54.855 0L658.265 176.524c52.457984 69.178982 121.632051 123.790029 201.149952 157.078016l0-61.961C773.560013 230.238003 702.853018 160.287027 658.264986 73.385984z" p-id="5701"></path></svg>`,
|
||||
width: 20, //其实指定的是svg图片绘制多大,实际占位是box,margin也是相对阴影范围指定的
|
||||
height: 20,
|
||||
funcType: VTable.TYPES.IconFuncTypeEnum.sort,
|
||||
name: 'sort_normal',
|
||||
positionType: VTable.TYPES.IconPosition.inlineFront,
|
||||
marginLeft: 0,
|
||||
marginRight: 0,
|
||||
hover: {
|
||||
width: 24,
|
||||
height: 24,
|
||||
bgColor: 'rgba(22,44,66,0.5)'
|
||||
},
|
||||
cursor: 'pointer'
|
||||
});
|
||||
|
||||
export function createTable() {
|
||||
const records = generatePersons(2000);
|
||||
const columns: VTable.ColumnsDefine = [
|
||||
{
|
||||
field: '',
|
||||
title: '行号',
|
||||
width: 80,
|
||||
fieldFormat(data, col, row, table) {
|
||||
return row - 1;
|
||||
},
|
||||
style: {
|
||||
underline: true,
|
||||
underlineDash: [2, 0],
|
||||
underlineOffset: 3
|
||||
}
|
||||
},
|
||||
{
|
||||
field: 'id',
|
||||
title: 'ID',
|
||||
width: 'auto',
|
||||
minWidth: 50,
|
||||
sort: true
|
||||
},
|
||||
{
|
||||
field: 'email1',
|
||||
title: 'email',
|
||||
width: 200,
|
||||
sort: true,
|
||||
style: {
|
||||
underline: true,
|
||||
underlineDash: [2, 0],
|
||||
underlineOffset: 3
|
||||
}
|
||||
},
|
||||
// {
|
||||
// title: 'full name',
|
||||
// columns: [
|
||||
// {
|
||||
// field: 'name',
|
||||
// title: 'First Name',
|
||||
// width: 200
|
||||
// },
|
||||
// {
|
||||
// field: 'name',
|
||||
// title: 'Last Name',
|
||||
// width: 200
|
||||
// }
|
||||
// ]
|
||||
// },
|
||||
{
|
||||
field: 'date1',
|
||||
title: 'birthday',
|
||||
width: 200
|
||||
},
|
||||
{
|
||||
field: 'sex',
|
||||
title: 'sex',
|
||||
width: 100
|
||||
},
|
||||
{
|
||||
field: 'tel',
|
||||
title: 'telephone',
|
||||
width: 150
|
||||
},
|
||||
{
|
||||
field: 'work',
|
||||
title: 'job',
|
||||
width: 200
|
||||
},
|
||||
{
|
||||
field: 'city',
|
||||
title: 'city',
|
||||
width: 150
|
||||
},
|
||||
{
|
||||
field: 'date1',
|
||||
title: 'birthday',
|
||||
width: 200
|
||||
},
|
||||
{
|
||||
field: 'sex',
|
||||
title: 'sex',
|
||||
width: 100
|
||||
},
|
||||
{
|
||||
field: 'tel',
|
||||
title: 'telephone',
|
||||
width: 150
|
||||
},
|
||||
{
|
||||
field: 'work',
|
||||
title: 'job',
|
||||
width: 200
|
||||
},
|
||||
{
|
||||
field: 'city',
|
||||
title: 'city',
|
||||
width: 150
|
||||
},
|
||||
{
|
||||
field: 'date1',
|
||||
title: 'birthday',
|
||||
width: 200
|
||||
},
|
||||
{
|
||||
field: 'sex',
|
||||
title: 'sex',
|
||||
width: 100
|
||||
},
|
||||
{
|
||||
field: 'tel',
|
||||
title: 'telephone',
|
||||
width: 150
|
||||
},
|
||||
{
|
||||
field: 'work',
|
||||
title: 'job',
|
||||
width: 200
|
||||
},
|
||||
{
|
||||
field: 'city',
|
||||
title: 'city',
|
||||
width: 150
|
||||
},
|
||||
{
|
||||
field: 'date1',
|
||||
title: 'birthday',
|
||||
width: 200
|
||||
},
|
||||
{
|
||||
field: 'sex',
|
||||
title: 'sex',
|
||||
width: 100
|
||||
},
|
||||
{
|
||||
field: 'tel',
|
||||
title: 'telephone',
|
||||
width: 150
|
||||
},
|
||||
{
|
||||
field: 'work',
|
||||
title: 'job',
|
||||
width: 200
|
||||
},
|
||||
{
|
||||
field: 'city',
|
||||
title: 'city',
|
||||
width: 150
|
||||
}
|
||||
];
|
||||
const option: VTable.ListTableConstructorOptions = {
|
||||
container: document.getElementById(CONTAINER_ID),
|
||||
emptyTip: true,
|
||||
records,
|
||||
columns: [
|
||||
...columns
|
||||
// ...columns,
|
||||
// ...columns,
|
||||
// ...columns,
|
||||
// ...columns,
|
||||
// ...columns,
|
||||
// ...columns,
|
||||
// ...columns,
|
||||
// ...columns,
|
||||
// ...columns
|
||||
],
|
||||
tooltip: {
|
||||
isShowOverflowTextTooltip: true
|
||||
},
|
||||
frozenColCount: 1,
|
||||
bottomFrozenRowCount: 2,
|
||||
rightFrozenColCount: 2,
|
||||
overscrollBehavior: 'none',
|
||||
// dragHeaderMode: 'all',
|
||||
keyboardOptions: {
|
||||
pasteValueToCell: true,
|
||||
copySelected: true,
|
||||
selectAllOnCtrlA: true
|
||||
},
|
||||
eventOptions: {
|
||||
preventDefaultContextMenu: false
|
||||
},
|
||||
autoWrapText: true,
|
||||
editor: '',
|
||||
// theme: VTable.themes.ARCO,
|
||||
// hover: {
|
||||
// highlightMode: 'cross'
|
||||
// },
|
||||
// select: {
|
||||
// headerSelectMode: 'cell',
|
||||
// highlightMode: 'cross'
|
||||
// },
|
||||
theme: {
|
||||
frameStyle: {
|
||||
cornerRadius: [10, 0, 0, 10],
|
||||
// cornerRadius: 10,
|
||||
borderLineWidth: [10, 0, 10, 10],
|
||||
// borderLineWidth: 10,
|
||||
borderColor: 'red',
|
||||
shadowBlur: 0
|
||||
},
|
||||
bodyStyle: {
|
||||
select: {
|
||||
cellBgColor: 'red',
|
||||
inlineRowBgColor: 'pink',
|
||||
inlineColumnBgColor: 'purple'
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
// transpose: true,
|
||||
select: {
|
||||
headerSelectMode: 'inline',
|
||||
highlightMode: 'cross',
|
||||
highlightInRange: true
|
||||
}
|
||||
// excelOptions: {
|
||||
// fillHandle: true
|
||||
// }
|
||||
// widthMode: 'adaptive'
|
||||
};
|
||||
const tableInstance = new VTable.ListTable(option);
|
||||
window.tableInstance = tableInstance;
|
||||
|
||||
bindDebugTool(tableInstance.scenegraph.stage, {
|
||||
customGrapicKeys: ['col', 'row']
|
||||
});
|
||||
|
||||
// tableInstance.on('sort_click', args => {
|
||||
// tableInstance.updateSortState(
|
||||
// {
|
||||
// field: args.field,
|
||||
// order: Date.now() % 3 === 0 ? 'desc' : Date.now() % 3 === 1 ? 'asc' : 'normal'
|
||||
// },
|
||||
// false
|
||||
// );
|
||||
// return false; //return false代表不执行内部排序逻辑
|
||||
// });
|
||||
}
|
@ -35,6 +35,10 @@ export const menus = [
|
||||
path: 'list',
|
||||
name: 'list'
|
||||
},
|
||||
{
|
||||
path: 'list',
|
||||
name: 'list-highlightInRange'
|
||||
},
|
||||
{
|
||||
path: 'list',
|
||||
name: 'list-transpose'
|
||||
|
@ -2,10 +2,11 @@ import type { StateManager } from '../state';
|
||||
import type { Group } from '../../scenegraph/graphic/group';
|
||||
import { getProp } from '../../scenegraph/utils/get-prop';
|
||||
import type { BaseTableAPI } from '../../ts-types/base-table';
|
||||
import type { ColumnDefine } from '../../ts-types';
|
||||
import type { CellRange, ColumnDefine } from '../../ts-types';
|
||||
import { HighlightScope } from '../../ts-types';
|
||||
import { isValid } from '@visactor/vutils';
|
||||
import { getCellMergeRange } from '../../tools/merge-range';
|
||||
import { cellInRange } from '../../tools/helper';
|
||||
|
||||
export function getCellSelectColor(cellGroup: Group, table: BaseTableAPI): string | undefined {
|
||||
let colorKey;
|
||||
@ -56,11 +57,84 @@ export function getCellSelectColor(cellGroup: Group, table: BaseTableAPI): strin
|
||||
return fillColor;
|
||||
}
|
||||
|
||||
export function isCellSelected(state: StateManager, col: number, row: number, cellGroup: Group): string | undefined {
|
||||
const { highlightScope, disableHeader, cellPos, ranges } = state.select;
|
||||
// 选中多列
|
||||
function isSelectMultipleRange(range: CellRange) {
|
||||
return range.start.col !== range.end.col || range.start.row !== range.end.row;
|
||||
}
|
||||
|
||||
function getSelectModeRange(state: StateManager, col: number, row: number) {
|
||||
let selectMode;
|
||||
if (ranges?.length === 1 && ranges[0].end.col === ranges[0].start.col && ranges[0].end.row === ranges[0].start.row) {
|
||||
const { highlightScope, cellPos, ranges } = state.select;
|
||||
const range = ranges[0];
|
||||
const rangeColStart = Math.min(range.start.col, range.end.col);
|
||||
const rangeColEnd = Math.max(range.start.col, range.end.col);
|
||||
const rangeRowStart = Math.min(range.start.row, range.end.row);
|
||||
const rangeRowEnd = Math.max(range.start.row, range.end.row);
|
||||
if (highlightScope === HighlightScope.single && cellPos.col === col && cellPos.row === row) {
|
||||
selectMode = 'cellBgColor';
|
||||
} else if (highlightScope === HighlightScope.column && col >= rangeColStart && col <= rangeColEnd) {
|
||||
if (cellInRange(ranges[0], col, row)) {
|
||||
selectMode = 'cellBgColor';
|
||||
} else {
|
||||
selectMode = 'inlineColumnBgColor';
|
||||
}
|
||||
} else if (highlightScope === HighlightScope.row && row >= rangeRowStart && row <= rangeRowEnd) {
|
||||
if (cellInRange(ranges[0], col, row)) {
|
||||
selectMode = 'cellBgColor';
|
||||
} else {
|
||||
selectMode = 'inlineRowBgColor';
|
||||
}
|
||||
} else if (highlightScope === HighlightScope.cross) {
|
||||
if (cellInRange(ranges[0], col, row)) {
|
||||
selectMode = 'cellBgColor';
|
||||
} else if (col >= rangeColStart && col <= rangeColEnd) {
|
||||
selectMode = 'inlineColumnBgColor';
|
||||
} else if (row >= rangeRowStart && row <= rangeRowEnd) {
|
||||
selectMode = 'inlineRowBgColor';
|
||||
}
|
||||
}
|
||||
return selectMode;
|
||||
}
|
||||
|
||||
function getSelectMode(state: StateManager, col: number, row: number) {
|
||||
let selectMode;
|
||||
const { highlightScope, cellPos } = state.select;
|
||||
|
||||
if (highlightScope === HighlightScope.single && cellPos.col === col && cellPos.row === row) {
|
||||
selectMode = 'cellBgColor';
|
||||
} else if (highlightScope === HighlightScope.column && cellPos.col === col) {
|
||||
if (cellPos.col === col && cellPos.row === row) {
|
||||
selectMode = 'cellBgColor';
|
||||
} else {
|
||||
selectMode = 'inlineColumnBgColor';
|
||||
}
|
||||
} else if (highlightScope === HighlightScope.row && cellPos.row === row) {
|
||||
if (cellPos.col === col && cellPos.row === row) {
|
||||
selectMode = 'cellBgColor';
|
||||
} else {
|
||||
selectMode = 'inlineRowBgColor';
|
||||
}
|
||||
} else if (highlightScope === HighlightScope.cross) {
|
||||
if (cellPos.col === col && cellPos.row === row) {
|
||||
selectMode = 'cellBgColor';
|
||||
} else if (cellPos.col === col) {
|
||||
selectMode = 'inlineColumnBgColor';
|
||||
} else if (cellPos.row === row) {
|
||||
selectMode = 'inlineRowBgColor';
|
||||
}
|
||||
}
|
||||
return selectMode;
|
||||
}
|
||||
|
||||
export function isCellSelected(state: StateManager, col: number, row: number, cellGroup: Group): string | undefined {
|
||||
const { highlightInRange, disableHeader, ranges } = state.select;
|
||||
let selectMode;
|
||||
const isSelectRange = ranges.length === 1 && isSelectMultipleRange(ranges?.[0]) && highlightInRange;
|
||||
if (
|
||||
isSelectRange
|
||||
? ranges?.length === 1 && ranges[0].start && ranges[0].end
|
||||
: ranges?.length === 1 && ranges[0].end.col === ranges[0].start.col && ranges[0].end.row === ranges[0].start.row
|
||||
) {
|
||||
const table = state.table;
|
||||
|
||||
const isHeader = table.isHeader(col, row);
|
||||
@ -68,29 +142,7 @@ export function isCellSelected(state: StateManager, col: number, row: number, ce
|
||||
return undefined;
|
||||
}
|
||||
|
||||
if (highlightScope === HighlightScope.single && cellPos.col === col && cellPos.row === row) {
|
||||
selectMode = 'cellBgColor';
|
||||
} else if (highlightScope === HighlightScope.column && cellPos.col === col) {
|
||||
if (cellPos.col === col && cellPos.row === row) {
|
||||
selectMode = 'cellBgColor';
|
||||
} else {
|
||||
selectMode = 'inlineColumnBgColor';
|
||||
}
|
||||
} else if (highlightScope === HighlightScope.row && cellPos.row === row) {
|
||||
if (cellPos.col === col && cellPos.row === row) {
|
||||
selectMode = 'cellBgColor';
|
||||
} else {
|
||||
selectMode = 'inlineRowBgColor';
|
||||
}
|
||||
} else if (highlightScope === HighlightScope.cross) {
|
||||
if (cellPos.col === col && cellPos.row === row) {
|
||||
selectMode = 'cellBgColor';
|
||||
} else if (cellPos.col === col) {
|
||||
selectMode = 'inlineColumnBgColor';
|
||||
} else if (cellPos.row === row) {
|
||||
selectMode = 'inlineRowBgColor';
|
||||
}
|
||||
}
|
||||
selectMode = isSelectRange ? getSelectModeRange(state, col, row) : getSelectMode(state, col, row);
|
||||
|
||||
if (selectMode) {
|
||||
let cellDisable;
|
||||
|
@ -79,6 +79,7 @@ export class StateManager {
|
||||
* 'body': 不选择表头,点击行表头则选择该行所有 body 单元格,点击列表头则选择该列所有 body 单元格。
|
||||
*/
|
||||
headerSelectMode?: 'inline' | 'cell' | 'body';
|
||||
highlightInRange?: boolean;
|
||||
selecting: boolean;
|
||||
};
|
||||
fillHandle: {
|
||||
@ -420,7 +421,8 @@ export class StateManager {
|
||||
headerSelectMode,
|
||||
disableSelect,
|
||||
disableHeaderSelect,
|
||||
highlightMode
|
||||
highlightMode,
|
||||
highlightInRange
|
||||
} = Object.assign(
|
||||
{},
|
||||
{
|
||||
@ -428,7 +430,8 @@ export class StateManager {
|
||||
headerSelectMode: 'inline',
|
||||
disableSelect: false,
|
||||
disableHeaderSelect: false,
|
||||
highlightMode: 'cell'
|
||||
highlightMode: 'cell',
|
||||
highlightInRange: false
|
||||
},
|
||||
this.table.options.select
|
||||
);
|
||||
@ -457,6 +460,7 @@ export class StateManager {
|
||||
this.select.singleStyle = !disableSelect;
|
||||
this.select.disableHeader = disableHeaderSelect;
|
||||
this.select.headerSelectMode = headerSelectMode;
|
||||
this.select.highlightInRange = highlightInRange;
|
||||
}
|
||||
|
||||
isSelected(col: number, row: number): boolean {
|
||||
|
@ -258,7 +258,9 @@ export { isNode, getChainSafe, applyChainSafe, getOrApply, getIgnoreCase, array
|
||||
export function cellInRange(range: CellRange, col: number, row: number): boolean {
|
||||
return (
|
||||
(range.start.col <= col && col <= range.end.col && range.start.row <= row && row <= range.end.row) ||
|
||||
(range.end.col <= col && col <= range.start.col && range.end.row <= row && row <= range.start.row)
|
||||
(range.end.col <= col && col <= range.start.col && range.end.row <= row && row <= range.start.row) ||
|
||||
(range.end.col <= col && col <= range.start.col && range.start.row <= row && row <= range.end.row) ||
|
||||
(range.start.col <= col && col <= range.end.col && range.end.row <= row && row <= range.start.row)
|
||||
);
|
||||
}
|
||||
export function cellInRanges(ranges: CellRange[], col: number, row: number): boolean {
|
||||
|
@ -375,6 +375,8 @@ export interface BaseTableConstructorOptions {
|
||||
outsideClickDeselect?: boolean; //
|
||||
/** 禁止拖拽框选 */
|
||||
disableDragSelect?: boolean;
|
||||
/** 是否在选择多行或多列时高亮范围 */
|
||||
highlightInRange?: boolean;
|
||||
};
|
||||
/** 下拉菜单的相关配置。消失时机:显示后点击菜单区域外自动消失*/
|
||||
menu?: {
|
||||
|
Loading…
Reference in New Issue
Block a user