UNPKG

e-virt-table

Version:

A powerful data table based on canvas. You can use it as data grid、Microsoft Excel or Google sheets. It supports virtual scroll、cell edit etc.

343 lines 13.2 kB
import { isInnerScrollbarMode } from './ScrollbarMode'; export default class EventTable { constructor(ctx) { Object.defineProperty(this, "ctx", { enumerable: true, configurable: true, writable: true, value: void 0 }); Object.defineProperty(this, "visibleHoverCell", { enumerable: true, configurable: true, writable: true, value: void 0 }); Object.defineProperty(this, "resizeObserver", { enumerable: true, configurable: true, writable: true, value: void 0 }); Object.defineProperty(this, "mutationObserver", { enumerable: true, configurable: true, writable: true, value: void 0 }); this.ctx = ctx; this.init(); } init() { // 监听窗口大小变化 this.resizeObserver = new ResizeObserver((entries) => { this.ctx.emit('resetHeader'); this.ctx.emit('resizeObserver', entries); this.ctx.emit('containerResize', this.ctx.containerElement); }); this.resizeObserver.observe(this.ctx.containerElement); this.mutationObserver = new MutationObserver((mutations) => { for (const mutation of mutations) { if (mutation.type === 'attributes' && mutation.attributeName === 'class') { this.ctx.config.updateCssVar(); this.ctx.emit('draw'); } } }); if (this.ctx.config.ENABLE_AUTO_THEME) { this.mutationObserver.observe(document.documentElement, { attributes: true, attributeFilter: ['class'], // ✅ 只监听 class 更改 }); } // 按下事件 this.ctx.on('mousedown', (e) => { // 是否忙碌,进行其他操作 if (this.isBusy(e)) { return; } const { offsetY, offsetX } = this.ctx.getOffset(e); const y = offsetY; const x = offsetX; if (!this.isInsideBody(x, y)) { this.ctx.emit('mousedownBodyOutside', e); } // 左边点击 if (e.button !== 0) { return; } this.handleHeaderEvent(x, y, this.ctx.header.renderCellHeaders, (cell) => { this.ctx.focusCellHeader = cell; this.ctx.focusCell = undefined; this.ctx.emit('cellHeaderMousedown', cell, e); }); this.handleBodyEvent(x, y, this.ctx.body.renderRows, (cell) => { this.ctx.setFocusCell(cell); this.ctx.focusCellHeader = undefined; this.ctx.emit('cellMousedown', cell, e); }, true); }); // 按上事件 this.ctx.on('mouseup', (e) => { // 左边点击 if (e.button !== 0) { return; } // 是否忙碌,进行其他操作 if (this.isBusy(e)) { return; } const { offsetY, offsetX } = this.ctx.getOffset(e); const y = offsetY; const x = offsetX; this.handleHeaderEvent(x, y, this.ctx.header.renderCellHeaders, (cell) => { this.ctx.emit('cellHeaderMouseup', cell, e); }); this.handleBodyEvent(x, y, this.ctx.body.renderRows, (cell) => { this.ctx.emit('cellMouseup', cell, e); }); }); this.ctx.on('click', (e) => { // 左边点击 if (e.button !== 0) { return; } // 是否忙碌,进行其他操作 if (this.isBusy(e)) { return; } const y = this.ctx.getOffset(e).offsetY; const x = this.ctx.getOffset(e).offsetX; this.handleHeaderEvent(x, y, this.ctx.header.renderCellHeaders, (cell) => { this.ctx.clickCellHeader = cell; this.ctx.emit('cellHeaderClick', cell, e); }); // 可视区 this.handleBodyEvent(x, y, this.ctx.body.renderRows, (cell) => { this.ctx.clickCell = cell; this.ctx.emit('cellClick', cell, e); const hoverIcon = cell.getImage('hover'); if (!this.ctx.disableHoverIconClick && hoverIcon && hoverIcon.isInside(x, y)) { this.ctx.emit('hoverIconClick', cell); } }, true); }); this.ctx.on('dblclick', (e) => { // 左边点击 if (e.button !== 0) { return; } // 是否忙碌,进行其他操作 if (this.isBusy(e)) { return; } const y = this.ctx.getOffset(e).offsetY; const x = this.ctx.getOffset(e).offsetX; this.handleHeaderEvent(x, y, this.ctx.header.renderCellHeaders, (cell) => { this.ctx.emit('cellHeaderDblclick', cell, e); }); this.handleBodyEvent(x, y, this.ctx.body.renderRows, (cell) => { this.ctx.clickCell = cell; this.ctx.emit('cellDblclick', cell, e); }); }); this.ctx.on('contextMenu', (e) => { if (this.isBusy(e)) { return; } const { offsetY, offsetX } = this.ctx.getOffset(e); const y = offsetY; const x = offsetX; this.handleHeaderEvent(x, y, this.ctx.header.renderCellHeaders, (cell) => { this.ctx.emit('cellHeaderContextMenuClick', cell, e); }); this.handleBodyEvent(x, y, this.ctx.body.renderRows, (cell) => { this.ctx.emit('cellContextMenuClick', cell, e); }); }); this.ctx.on('mouseout', (e) => { if (!this.ctx.containerElement.contains(e.relatedTarget) && this.ctx.hoverCell !== undefined) { this.ctx.hoverRow = undefined; this.ctx.hoverCell = undefined; this.ctx.emit('draw'); } }); this.ctx.on('mousemove', (e) => { // 是否忙碌,进行其他操作 if (this.isBusy(e)) { return; } if (!this.ctx.mousedown && this.ctx.stageElement.style.cursor !== 'default') { this.ctx.stageElement.style.cursor = 'default'; } const y = this.ctx.getOffset(e).offsetY; const x = this.ctx.getOffset(e).offsetX; this.handleHeaderEvent(x, y, this.ctx.header.renderCellHeaders, (cell) => { this.imageEnterAndLeave(cell, e); this.ctx.emit('cellHeaderMouseenter', cell, e); // 移出事件 if (this.ctx.hoverCellHeader && this.ctx.hoverCellHeader !== cell) { this.ctx.emit('cellHeaderMouseleave', this.ctx.hoverCellHeader, e); } if (this.ctx.hoverCellHeader === cell) { return; } this.ctx.hoverCellHeader = cell; this.visibleHoverCell = undefined; // 清除可视区hover this.ctx.emit('cellHeaderHoverChange', cell, e); }); // 可视区 this.handleBodyEvent(x, y, this.ctx.body.renderRows, (cell) => { this.imageEnterAndLeave(cell, e); if (this.visibleHoverCell !== cell) { this.ctx.emit('visibleCellMouseleave', cell, e); this.visibleHoverCell = cell; this.ctx.hoverCellHeader = undefined; // 清除头部hover this.ctx.emit('visibleCellHoverChange', cell, e); } }, true); // 正常 this.handleBodyEvent(x, y, this.ctx.body.renderRows, (cell) => { // this.imageEnterAndLeave(cell, e); this.ctx.emit('cellMouseenter', cell, e); // 移出事件 if (this.ctx.hoverCell && this.ctx.hoverCell !== cell) { this.ctx.emit('cellMouseleave', cell, e); } if (this.ctx.hoverCell === cell) return; if (this.ctx.hoverCell?.rowKey !== cell.rowKey) { this.ctx.hoverCell = cell; this.ctx.hoverRow = this.ctx.body.renderRows.find((item) => item.rowKey === cell.rowKey); this.ctx.emit('rowHoverChange', this.ctx.hoverRow, cell, e); this.ctx.emit('draw'); } this.ctx.hoverCell = cell; this.ctx.emit('cellHoverChange', cell, e); }); this.handleFooterEvent(x, y, this.ctx.footer.renderRows, (cell) => { this.ctx.emit('cellFooterMouseenter', cell, e); // 移出事件 if (this.ctx.hoverCell && this.ctx.hoverCell !== cell) { this.ctx.emit('cellFooterMouseleave', cell, e); } this.ctx.emit('cellFooterHoverChange', cell, e); }); }); } /** * 图标进入和离开事件,包括选中,展开,提示图标等 * @param cell * @param e */ imageEnterAndLeave(cell, e) { if (this.ctx.dragRowIng || this.ctx.dragHeaderIng || this.ctx.selectorMove || this.ctx.autofillMove) { return; } const { offsetY, offsetX } = this.ctx.getOffset(e); const y = offsetY; const x = offsetX; cell.cellImages.forEach((image, key) => { if (image.isInside(x, y)) { if (key === 'drag') { this.ctx.stageElement.style.cursor = 'grab'; } else { this.ctx.stageElement.style.cursor = 'pointer'; } } }); } isBusy(e) { const { offsetY, offsetX } = this.ctx.getOffset(e); const y = offsetY; const x = offsetX; if (this.ctx.loading) { return true; } if (!this.ctx.isTarget(e)) { return true; } // 行调整大小中不处理 if (this.ctx.stageElement.style.cursor === 'row-resize') { return true; } // 列调整大小中不处理 if (this.ctx.stageElement.style.cursor === 'col-resize') { return true; } // 列调整大小中不处理 if (this.ctx.columnResizing) { return true; } // 行调整大小中不处理 if (this.ctx.rowResizing) { return true; } const { SCROLLER_TRACK_SIZE } = this.ctx.config; const innerScrollbar = isInnerScrollbarMode(this.ctx.config); // 滚动条移动不处理 if (this.ctx.scrollerMove) { return true; } // 滚动条悬浮不处理 if (this.ctx.scrollerFocus) { return true; } // 点击滚动条不处理 if (!innerScrollbar && y > this.ctx.stageHeight - SCROLLER_TRACK_SIZE) { return true; } // 点击滚动条不处理 if (!innerScrollbar && x > this.ctx.stageWidth - SCROLLER_TRACK_SIZE) { return true; } return false; } handleBodyEvent(x, y, renderRows, callback, visible = false) { if (!this.isInsideBody(x, y)) { return; } for (const row of renderRows) { // 优先处理固定列 const cells = row.fixedCells.concat(row.noFixedCells); for (const cell of cells) { const isInside = visible ? cell.isInsideVisible(x, y) : cell.isInside(x, y); if (isInside) { callback(cell); return; } } } } handleHeaderEvent(x, y, renderCellHeaders, callback) { for (const cell of renderCellHeaders) { if (cell.isInside(x, y)) { callback(cell); return; } } } handleFooterEvent(x, y, renderRows, callback) { for (const row of renderRows) { // 优先处理固定列 const cells = row.fixedCells.concat(row.noFixedCells); for (const cell of cells) { if (cell.isInside(x, y)) { callback(cell); return; } } } } isInsideBody(_x, _y) { const { body: { y, visibleHeight, height, visibleWidth, } } = this.ctx; const realityHeight = Math.min(height, visibleHeight); return _x > 0 && _x < visibleWidth && _y > y && _y < y + realityHeight; } destroy() { this.resizeObserver.unobserve(this.ctx.stageElement); this.mutationObserver.disconnect(); } } //# sourceMappingURL=EventTable.js.map