diff --git a/examples/views/table/TableTest2.vue b/examples/views/table/TableTest2.vue index 6a82c9484b..9513cb9822 100644 --- a/examples/views/table/TableTest2.vue +++ b/examples/views/table/TableTest2.vue @@ -13,8 +13,9 @@ ref="tableRef" id="bbbbb" :row-config="{useKey: true,drag:true}" + :row-drag-config="{trigger:'row',disabledMethod:disabledRowMethod}" :column-config="{useKey: true,drag: true}" - :column-drag-config="{isCrossDrag:true,isToChildDrag:true,isSelfToChildDrag:true}" + :column-drag-config="{isCrossDrag:true,isToChildDrag:true,isSelfToChildDrag:true,trigger:'default',disabledMethod:disabledColumnMethod}" :custom-config="customConfig" :loading="demo1.loading" :import-config="{modes: importModes}" @@ -40,8 +41,8 @@ - - + + { }, 100) }) +const disabledColumnMethod = ({ column }: any) => { + return column.field === 'sex11' +} + +const disabledRowMethod = ({ row }: any) => { + return row.id === 10002 +} + const rowDragstartEvent = (params: any) => { console.log(params) } diff --git a/package.json b/package.json index 7ddc354186..b54ef22d8e 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "vxe-table", - "version": "4.9.27", + "version": "4.9.28", "description": "一个基于 vue 的 PC 端表格组件,支持增删改查、虚拟树、拖拽排序,懒加载、快捷菜单、数据校验、树形结构、打印、导入导出、自定义模板、渲染器、JSON 配置式...", "scripts": { "update": "npm install --legacy-peer-deps", @@ -28,7 +28,7 @@ "style": "lib/style.css", "typings": "types/index.d.ts", "dependencies": { - "vxe-pc-ui": "^4.3.32" + "vxe-pc-ui": "^4.3.33" }, "devDependencies": { "@types/resize-observer-browser": "^0.1.11", diff --git a/packages/table/module/keyboard/hook.ts b/packages/table/module/keyboard/hook.ts index 3fe59b1eeb..fcdcc2ba6d 100644 --- a/packages/table/module/keyboard/hook.ts +++ b/packages/table/module/keyboard/hook.ts @@ -1,7 +1,7 @@ import XEUtils from 'xe-utils' import { VxeUI } from '../../../ui' import { getRefElem } from '../../src/util' -import { browse, hasClass, getAbsolutePos, addClass, removeClass, getEventTargetNode } from '../../../ui/src/dom' +import { browse, hasClass, getAbsolutePos, addClass, removeClass } from '../../../ui/src/dom' import type { TableKeyboardPrivateMethods } from '../../../../types' @@ -373,36 +373,7 @@ hooks.add('tableKeyboardModule', { $xeTable.handleSelected(params, evnt) }) }, - /** - * 表头单元格按下事件 - */ - triggerHeaderCellMousedownEvent (evnt, params) { - const { mouseConfig } = props - const mouseOpts = computeMouseOpts.value - if (mouseConfig && mouseOpts.area && $xeTable.handleHeaderCellAreaEvent) { - const cell = evnt.currentTarget - const triggerSort = getEventTargetNode(evnt, cell, 'vxe-cell--sort').flag - const triggerFilter = getEventTargetNode(evnt, cell, 'vxe-cell--filter').flag - $xeTable.handleHeaderCellAreaEvent(evnt, Object.assign({ cell, triggerSort, triggerFilter }, params)) - } - $xeTable.focus() - if ($xeTable.closeMenu) { - $xeTable.closeMenu() - } - }, - /** - * 单元格按下事件 - */ - triggerCellMousedownEvent (evnt, params) { - const cell = evnt.currentTarget - params.cell = cell - handleCellMousedownEvent(evnt, params) - $xeTable.focus() - $xeTable.closeFilter() - if ($xeTable.closeMenu) { - $xeTable.closeMenu() - } - } + handleCellMousedownEvent } return keyboardMethods diff --git a/packages/table/src/body.ts b/packages/table/src/body.ts index 0e1f83be02..e3efc48027 100644 --- a/packages/table/src/body.ts +++ b/packages/table/src/body.ts @@ -36,7 +36,7 @@ export default defineComponent({ const { xID, props: tableProps, context: tableContext, reactData: tableReactData, internalData: tableInternalData } = $xeTable const { refTableBody, refTableHeader, refTableFooter, refTableLeftBody, refTableRightBody, refScrollXHandleElem, refScrollYHandleElem } = $xeTable.getRefMaps() - const { computeEditOpts, computeMouseOpts, computeAreaOpts, computeSYOpts, computeEmptyOpts, computeKeyboardOpts, computeTooltipOpts, computeRadioOpts, computeExpandOpts, computeTreeOpts, computeCheckboxOpts, computeCellOpts, computeValidOpts, computeRowOpts, computeColumnOpts } = $xeTable.getComputeMaps() + const { computeEditOpts, computeMouseOpts, computeAreaOpts, computeSYOpts, computeEmptyOpts, computeKeyboardOpts, computeTooltipOpts, computeRadioOpts, computeExpandOpts, computeTreeOpts, computeCheckboxOpts, computeCellOpts, computeValidOpts, computeRowOpts, computeColumnOpts, computeRowDragOpts } = $xeTable.getComputeMaps() const refElem = ref() as Ref const refBodyTable = ref() as Ref @@ -140,6 +140,8 @@ export default defineComponent({ const editOpts = computeEditOpts.value const tooltipOpts = computeTooltipOpts.value const rowOpts = computeRowOpts.value + const rowDragOpts = computeRowDragOpts.value + const { disabledMethod: dragDisabledMethod } = rowDragOpts const sYOpts = computeSYOpts.value const columnOpts = computeColumnOpts.value const mouseOpts = computeMouseOpts.value @@ -195,6 +197,14 @@ export default defineComponent({ data: tableData, items } + let isColDragCell = false + let isDisabledDrag = false + if (rowOpts.drag) { + isColDragCell = rowDragOpts.trigger === 'row' || (column.dragSort && rowDragOpts.trigger === 'cell') + } + if (isColDragCell) { + isDisabledDrag = !!(dragDisabledMethod && dragDisabledMethod(params)) + } // hover 进入事件 if (showTitle || showTooltip || showAllTip || tooltipConfig) { tdOns.onMouseenter = (evnt: MouseEvent) => { @@ -223,7 +233,7 @@ export default defineComponent({ } } // 按下事件处理 - if (checkboxOpts.range || mouseConfig) { + if (isColDragCell || checkboxOpts.range || mouseConfig) { tdOns.onMousedown = (evnt: MouseEvent) => { $xeTable.triggerCellMousedownEvent(evnt, params) } @@ -367,6 +377,8 @@ export default defineComponent({ 'col--edit': isEdit, 'col--ellipsis': hasEllipsis, 'fixed--hidden': fixedHiddenColumn, + 'is--drag-cell': isColDragCell, + 'is--drag-disabled': isDisabledDrag, 'col--dirty': isDirty, 'col--active': editConfig && isEdit && (actived.row === row && (actived.column === column || editOpts.mode === 'row')), 'col--valid-error': !!errorValidItem, diff --git a/packages/table/src/cell.ts b/packages/table/src/cell.ts index aa73304888..edf7522363 100644 --- a/packages/table/src/cell.ts +++ b/packages/table/src/cell.ts @@ -50,20 +50,24 @@ function renderCellDragIcon (params: VxeTableDefines.CellRenderBodyParams) { const { dragConfig } = tableProps const { computeRowDragOpts } = $table.getComputeMaps() const rowDragOpts = computeRowDragOpts.value - const { icon, disabledMethod } = rowDragOpts + const { icon, trigger, disabledMethod } = rowDragOpts const rDisabledMethod = disabledMethod || (dragConfig ? dragConfig.rowDisabledMethod : null) const isDisabled = rDisabledMethod && rDisabledMethod(params) + const ons: Record = {} + if (trigger !== 'cell') { + ons.onMousedown = (evnt: MouseEvent) => { + if (!isDisabled) { + $table.handleCellDragMousedownEvent(evnt, params) + } + } + ons.onMouseup = $table.handleCellDragMouseupEvent + } return h('span', { key: 'dg', class: ['vxe-cell--drag-handle', { 'is--disabled': isDisabled }], - onMousedown (evnt) { - if (!isDisabled) { - $table.handleCellDragMousedownEvent(evnt, params) - } - }, - onMouseup: $table.handleCellDragMouseupEvent + ...ons }, [ h('i', { class: icon || (dragConfig ? dragConfig.rowIcon : '') || getIcon().TABLE_DRAG_ROW @@ -103,21 +107,25 @@ function renderHeaderCellDragIcon (params: VxeTableDefines.CellRenderHeaderParam const { computeColumnOpts, computeColumnDragOpts } = $table.getComputeMaps() const columnOpts = computeColumnOpts.value const columnDragOpts = computeColumnDragOpts.value - const { showIcon, icon, isCrossDrag, visibleMethod, disabledMethod } = columnDragOpts - const isDisabled = disabledMethod && disabledMethod(params) + const { showIcon, icon, trigger, isCrossDrag, visibleMethod, disabledMethod } = columnDragOpts if (columnOpts.drag && showIcon && (!visibleMethod || visibleMethod(params))) { if (!column.fixed && (isCrossDrag || !column.parentId)) { + const isDisabled = disabledMethod && disabledMethod(params) + const ons: Record = {} + if (trigger !== 'cell') { + ons.onMousedown = (evnt: MouseEvent) => { + if (!isDisabled) { + $table.handleHeaderCellDragMousedownEvent(evnt, params) + } + } + ons.onMouseup = $table.handleHeaderCellDragMouseupEvent + } return h('span', { key: 'dg', class: ['vxe-cell--drag-handle', { 'is--disabled': isDisabled }], - onMousedown (evnt) { - if (!isDisabled) { - $table.handleHeaderCellDragMousedownEvent(evnt, params) - } - }, - onMouseup: $table.handleHeaderCellDragMouseupEvent + ...ons }, [ h('i', { class: icon || getIcon().TABLE_DRAG_COLUMN diff --git a/packages/table/src/header.ts b/packages/table/src/header.ts index 2b6d11de7f..8746090bdb 100644 --- a/packages/table/src/header.ts +++ b/packages/table/src/header.ts @@ -27,7 +27,7 @@ export default defineComponent({ const { xID, props: tableProps, reactData: tableReactData, internalData: tableInternalData } = $xeTable const { refElem: tableRefElem, refTableBody, refLeftContainer, refRightContainer, refCellResizeBar, refCellResizeTip } = $xeTable.getRefMaps() - const { computeColumnOpts, computeResizableOpts } = $xeTable.getComputeMaps() + const { computeColumnOpts, computeColumnDragOpts, computeResizableOpts } = $xeTable.getComputeMaps() const headerColumn = ref([] as VxeTableDefines.ColumnInfo[][]) @@ -169,6 +169,8 @@ export default defineComponent({ const { resizable: allResizable, border, columnKey, headerCellClassName, headerCellStyle, showHeaderOverflow: allColumnHeaderOverflow, headerAlign: allHeaderAlign, align: allAlign, mouseConfig } = tableProps const { currentColumn, scrollXLoad, overflowX, scrollbarWidth } = tableReactData const columnOpts = computeColumnOpts.value + const columnDragOpts = computeColumnDragOpts.value + const { disabledMethod: dragDisabledMethod } = columnDragOpts return cols.map((column, $columnIndex) => { const { type, showHeaderOverflow, headerAlign, align, headerClassName, editRender, cellRender } = column const colid = column.id @@ -186,6 +188,11 @@ export default defineComponent({ const columnIndex = $xeTable.getColumnIndex(column) const _columnIndex = $xeTable.getVTColumnIndex(column) const params: VxeTableDefines.CellRenderHeaderParams = { $table: $xeTable, $grid: $xeTable.xegrid, $rowIndex, column, columnIndex, $columnIndex, _columnIndex, fixed: fixedType, type: renderType, isHidden: fixedHiddenColumn, hasFilter } + const thAttrs: Record = { + colid, + colspan: column.colSpan > 1 ? column.colSpan : null, + rowspan: column.rowSpan > 1 ? column.rowSpan : null + } const thOns: any = { onClick: (evnt: MouseEvent) => $xeTable.triggerHeaderCellClickEvent(evnt, params), onDblclick: (evnt: MouseEvent) => $xeTable.triggerHeaderCellDblclickEvent(evnt, params) @@ -194,15 +201,23 @@ export default defineComponent({ if (scrollXLoad && !hasEllipsis) { showEllipsis = hasEllipsis = true } + const isColDragCell = columnOpts.drag && columnDragOpts.trigger === 'cell' + let isDisabledDrag = false + if (isColDragCell) { + isDisabledDrag = !!(dragDisabledMethod && dragDisabledMethod(params)) + } // 按下事件处理 - if (mouseConfig) { + if (mouseConfig || isColDragCell) { thOns.onMousedown = (evnt: MouseEvent) => $xeTable.triggerHeaderCellMousedownEvent(evnt, params) } - // 拖拽行事件 + // 拖拽列事件 if (columnOpts.drag) { thOns.onDragstart = $xeTable.handleHeaderCellDragDragstartEvent thOns.onDragend = $xeTable.handleHeaderCellDragDragendEvent thOns.onDragover = $xeTable.handleHeaderCellDragDragoverEvent + if (isColDragCell) { + thOns.onMouseup = $xeTable.handleHeaderCellDragMouseupEvent + } } return h('th', { class: ['vxe-header--column', colid, { @@ -216,15 +231,14 @@ export default defineComponent({ 'is--sortable': column.sortable, 'col--filter': !!column.filters, 'is--filter-active': hasFilter, + 'is--drag-disabled': isDisabledDrag, 'col--current': currentColumn === column }, headerClassName ? (XEUtils.isFunction(headerClassName) ? headerClassName(params) : headerClassName) : '', headerCellClassName ? (XEUtils.isFunction(headerCellClassName) ? headerCellClassName(params) : headerCellClassName) : '' ], - colid, - colspan: column.colSpan > 1 ? column.colSpan : null, - rowspan: column.rowSpan > 1 ? column.rowSpan : null, style: headerCellStyle ? (XEUtils.isFunction(headerCellStyle) ? headerCellStyle(params) : headerCellStyle) : null, + ...thAttrs, ...thOns, key: columnKey || columnOpts.useKey || columnOpts.drag || isColGroup ? colid : $columnIndex }, [ diff --git a/packages/table/src/table.ts b/packages/table/src/table.ts index 45c8e642a4..0c7f369b3e 100644 --- a/packages/table/src/table.ts +++ b/packages/table/src/table.ts @@ -7168,6 +7168,74 @@ export default defineComponent({ $xeTable.handleColumnSortEvent(evnt, column) } }, + /** + * 表头单元格按下事件 + */ + triggerHeaderCellMousedownEvent (evnt, params) { + const { mouseConfig } = props + const mouseOpts = computeMouseOpts.value + const columnOpts = computeColumnOpts.value + const columnDragOpts = computeColumnDragOpts.value + const { trigger, disabledMethod } = columnDragOpts + const cell = evnt.currentTarget as HTMLDivElement + const triggerInput = cell && cell.tagName && cell.tagName.toLowerCase() === 'input' + const triggerCheckbox = getEventTargetNode(evnt, cell, 'vxe-cell--checkbox').flag + const triggerSort = getEventTargetNode(evnt, cell, 'vxe-cell--sort').flag + const triggerFilter = getEventTargetNode(evnt, cell, 'vxe-cell--filter').flag + let triggerDrag = false + if (!(triggerInput || triggerCheckbox || triggerSort || triggerFilter)) { + if (columnOpts.drag && trigger === 'cell' && !(disabledMethod && disabledMethod(params))) { + triggerDrag = true + $xeTable.handleHeaderCellDragMousedownEvent(evnt, params) + } + } + if (!triggerDrag && mouseConfig && mouseOpts.area && $xeTable.handleHeaderCellAreaEvent) { + $xeTable.handleHeaderCellAreaEvent(evnt, Object.assign({ cell, triggerSort, triggerFilter }, params)) + } + $xeTable.focus() + if ($xeTable.closeMenu) { + $xeTable.closeMenu() + } + }, + /** + * 单元格按下事件 + */ + triggerCellMousedownEvent (evnt, params) { + const { column } = params + const { type, treeNode } = column + const isRadioType = type === 'radio' + const isCheckboxType = type === 'checkbox' + const isExpandType = type === 'expand' + const rowOpts = computeRowOpts.value + const rowDragOpts = computeRowDragOpts.value + const { trigger, disabledMethod } = rowDragOpts + const cell = evnt.currentTarget + params.cell = cell + const triggerInput = cell && cell.tagName && cell.tagName.toLowerCase() === 'input' + const triggerRadio = isRadioType && getEventTargetNode(evnt, cell, 'vxe-cell--radio').flag + const triggerCheckbox = isCheckboxType && getEventTargetNode(evnt, cell, 'vxe-cell--checkbox').flag + const triggerTreeNode = treeNode && getEventTargetNode(evnt, cell, 'vxe-tree--btn-wrapper').flag + const triggerExpandNode = isExpandType && getEventTargetNode(evnt, cell, 'vxe-table--expanded').flag + let isColDragCell = false + if (rowOpts.drag) { + isColDragCell = trigger === 'row' || (column.dragSort && trigger === 'cell') + } + let triggerDrag = false + if (!(triggerInput || triggerRadio || triggerCheckbox || triggerTreeNode || triggerExpandNode)) { + if (isColDragCell && !(disabledMethod && disabledMethod(params))) { + triggerDrag = true + $xeTable.handleCellDragMousedownEvent(evnt, params) + } + } + if (!triggerDrag && $xeTable.handleCellMousedownEvent) { + $xeTable.handleCellMousedownEvent(evnt, params) + } + $xeTable.focus() + $xeTable.closeFilter() + if ($xeTable.closeMenu) { + $xeTable.closeMenu() + } + }, /** * 行拖拽 */ @@ -7393,15 +7461,15 @@ export default defineComponent({ } }, handleCellDragMousedownEvent (evnt, params) { + evnt.stopPropagation() const { dragConfig } = props const rowDragOpts = computeRowDragOpts.value - const { dragStartMethod } = rowDragOpts + const { trigger, dragStartMethod } = rowDragOpts const { row } = params const dragEl = evnt.currentTarget as HTMLElement - const tdEl = dragEl.parentElement?.parentElement as HTMLElement + const tdEl = trigger === 'cell' || trigger === 'row' ? dragEl : dragEl.parentElement?.parentElement as HTMLElement const trEl = tdEl.parentElement as HTMLElement const dStartMethod = dragStartMethod || (dragConfig ? dragConfig.dragStartMethod : null) - reactData.isDragRowMove = false clearRowDropOrigin() if (dStartMethod && !dStartMethod(params)) { trEl.draggable = false @@ -7641,11 +7709,12 @@ export default defineComponent({ } }, handleHeaderCellDragMousedownEvent (evnt, params) { + evnt.stopPropagation() const columnDragOpts = computeColumnDragOpts.value - const { dragStartMethod } = columnDragOpts + const { trigger, dragStartMethod } = columnDragOpts const { column } = params const dragEl = evnt.currentTarget as HTMLElement - const thEl = dragEl.parentElement?.parentElement as HTMLElement + const thEl = trigger === 'cell' ? dragEl : dragEl.parentElement?.parentElement as HTMLElement reactData.isDragColMove = false clearColDropOrigin() if (dragStartMethod && !dragStartMethod(params)) { @@ -8183,6 +8252,7 @@ export default defineComponent({ const resizableOpts = computeResizableOpts.value const isArea = mouseConfig && mouseOpts.area const tableStyle = computeTableStyle.value + const columnDragOpts = computeColumnDragOpts.value return h('div', { ref: refElem, class: ['vxe-table', 'vxe-table--render-default', `tid_${xID}`, `border--${tableBorder}`, { @@ -8199,6 +8269,7 @@ export default defineComponent({ 'column--highlight': columnOpts.isHover || highlightHoverColumn, 'checkbox--range': checkboxOpts.range, 'column--calc': isCalcColumn, + 'col--drag-cell': columnOpts.drag && columnDragOpts.trigger === 'cell', 'is--header': showHeader, 'is--footer': showFooter, 'is--group': isGroup, @@ -8754,7 +8825,7 @@ export default defineComponent({ if (props.editRules && !$xeTable.validate) { errLog('vxe.error.reqModule', ['Validator']) } - if ((checkboxOpts.range || props.keyboardConfig || props.mouseConfig) && !$xeTable.triggerCellMousedownEvent) { + if ((checkboxOpts.range || props.keyboardConfig || props.mouseConfig) && !$xeTable.handleCellMousedownEvent) { errLog('vxe.error.reqModule', ['Keyboard']) } if ((props.printConfig || props.importConfig || props.exportConfig) && !$xeTable.exportData) { diff --git a/styles/components/table.scss b/styles/components/table.scss index 7d68c429e9..c02d5d5fc0 100644 --- a/styles/components/table.scss +++ b/styles/components/table.scss @@ -677,6 +677,24 @@ } } } + &.col--drag-cell { + .vxe-header--column { + user-select: none; + &:not(.is--drag-disabled) { + cursor: grab; + &:active { + cursor: grabbing; + } + &:hover { + color: var(--vxe-ui-font-primary-color); + } + } + &.is--drag-disabled { + color: var(--vxe-ui-input-disabled-color); + cursor: not-allowed; + } + } + } &.column--highlight { .vxe-header--column { &:not(.col--seq) { @@ -1368,6 +1386,24 @@ } } } + .vxe-body--column { + &.is--drag-cell { + user-select: none; + &:not(.is--drag-disabled) { + cursor: grab; + &:active { + cursor: grabbing; + } + &:hover { + color: var(--vxe-ui-font-primary-color); + } + } + &.is--drag-disabled { + color: var(--vxe-ui-input-disabled-color); + cursor: not-allowed; + } + } + } .vxe-body--row-list-move { transition-property: transform; transition-duration: 0.35s;