diff --git a/examples/views/table/renderer/Filter.vue b/examples/views/table/renderer/Filter.vue index bfef79d7b4..a45206f078 100644 --- a/examples/views/table/renderer/Filter.vue +++ b/examples/views/table/renderer/Filter.vue @@ -18,6 +18,9 @@ diff --git a/package.json b/package.json index e47c1fe904..da1707fb40 100644 --- a/package.json +++ b/package.json @@ -28,6 +28,7 @@ "style": "lib/style.css", "typings": "types/index.d.ts", "dependencies": { + "@floating-ui/vue": "^1.0.2", "dom-zindex": "^1.0.1", "xe-utils": "^3.5.14" }, diff --git a/packages/table/src/table.ts b/packages/table/src/table.ts index 20a04825f2..9c4ab0d3e2 100644 --- a/packages/table/src/table.ts +++ b/packages/table/src/table.ts @@ -1,4 +1,4 @@ -import { defineComponent, getCurrentInstance, h, createCommentVNode, ComponentPublicInstance, resolveComponent, ComponentOptions, reactive, ref, Ref, provide, inject, nextTick, onActivated, onDeactivated, onBeforeUnmount, onUnmounted, watch, computed, ComputedRef, onMounted } from 'vue' +import { defineComponent, getCurrentInstance, h, createCommentVNode, ComponentPublicInstance, resolveComponent, ComponentOptions, reactive, ref, Ref, provide, inject, nextTick, onActivated, onDeactivated, onBeforeUnmount, onUnmounted, watch, computed, ComputedRef, onMounted, Teleport } from 'vue' import XEUtils from 'xe-utils' import { browse, isPx, isScale, hasClass, addClass, removeClass, getEventTargetNode, getPaddingTopBottomSize, setScrollTop, setScrollLeft, isNodeElement } from '../../tools/dom' import { getLastZIndex, nextZIndex, hasChildrenList, getFuncText, isEnableConf, formatText, eqEmptyValue } from '../../tools/utils' @@ -17,6 +17,7 @@ import tableEmits from './emits' import VxeLoading from '../../loading/index' import { getRowUniqueId, clearTableAllStatus, getRowkey, getRowid, rowToVisible, colToVisible, getCellValue, setCellValue, handleFieldOrColumn, toTreePathSeq, restoreScrollLocation, restoreScrollListener, XEBodyScrollElement, getRootColumn } from './util' import { getSlotVNs } from '../../tools/vn' +import { useFloating, autoUpdate, offset, flip } from '@floating-ui/vue' import { VxeGridConstructor, VxeGridPrivateMethods, VxeTableConstructor, TableReactData, TableInternalData, VxeTablePropTypes, VxeToolbarConstructor, VxeTooltipInstance, TablePrivateMethods, VxeTablePrivateRef, VxeTablePrivateComputed, VxeTablePrivateMethods, VxeTableMethods, TableMethods, VxeMenuPanelInstance, VxeTableDefines, VxeTableProps, VxeColumnPropTypes, VxeTableDataRow } from '../../../types/all' @@ -339,6 +340,17 @@ export default defineComponent({ const $xegrid = inject<(VxeGridConstructor & VxeGridPrivateMethods) | null>('$xegrid', null) let $xetoolbar: VxeToolbarConstructor + const reference = ref(null) + + const { floatingStyles } = useFloating(reference, refTableFilter, { + // 浮动元素跟随目标元素 + whileElementsMounted (...args) { + const cleanup = autoUpdate(...args, { animationFrame: true }) + return cleanup + }, + middleware: [offset(10), flip()] + }) + const computeValidOpts = computed(() => { return Object.assign({}, GlobalConfig.table.validConfig, props.validConfig) as VxeTablePropTypes.ValidOpts }) @@ -1379,7 +1391,10 @@ export default defineComponent({ if (sortMultiple && chronological && orderColumns.length > 1) { orderColumns = XEUtils.orderBy(orderColumns, 'sortTime') } - + // 处理是否有筛选列 + if (tableFullColumn.findIndex(item => item.filters) > -1 && filterOpts.isFloating) { + reactData.initStore.filter = true + } // 处理筛选 // 支持单列、多列、组合筛选 if (!allRemoteFilter && filterColumns.length) { @@ -4470,6 +4485,8 @@ export default defineComponent({ if (tableFilter) { if (getEventTargetNode(evnt, el, 'vxe-cell--filter').flag) { // 如果点击了筛选按钮 + // 获取到元素位置 + reference.value = getEventTargetNode(evnt, el, 'vxe-cell--filter').targetElem } else if (getEventTargetNode(evnt, tableFilter.$el as HTMLDivElement).flag) { // 如果点击筛选容器 } else { @@ -6617,6 +6634,7 @@ export default defineComponent({ const mouseOpts = computeMouseOpts.value const validTipOpts = computeValidTipOpts.value const loadingOpts = computeLoadingOpts.value + const filterOpts = computeFilterOpts.value const isMenu = computeIsMenu.value return h('div', { ref: refElem, @@ -6740,7 +6758,13 @@ export default defineComponent({ /** * 筛选 */ - initStore.filter ? h(resolveComponent('vxe-table-filter') as ComponentOptions, { + initStore.filter ? filterOpts.isFloating ? h(Teleport, { + to: 'body' + }, [h(resolveComponent('vxe-table-filter'), { + ref: refTableFilter, + filterStore, + style: floatingStyles.value + })]) : h(resolveComponent('vxe-table-filter') as ComponentOptions, { ref: refTableFilter, filterStore }) : createCommentVNode(), diff --git a/types/table.d.ts b/types/table.d.ts index 5e7c14c8ea..8c943a78f4 100644 --- a/types/table.d.ts +++ b/types/table.d.ts @@ -1535,6 +1535,7 @@ export namespace VxeTablePropTypes { showIcon?: boolean iconNone?: string iconMatch?: string + isFloating?: boolean } export interface FilterOpts extends FilterConfig { }