From d7768e8a46bf414f614dc61d2394cd8203d57eb8 Mon Sep 17 00:00:00 2001 From: heao <72446584+heaxo@users.noreply.github.com> Date: Fri, 11 Sep 2026 12:28:08 +0800 Subject: [PATCH] feat: add menu mode to CellOperation renderer (#8393) * feat: add menu mode to CellOperation renderer * feat: add menu mode to CellOperation renderer --------- Co-authored-by: heao --- packages/locales/src/langs/en-US/common.json | 3 +- packages/locales/src/langs/zh-CN/common.json | 3 +- packages/locales/src/langs/zh-TW/common.json | 3 +- playground/src/adapter/vxe-table.ts | 93 ++++++++++++++++++- .../src/views/examples/vxe-table/viewed.vue | 5 +- 5 files changed, 100 insertions(+), 7 deletions(-) diff --git a/packages/locales/src/langs/en-US/common.json b/packages/locales/src/langs/en-US/common.json index b4a576aca..b53dc288c 100644 --- a/packages/locales/src/langs/en-US/common.json +++ b/packages/locales/src/langs/en-US/common.json @@ -22,5 +22,6 @@ "no": "No", "showSearchPanel": "Show search panel", "hideSearchPanel": "Hide search panel", - "notShow": "Don't Show" + "notShow": "Don't Show", + "more": "More" } diff --git a/packages/locales/src/langs/zh-CN/common.json b/packages/locales/src/langs/zh-CN/common.json index f33b18448..dce684b3a 100644 --- a/packages/locales/src/langs/zh-CN/common.json +++ b/packages/locales/src/langs/zh-CN/common.json @@ -22,5 +22,6 @@ "no": "否", "showSearchPanel": "显示搜索面板", "hideSearchPanel": "隐藏搜索面板", - "notShow": "不显示" + "notShow": "不显示", + "more": "更多" } diff --git a/packages/locales/src/langs/zh-TW/common.json b/packages/locales/src/langs/zh-TW/common.json index e56344769..64458f6bb 100644 --- a/packages/locales/src/langs/zh-TW/common.json +++ b/packages/locales/src/langs/zh-TW/common.json @@ -22,5 +22,6 @@ "no": "否", "showSearchPanel": "顯示搜尋面板", "hideSearchPanel": "隱藏搜尋面板", - "notShow": "不顯示" + "notShow": "不顯示", + "more": "更多" } diff --git a/playground/src/adapter/vxe-table.ts b/playground/src/adapter/vxe-table.ts index 391d9e06b..9131d1a88 100644 --- a/playground/src/adapter/vxe-table.ts +++ b/playground/src/adapter/vxe-table.ts @@ -17,7 +17,7 @@ import { import { get, isFunction, isString } from '@vben/utils'; import { objectOmit } from '@vueuse/core'; -import { Button, Image, Popconfirm, Switch, Tag } from 'antdv-next'; +import { Button, Dropdown, Image, Popconfirm, Switch, Tag } from 'antdv-next'; import { $t } from '#/locales'; @@ -134,7 +134,16 @@ setupVbenVxeTable({ * 注册表格的操作按钮渲染器 */ vxeUI.renderer.add('CellOperation', { - renderTableDefault({ attrs, options, props }, { column, row }) { + renderTableDefault({ attrs, options, props: rawProps }, { column, row }) { + const { + dropdownProps, + menuButtonProps, + menuIcon = 'ant-design:more-outlined', + menuText = $t('common.more'), + mode, + renderMode, + ...props + } = rawProps ?? {}; const defaultProps = { size: 'small', type: 'link', ...props }; let align: string; switch (column.align) { @@ -271,13 +280,91 @@ setupVbenVxeTable({ const btns = operations.map((opt) => opt.code === 'delete' ? renderConfirm(opt) : renderBtn(opt), ); + + function renderMenuTrigger() { + return h( + Button, + { + size: defaultProps.size, + type: defaultProps.type, + ...menuButtonProps, + }, + { + default: () => { + const content = []; + if (menuIcon) { + content.push( + h(IconifyIcon, { class: 'size-5', icon: menuIcon }), + ); + } + if (menuText) { + content.push(h('span', menuText)); + } + return h( + 'div', + { class: 'inline-flex items-center gap-1 leading-none' }, + content, + ); + }, + }, + ); + } + + const operationRenderStrategies: Recordable<() => any[]> = { + button: () => btns, + menu: () => [ + h( + Dropdown, + { + getPopupContainer: () => document.body, + placement: + column.align === 'left' + ? 'bottomLeft' + : 'bottomRight', + trigger: ['click'], + ...dropdownProps, + }, + { + default: () => + h( + 'span', + { + class: 'inline-flex cursor-pointer', + }, + [renderMenuTrigger()], + ), + + popupRender: () => + h( + 'div', + { + class: + 'ant-dropdown-menu flex flex-col gap-1 p-1', + + onClick: (event: MouseEvent) => + event.stopPropagation(), + + style: { + minWidth: '80px', + }, + }, + btns, + ), + }, + ), + ], + }; + const renderOperations = + operationRenderStrategies[renderMode ?? mode] ?? + operationRenderStrategies.button!; + return h( 'div', { class: 'flex table-operations', style: { justifyContent: align }, }, - btns, + renderOperations(), ); }, }); diff --git a/playground/src/views/examples/vxe-table/viewed.vue b/playground/src/views/examples/vxe-table/viewed.vue index d2b485566..05c94ca7a 100644 --- a/playground/src/views/examples/vxe-table/viewed.vue +++ b/playground/src/views/examples/vxe-table/viewed.vue @@ -35,6 +35,9 @@ const gridOptions: VxeGridProps = { { align: 'center', cellRender: { + props: { + renderMode: 'menu', + }, attrs: { nameField: 'category', onClick: onActionClick, @@ -53,7 +56,7 @@ const gridOptions: VxeGridProps = { headerAlign: 'center', showOverflow: false, title: $t('system.menu.operation'), - width: 200, + width: 100, }, ], exportConfig: {},