UNPKG

@fesjs/fes-design

Version:
441 lines (432 loc) 13.7 kB
import _defineProperty from '@babel/runtime/helpers/esm/defineProperty'; import { ref, computed, reactive, watch } from 'vue'; import { isUndefined, throttle, isPlainObject, isFunction } from 'lodash-es'; import getPrefixCls from '../_util/getPrefixCls'; import { getCellValue } from './helper'; import useTableLayout from './useTableLayout'; function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; } function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; } const prefixCls = getPrefixCls('table'); var useTableStyle = _ref => { let { props, columns, columnsFixed, expandColumn, isExpandOpened, showData } = _ref; const wrapperRef = ref(null); const headerWrapperRef = ref(null); const bodyWrapperRef = ref(null); const scrollbarRef = ref(null); const bodyTableRef = ref(null); const isWidthAuto = computed(() => { return isUndefined(props.height) && props.layout === 'auto'; }); const wrapperClass = computed(() => [prefixCls, props.bordered && 'is-bordered', props.size && `is-size-${props.size}`, props.horizontalLine && 'is-horizontal-line', props.verticalLine && 'is-vertical-line'].filter(Boolean).join(' ')); const layout = useTableLayout({ wrapperRef, headerWrapperRef, bodyWrapperRef, bodyTableRef, props, columns, showData }); const scrollState = reactive({ x: '' // 默认为空值,避免左侧列固定的时候,右侧默认出现阴影区域 }); watch(computed(() => { var _scrollbarRef$value; return (_scrollbarRef$value = scrollbarRef.value) === null || _scrollbarRef$value === void 0 ? void 0 : _scrollbarRef$value.containerRef; }), () => { var _scrollbarRef$value2, _scrollbarRef$value3; // 有滚动条实例,说明实际内容宽度超出容器宽度,需要默认显示阴影区域 if (!scrollState.x && (_scrollbarRef$value2 = scrollbarRef.value) !== null && _scrollbarRef$value2 !== void 0 && _scrollbarRef$value2.containerRef) { scrollState.x = 'left'; } else if (scrollState.x && !((_scrollbarRef$value3 = scrollbarRef.value) !== null && _scrollbarRef$value3 !== void 0 && _scrollbarRef$value3.containerRef)) { scrollState.x = ''; } }); const headerWrapperClass = computed(() => { const arr = [`${prefixCls}-header-wrapper`]; if (scrollState.x) { arr.push(`is-scrolling-x-${scrollState.x}`); } return arr; }); /** * HeaderTable 不使用 Scrollbar * 因此需要处理 left, right, none 三种情况下的滚动内阴影 * both 的情况由 cell 绘制阴影 */ const headerShadowVisible = computed(() => { if (columnsFixed.value === 'both') { return { left: false, right: false }; } if (columnsFixed.value === 'none') { return { left: ['left', 'middle'].includes(scrollState.x), right: ['right', 'middle'].includes(scrollState.x) }; } let left = false; let right = false; if (columnsFixed.value === 'left') { left = ['left', 'middle'].includes(scrollState.x); } else if (columnsFixed.value === 'right') { right = ['right', 'middle'].includes(scrollState.x); } return { left, right }; }); const bodyWrapperClass = computed(() => { const arr = [`${prefixCls}-body-wrapper`]; if (scrollState.x) { arr.push(`is-scrolling-x-${scrollState.x}`); } /** * BodyTable 使用 Scrollbar * 仅处理单侧有固定列的情况 * none 的情况由 Scrollbar 绘制阴影 * both 的情况由 cell 绘制阴影 */ if (['left', 'right'].includes(columnsFixed.value)) { arr.push(`columns-fixed-${columnsFixed.value}`); } return arr; }); const bodyWrapperStyle = computed(() => { const style = {}; if (layout.isScrollY.value) { style.height = `${layout.bodyHeight.value}px`; } return style; }); const headerStyle = computed(() => { if (isWidthAuto.value) { return { minWidth: '100%' }; } const style = { width: `${layout.bodyWidth.value}px` }; return style; }); const bodyStyle = computed(() => { if (isWidthAuto.value) { return { minWidth: '100%' }; } const style = { width: `${layout.bodyWidth.value}px` }; return style; }); const getRowClassName = _ref2 => { let { row, rowIndex } = _ref2; const classList = [`${prefixCls}-row`]; const rowClassName = props.rowClassName; if (expandColumn.value) { classList.push(isExpandOpened({ row }) && 'is-opened'); } classList.push(typeof rowClassName === 'function' ? rowClassName({ row, rowIndex }) : rowClassName); if (props.striped && rowIndex % 2 === 1) { classList.push('is-striped'); } return classList.filter(Boolean); }; const getRowStyle = _ref3 => { let { row, rowIndex } = _ref3; const rowStyle = props.rowStyle; if (isPlainObject(rowStyle)) { return rowStyle; } if (isFunction(rowStyle)) { return rowStyle({ row, rowIndex }); } }; const getCellClass = _ref4 => { let { column, columns } = _ref4; const arr = [`${prefixCls}-cell`, column.id]; // 兼容多级表头的情况 const columnIndex = columns.findIndex(item => item.id === column.id); if (layout.isScrollX.value && column.fixedLeft) { var _columns; arr.push(`${prefixCls}-fixed-left`); if (!((_columns = columns[columnIndex + 1]) !== null && _columns !== void 0 && _columns.fixedLeft)) { arr.push('is-last'); } } if (layout.isScrollX.value && column.fixedRight) { var _columns2; arr.push(`${prefixCls}-fixed-right`); if (!((_columns2 = columns[columnIndex - 1]) !== null && _columns2 !== void 0 && _columns2.fixedRight)) { arr.push('is-first'); } } return arr; }; const getCustomCellClass = _ref5 => { let { row, column, rowIndex, columnIndex } = _ref5; const colClassName = column.props.colClassName; const cellValue = getCellValue(row, column); return [typeof colClassName === 'function' ? colClassName({ row, column, rowIndex, columnIndex, cellValue }) : colClassName]; }; const getCellStyle = _ref6 => { let { column, columns, row } = _ref6; // 兼容多级表头的情况 const columnIndex = columns.findIndex(item => item.id === column.id); const align = column.props.align; const alignStyle = { 'text-align': !row && column.colSpan > 1 ? 'center' : align }; const fixedStyle = {}; if (column.fixedLeft && layout.isScrollX.value) { const leftColumns = columns.slice(0, columnIndex); const width = leftColumns.reduce((accumulator, currentValue) => { var _layout$widthMap$valu, _layout$widthMap$valu2; const width = (_layout$widthMap$valu = layout.widthMap.value[currentValue.id]) === null || _layout$widthMap$valu === void 0 ? void 0 : _layout$widthMap$valu.width; const minWidth = (_layout$widthMap$valu2 = layout.widthMap.value[currentValue.id]) === null || _layout$widthMap$valu2 === void 0 ? void 0 : _layout$widthMap$valu2.minWidth; return (width || minWidth) + accumulator; }, 0); fixedStyle.left = `${width}px`; } else if (column.fixedRight && layout.isScrollX.value) { const rightColumns = columns.slice(columnIndex + 1); const width = rightColumns.reduceRight((accumulator, currentValue) => { var _layout$widthMap$valu3, _layout$widthMap$valu4; const width = (_layout$widthMap$valu3 = layout.widthMap.value[currentValue.id]) === null || _layout$widthMap$valu3 === void 0 ? void 0 : _layout$widthMap$valu3.width; const minWidth = (_layout$widthMap$valu4 = layout.widthMap.value[currentValue.id]) === null || _layout$widthMap$valu4 === void 0 ? void 0 : _layout$widthMap$valu4.minWidth; return (width || minWidth) + accumulator; }, 0); fixedStyle.right = `${width}px`; } return _objectSpread(_objectSpread({}, alignStyle), fixedStyle); }; const getCustomCellStyle = _ref7 => { let { row, column, rowIndex, columnIndex } = _ref7; const cellValue = getCellValue(row, column); const colStyle = column.props.colStyle; let extraStyle = {}; // row 为空,则是表头,表头不处理 colStyle if (row) { if (isPlainObject(colStyle)) { extraStyle = colStyle; } if (isFunction(colStyle)) { extraStyle = colStyle({ row, column, rowIndex, columnIndex, cellValue }); } } return extraStyle; }; const getCellSpan = _ref8 => { let { row, column, rowIndex, columnIndex } = _ref8; let rowspan = '1'; let colspan = '1'; if (isFunction(props.spanMethod)) { const result = props.spanMethod({ row, column, rowIndex, columnIndex }); if (isPlainObject(result)) { rowspan = result.rowspan; colspan = result.colspan; } } return { rowspan, colspan }; }; // 更新 scrollState,根据 bodyWrapper 或 headerWrapper 的尺寸位置信息 const updateScrollState = _ref9 => { let { scrollLeft, offsetWidth, scrollWidth } = _ref9; const maxScrollLeftPosition = scrollWidth - offsetWidth - 1; if (scrollLeft >= maxScrollLeftPosition) { scrollState.x = 'right'; } else if (scrollLeft === 0) { scrollState.x = 'left'; } else { scrollState.x = 'middle'; } }; // 边界场景:重置滚动状态 watch([() => props.height, () => showData.value.length], (_ref10, _ref11) => { let [nextHeight, nextDataLength] = _ref10; let [prevHeight, prevDataLength] = _ref11; if (!props.showHeader) { return; } const resetScrolling = function () { let resetBodyTable = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true; // BodyTable if (resetBodyTable && scrollbarRef.value && scrollbarRef.value.containerRef) { scrollbarRef.value.containerRef.scrollLeft = 0; } // HeaderTable if (headerWrapperRef.value) { headerWrapperRef.value.scrollLeft = 0; } // updateScrollState scrollState.x = 'left'; }; if ( // <BodyTable> -> <NoData> prevDataLength !== 0 && nextDataLength === 0) { resetScrolling(false); } else if ( // <NoData> -> <BodyTable> prevDataLength === 0 && nextDataLength !== 0) { resetScrolling(); } else if ( // 不固定表头 -> 固定表头 isUndefined(prevHeight) && !isUndefined(nextHeight)) { resetScrolling(); } }); // BodyTable 滚动后,同步 HeaderTable(可能不存在) 的 scrollLeft const syncPosition = throttle(e => { const $bodyWrapper = e.target; if (!$bodyWrapper) { return; } const { scrollLeft, offsetWidth, scrollWidth } = $bodyWrapper; const $headerWrapper = headerWrapperRef.value; if ($headerWrapper) { $headerWrapper.scrollLeft = scrollLeft; } updateScrollState({ scrollLeft, offsetWidth, scrollWidth }); }, 10); const handleHeaderMousewheel = e => { const { deltaX, deltaY } = e; if (Math.abs(deltaX) >= Math.abs(deltaY)) { e.preventDefault(); /** * 没有数据时, * bodyWrapper 的 offsetWidth === scrollWidth,此时设置 scrollLeft 不生效 * 无法通过 bodyWrapper 的 scroll 事件回调触发 syncPosition 以更新 headerWrapper 的 scrollLeft * 注意,headerWrapper 的 overflow 为 hidden,可以响应 scroll 事件但是元素无法滚动 */ if (showData.value.length === 0 && headerWrapperRef.value) { headerWrapperRef.value.scrollLeft += deltaX; const { scrollLeft, offsetWidth, scrollWidth } = headerWrapperRef.value; updateScrollState({ scrollLeft, offsetWidth, scrollWidth }); return; } /** * 有数据时, * 仍按照原逻辑,先更新 bodyWrapper 的 scrollLeft,再 syncPosition */ if (scrollbarRef.value && scrollbarRef.value.containerRef) { scrollbarRef.value.containerRef.scrollLeft += deltaX; } } }; return { prefixCls, wrapperRef, headerWrapperRef, bodyWrapperRef, layout, wrapperClass, bodyWrapperStyle, headerStyle, bodyStyle, getCellSpan, getRowClassName, getRowStyle, getCellClass, getCustomCellClass, getCellStyle, getCustomCellStyle, syncPosition, headerShadowVisible, handleHeaderMousewheel, headerWrapperClass, bodyWrapperClass, scrollbarRef, bodyTableRef }; }; export { useTableStyle as default };