feat: support column and row select

This commit is contained in:
JayBridge 2025-06-07 23:37:48 +08:00
parent 88d92fa033
commit 67d3b3f257
2 changed files with 216 additions and 2 deletions

View file

@ -39,6 +39,10 @@ export class CSVView extends TextFileView {
private activeRowIndex: number = -1;
private activeColIndex: number = -1;
// 新增:选中状态
private selectedRow: number = -1;
private selectedCol: number = -1;
constructor(leaf: any) {
super(leaf);
this.historyManager = new TableHistoryManager(
@ -148,7 +152,7 @@ export class CSVView extends TextFileView {
this.tableEl.empty();
// 创建表头行用于调整列宽
// 创建表头行(包含列号)
const headerRow = this.tableEl.createEl("thead").createEl("tr");
// 计算初始列宽(如果未设置)
@ -158,10 +162,44 @@ export class CSVView extends TextFileView {
);
}
// 创建表头和调整列宽的手柄
// 添加左上角单元格
const cornerCell = headerRow.createEl("th", {
cls: "csv-corner-cell",
});
// 创建列号行
if (this.tableData[0]) {
this.tableData[0].forEach((headerCell, index) => {
const th = headerRow.createEl("th", {
cls: "csv-col-number",
attr: {
style: `width: ${this.columnWidths[index] || 100}px`,
},
});
// 显示列号A, B, C...
th.textContent = this.getColumnLabel(index);
// 添加列选择功能
th.onclick = () => {
this.selectColumn(index);
};
});
}
// 创建表头数据行
const dataHeaderRow = this.tableEl.createEl("thead").createEl("tr");
// 添加行号列(表头行)
const headerRowNumber = dataHeaderRow.createEl("th", {
cls: "csv-row-number",
});
headerRowNumber.textContent = "0";
// 添加表头输入框
if (this.tableData[0]) {
this.tableData[0].forEach((headerCell, index) => {
const th = dataHeaderRow.createEl("th", {
cls: "csv-th",
attr: {
style: `width: ${this.columnWidths[index] || 100}px`,
@ -216,6 +254,18 @@ export class CSVView extends TextFileView {
const row = this.tableData[i];
const tableRow = tableBody.createEl("tr");
// 添加行号列
const rowNumberCell = tableRow.createEl("td", {
cls: "csv-row-number",
});
rowNumberCell.textContent = i.toString();
// 添加行选择功能
rowNumberCell.onclick = () => {
this.selectRow(i);
};
// 添加数据单元格
row.forEach((cell, j) => {
const td = tableRow.createEl("td", {
attr: { style: `width: ${this.columnWidths[j] || 100}px` },
@ -294,6 +344,77 @@ export class CSVView extends TextFileView {
}
}
// 新增获取列标签A, B, C, ... Z, AA, AB, ...
private getColumnLabel(index: number): string {
let result = '';
let num = index;
do {
result = String.fromCharCode(65 + (num % 26)) + result;
num = Math.floor(num / 26) - 1;
} while (num >= 0);
return result;
}
// 新增:选择行
private selectRow(rowIndex: number) {
// 如果点击的是已选中的行,则取消选择
if (this.selectedRow === rowIndex) {
this.clearSelection();
return;
}
// 清除之前的选择
this.clearSelection();
this.selectedRow = rowIndex;
// 添加选中样式到整行
const rows = this.tableEl.querySelectorAll('tbody tr');
const targetRowIndex = rowIndex - 1; // 因为数据行从索引1开始tbody中的索引需要-1
if (rows[targetRowIndex]) {
rows[targetRowIndex].addClass('csv-row-selected');
}
}
// 新增:选择列
private selectColumn(colIndex: number) {
// 如果点击的是已选中的列,则取消选择
if (this.selectedCol === colIndex) {
this.clearSelection();
return;
}
// 清除之前的选择
this.clearSelection();
this.selectedCol = colIndex;
// 添加选中样式到整列(包括列号和所有数据单元格)
// colIndex + 2 是因为有行号列(+1)和从0开始的索引(+1)
const columnCells = this.tableEl.querySelectorAll(`th:nth-child(${colIndex + 2}), td:nth-child(${colIndex + 2})`);
columnCells.forEach(cell => {
if (cell instanceof HTMLElement) {
cell.addClass('csv-col-selected');
}
});
}
// 新增:清除选择
private clearSelection() {
this.selectedRow = -1;
this.selectedCol = -1;
// 移除所有选中样式
this.tableEl.querySelectorAll('.csv-row-selected, .csv-col-selected').forEach(el => {
if (el instanceof HTMLElement) {
el.removeClass('csv-row-selected');
el.removeClass('csv-col-selected');
}
});
}
// 设置活动单元格
private setActiveCell(
rowIndex: number,

View file

@ -13,6 +13,7 @@ If your plugin does not need CSS, delete this file.
width: 100%;
margin-top: 10px;
table-layout: fixed;
position: relative;
}
.csv-lite-table td,
@ -241,3 +242,95 @@ td input:focus {
.csv-lite-table th .csv-cell-input {
background: var(--background-modifier-box-shadow-hover);
}
/* 行号和列号样式 */
.csv-row-number,
.csv-col-number {
background-color: var(--background-secondary);
color: var(--text-muted);
font-size: 0.85em;
text-align: center;
font-weight: 500;
user-select: none;
cursor: default;
}
.csv-row-number {
width: 40px;
min-width: 40px;
max-width: 40px;
border-right: 2px solid var(--background-modifier-border);
position: sticky;
left: 0;
z-index: 10;
}
.csv-col-number {
height: 25px;
min-height: 25px;
max-height: 25px;
border-bottom: 2px solid var(--background-modifier-border);
position: sticky;
top: 0;
z-index: 9;
}
/* 左上角交叉单元格 */
.csv-corner-cell {
background-color: var(--background-secondary);
border-right: 2px solid var(--background-modifier-border);
border-bottom: 2px solid var(--background-modifier-border);
position: sticky;
left: 0;
top: 0;
z-index: 11;
width: 40px;
min-width: 40px;
max-width: 40px;
height: 25px;
min-height: 25px;
max-height: 25px;
}
/* 调整普通单元格的z-index */
.csv-lite-table td,
.csv-lite-table th:not(.csv-row-number):not(.csv-col-number):not(.csv-corner-cell) {
/* ...existing code... */
z-index: 1;
}
/* 行号列点击高亮效果 */
.csv-row-number:hover {
background-color: var(--background-modifier-hover);
}
.csv-col-number:hover {
background-color: var(--background-modifier-hover);
}
/* 选中行/列的高亮效果 - 统一样式 */
.csv-row-selected .csv-row-number,
.csv-col-selected.csv-col-number {
background-color: var(--interactive-accent);
color: var(--text-on-accent);
}
/* 选中行的所有单元格高亮 */
.csv-row-selected td {
background-color: var(--background-modifier-hover);
}
/* 选中列的所有单元格高亮 */
.csv-col-selected {
background-color: var(--background-modifier-hover);
}
/* 选中行的输入框样式调整 */
.csv-row-selected td .csv-cell-input {
background-color: var(--background-primary);
}
/* 选中列的输入框样式调整 */
.csv-col-selected .csv-cell-input {
background-color: var(--background-primary);
}