UNPKG

@blueking/vxe-table

Version:

一个基于 vue 的 PC 端表格组件,支持增删改查、虚拟树、列拖拽,懒加载、快捷菜单、数据校验、树形结构、打印、导入导出、自定义模板、渲染器、JSON 配置式...

354 lines (353 loc) 17.2 kB
import { nextTick } from 'vue'; import XEUtils from 'xe-utils'; import { VxeUI } from '../../../ui'; import { toFilters, handleFieldOrColumn, getRefElem } from '../../src/util'; import { getDomNode, triggerEvent } from '../../../ui/src/dom'; import { isEnableConf } from '../../../ui/src/utils'; const { renderer, hooks } = VxeUI; const tableFilterMethodKeys = ['openFilter', 'setFilter', 'clearFilter', 'saveFilterPanel', 'resetFilterPanel', 'getCheckedFilters', 'updateFilterOptionStatus']; hooks.add('tableFilterModule', { setupTable($xeTable) { const { props, reactData, internalData } = $xeTable; const { refTableHeader, refTableBody, refTableFilter } = $xeTable.getRefMaps(); const { computeFilterOpts, computeMouseOpts } = $xeTable.getComputeMaps(); // 确认筛选 const handleFilterConfirmFilter = (evnt) => { const { filterStore } = reactData; filterStore.options.forEach((option) => { option.checked = option._checked; }); $xeTable.confirmFilterEvent(evnt); }; // (单选)筛选发生改变 const changeRadioOption = (evnt, checked, item) => { const { filterStore } = reactData; filterStore.options.forEach((option) => { option._checked = false; }); item._checked = checked; $xeTable.checkFilterOptions(); handleFilterConfirmFilter(evnt); }; // (多选)筛选发生改变 const changeMultipleOption = (evnt, checked, item) => { item._checked = checked; $xeTable.checkFilterOptions(); }; /** * 重置筛选 * 当筛选面板中的重置按钮被按下时触发 * @param {Event} evnt 事件 */ const handleFilterResetFilter = (evnt) => { const { filterStore } = reactData; $xeTable.handleClearFilter(filterStore.column); $xeTable.confirmFilterEvent(evnt); }; const filterPrivateMethods = { checkFilterOptions() { const { filterStore } = reactData; filterStore.isAllSelected = filterStore.options.every((item) => item._checked); filterStore.isIndeterminate = !filterStore.isAllSelected && filterStore.options.some((item) => item._checked); }, /** * 点击筛选事件 * 当筛选图标被点击时触发 * 更新选项是否全部状态 * 打开筛选面板 * @param {Event} evnt 事件 * @param {ColumnInfo} column 列配置 * @param {Object} params 参数 */ triggerFilterEvent(evnt, column, params) { const { initStore, filterStore } = reactData; if (filterStore.column === column && filterStore.visible) { filterStore.visible = false; } else { const { target: targetElem, pageX } = evnt; const { visibleWidth } = getDomNode(); const { filters, filterMultiple, filterRender } = column; const compConf = isEnableConf(filterRender) ? renderer.get(filterRender.name) : null; const frMethod = column.filterRecoverMethod || (compConf ? (compConf.tableFilterRecoverMethod || compConf.filterRecoverMethod) : null); internalData._currFilterParams = params; Object.assign(filterStore, { multiple: filterMultiple, options: filters, column, style: null }); // 复原状态 filterStore.options.forEach((option) => { const { _checked, checked } = option; option._checked = checked; if (!checked && _checked !== checked) { if (frMethod) { frMethod({ option, column, $table: $xeTable }); } } }); this.checkFilterOptions(); filterStore.visible = true; initStore.filter = true; nextTick(() => { const tableHeader = refTableHeader.value; const tableBody = refTableBody.value; const headerElem = tableHeader ? tableHeader.$el : null; const bodyElem = tableBody.$el; if (!bodyElem) { return; } const tableFilter = refTableFilter.value; const filterWrapperElem = tableFilter ? tableFilter.$el : null; if (!filterWrapperElem) { return; } const filterWidth = filterWrapperElem.offsetWidth; const filterHeight = filterWrapperElem.offsetHeight; const filterHeadElem = filterWrapperElem.querySelector('.vxe-table--filter-header'); const filterFootElem = filterWrapperElem.querySelector('.vxe-table--filter-footer'); const centerWidth = filterWidth / 2; const minMargin = 10; const maxLeft = bodyElem.clientWidth - filterWidth - minMargin; let left, right; const style = { top: `${targetElem.offsetTop + targetElem.offsetParent.offsetTop + targetElem.offsetHeight}px` }; // 判断面板不能大于表格高度 let maxHeight = null; const bodyHeight = bodyElem.clientHeight - (headerElem ? headerElem.clientHeight / 2 : 0); if (filterHeight >= bodyHeight) { maxHeight = Math.max(40, bodyHeight - (filterFootElem ? filterFootElem.offsetHeight : 0) - (filterHeadElem ? filterHeadElem.offsetHeight : 0)); } if (column.fixed === 'left') { left = targetElem.offsetLeft + targetElem.offsetParent.offsetLeft - centerWidth; } else if (column.fixed === 'right') { right = (targetElem.offsetParent.offsetWidth - targetElem.offsetLeft) + (targetElem.offsetParent.offsetParent.offsetWidth - targetElem.offsetParent.offsetLeft) - column.renderWidth - centerWidth; } else { left = targetElem.offsetLeft + targetElem.offsetParent.offsetLeft - centerWidth - bodyElem.scrollLeft; } if (left) { const overflowWidth = (pageX + filterWidth - centerWidth + minMargin) - visibleWidth; if (overflowWidth > 0) { left -= overflowWidth; } style.left = `${Math.min(maxLeft, Math.max(minMargin, left))}px`; } else if (right) { const overflowWidth = (pageX + filterWidth - centerWidth + minMargin) - visibleWidth; if (overflowWidth > 0) { right += overflowWidth; } style.right = `${Math.max(minMargin, right)}px`; } filterStore.style = style; filterStore.maxHeight = maxHeight; }); } $xeTable.dispatchEvent('filter-visible', { column, field: column.field, property: column.field, filterList: $xeTable.getCheckedFilters(), visible: filterStore.visible }, evnt); }, handleClearFilter(column) { if (column) { const { filters, filterRender } = column; if (filters) { const compConf = isEnableConf(filterRender) ? renderer.get(filterRender.name) : null; const frMethod = column.filterResetMethod || (compConf ? (compConf.tableFilterResetMethod || compConf.filterResetMethod) : null); filters.forEach((item) => { item._checked = false; item.checked = false; if (!frMethod) { item.data = XEUtils.clone(item.resetValue, true); } }); if (frMethod) { frMethod({ options: filters, column, $table: $xeTable }); } } } }, handleColumnConfirmFilter(column, evnt) { const { mouseConfig } = props; const { scrollXLoad: oldScrollXLoad, scrollYLoad: oldScrollYLoad } = reactData; const filterOpts = computeFilterOpts.value; const mouseOpts = computeMouseOpts.value; const { field } = column; const values = []; const datas = []; column.filters.forEach((item) => { if (item.checked) { values.push(item.value); datas.push(item.data); } }); const filterList = $xeTable.getCheckedFilters(); const params = { $table: $xeTable, $event: evnt, column, field, property: field, values, datas, filters: filterList, filterList }; // 如果是服务端筛选,则跳过本地筛选处理 if (!filterOpts.remote) { $xeTable.handleTableData(true); $xeTable.checkSelectionStatus(); } if (mouseConfig && mouseOpts.area && $xeTable.handleFilterEvent) { $xeTable.handleFilterEvent(evnt, params); } if (evnt) { $xeTable.dispatchEvent('filter-change', params, evnt); } $xeTable.closeFilter(); return $xeTable.updateFooter().then(() => { const { scrollXLoad, scrollYLoad } = reactData; if ((oldScrollXLoad || scrollXLoad) || (oldScrollYLoad || scrollYLoad)) { if (oldScrollXLoad || scrollXLoad) { $xeTable.updateScrollXSpace(); } if (oldScrollYLoad || scrollYLoad) { $xeTable.updateScrollYSpace(); } return $xeTable.refreshScroll(); } }).then(() => { $xeTable.updateCellAreas(); return $xeTable.recalculate(true); }).then(() => { // 存在滚动行为未结束情况 setTimeout(() => $xeTable.recalculate(), 50); }); }, /** * 确认筛选 * 当筛选面板中的确定按钮被按下时触发 * @param {Event} evnt 事件 */ confirmFilterEvent(evnt) { const { filterStore } = reactData; const { column } = filterStore; $xeTable.handleColumnConfirmFilter(column, evnt); }, handleFilterChangeRadioOption: changeRadioOption, handleFilterChangeMultipleOption: changeMultipleOption, // 筛选发生改变 handleFilterChangeOption(evnt, checked, item) { const { filterStore } = reactData; if (filterStore.multiple) { changeMultipleOption(evnt, checked, item); } else { changeRadioOption(evnt, checked, item); } }, handleFilterConfirmFilter, handleFilterResetFilter }; const filterMethods = { /** * 手动弹出筛选面板 * @param column */ openFilter(fieldOrColumn) { const column = handleFieldOrColumn($xeTable, fieldOrColumn); if (column && column.filters) { const { elemStore } = internalData; const { fixed } = column; return $xeTable.scrollToColumn(column).then(() => { const headerWrapperElem = getRefElem(elemStore[`${fixed || 'main'}-header-wrapper`] || elemStore['main-header-wrapper']); if (headerWrapperElem) { const filterBtnElem = headerWrapperElem.querySelector(`.vxe-header--column.${column.id} .vxe-filter--btn`); triggerEvent(filterBtnElem, 'click'); } }); } return nextTick(); }, /** * 修改筛选条件列表 * @param {ColumnInfo} fieldOrColumn 列或字段名 * @param {Array} options 选项 */ setFilter(fieldOrColumn, options, isUpdate) { const column = handleFieldOrColumn($xeTable, fieldOrColumn); if (column && column.filters) { column.filters = toFilters(options || []); if (isUpdate) { return $xeTable.handleColumnConfirmFilter(column, new Event('click')); } } return nextTick(); }, /** * 清空指定列的筛选条件 * 如果为空则清空所有列的筛选条件 * @param {String} fieldOrColumn 列或字段名 */ clearFilter(fieldOrColumn) { const { filterStore } = reactData; const { tableFullColumn } = internalData; const filterOpts = computeFilterOpts.value; let column; if (fieldOrColumn) { column = handleFieldOrColumn($xeTable, fieldOrColumn); if (column) { filterPrivateMethods.handleClearFilter(column); } } else { tableFullColumn.forEach(filterPrivateMethods.handleClearFilter); } if (!fieldOrColumn || column !== filterStore.column) { Object.assign(filterStore, { isAllSelected: false, isIndeterminate: false, style: null, options: [], column: null, multiple: false, visible: false }); } if (!filterOpts.remote) { return $xeTable.updateData(); } return nextTick(); }, saveFilterPanel() { handleFilterConfirmFilter(null); return nextTick(); }, resetFilterPanel() { handleFilterResetFilter(null); return nextTick(); }, getCheckedFilters() { const { tableFullColumn } = internalData; const filterList = []; tableFullColumn.forEach((column) => { const { field, filters } = column; const valueList = []; const dataList = []; if (filters && filters.length) { filters.forEach((item) => { if (item.checked) { valueList.push(item.value); dataList.push(item.data); } }); if (valueList.length) { filterList.push({ column, field, property: field, values: valueList, datas: dataList }); } } }); return filterList; }, updateFilterOptionStatus(item, checked) { item._checked = checked; item.checked = checked; return nextTick(); } }; return Object.assign(Object.assign({}, filterMethods), filterPrivateMethods); }, setupGrid($xeGrid) { return $xeGrid.extendTableMethods(tableFilterMethodKeys); } });