UNPKG

@fesjs/fes-design

Version:
222 lines (216 loc) 7.61 kB
import { ref, computed, onDeactivated, onActivated, watch, nextTick } from 'vue'; import { isUndefined, isEqual } from 'lodash-es'; import useResize from '../_util/use/useResize'; /** * 更新列的宽度 * 列最小宽度为80,如果设定了width则使用设定的width作为宽度,没有设定宽度的列平分剩余的宽度(容器的宽度减去已使用的宽度) */ function useTableLayout(_ref) { let { props, wrapperRef, headerWrapperRef, bodyWrapperRef, bodyTableRef, columns, showData } = _ref; const bodyWidth = ref(0); const widthMap = ref({}); const isScrollX = ref(false); const isScrollY = ref(false); const bodyHeight = ref(0); // 兼容 windows 浏览器滚动条导致高度有小数的场景 const propHeight = computed(() => Math.floor(props.height)); const isWidthAuto = computed(() => { return isUndefined(props.height) && props.layout === 'auto'; }); const isWatchX = ref(true); const min = 100; const computeY = () => { // 第一次渲染时会出现 bodyWrapperHeight = 0,必须再nextTick nextTick(() => { // 需要在宽度分配完,重新渲染后,此时table已经按照期望正常渲染,此时的高度才是最终高度 const $wrapper = wrapperRef.value; const $bodyWrapper = bodyWrapperRef.value; if ($wrapper && $bodyWrapper) { if (propHeight.value) { const $headerWrapper = props.showHeader ? headerWrapperRef.value : { offsetHeight: 0 }; const headerWrapperHeight = $headerWrapper.offsetHeight; let remainBodyHeight = propHeight.value - headerWrapperHeight; if (props.bordered) { remainBodyHeight -= 2; } const bodyWrapperHeight = $bodyWrapper.offsetHeight; bodyHeight.value = remainBodyHeight; // 渲染后重新执行,会出现 remainBodyHeight === bodyWrapperHeight 的情况 if (remainBodyHeight <= bodyWrapperHeight) { isScrollY.value = true; } else { isScrollY.value = false; } } else { isScrollY.value = false; } } }); }; const computeX = () => { if (!isWatchX.value) { return; } const $wrapper = wrapperRef.value; if (!$wrapper) { return; } if (isWidthAuto.value) { columns.value.forEach(column => { const widthObj = { id: column.id }; const width = column.props.width; const minWidth = column.props.minWidth; if (width) { widthObj.width = width; } else if (minWidth) { widthObj.minWidth = minWidth; } else if (column.props.type === 'selection' || column.props.type === 'expand') { widthObj.minWidth = min; } if (!isEqual(widthMap.value[column.id], widthObj)) { widthMap.value[column.id] = widthObj; } }); const $bodyTable = bodyTableRef.value; if (!$bodyTable) { return; } isScrollX.value = $bodyTable.offsetWidth > (props.bordered ? $wrapper.offsetWidth - 2 : $wrapper.offsetWidth); } else { const _wrapperWidth = $wrapper.offsetWidth; const wrapperWidth = props.bordered ? _wrapperWidth - 2 : _wrapperWidth; let bodyMinWidth = 0; const newWidthList = {}; columns.value.forEach(column => { const widthObj = { id: column.id, origin: {} }; const width = column.props.width; const minWidth = column.props.minWidth; if (width || minWidth) { // 用户设置的宽度优先级最高 widthObj.origin = { minWidth, width }; } else if (column.props.type === 'selection' || column.props.type === 'expand') { widthObj.origin = { width: min }; } else { widthObj.origin = { minWidth: min }; } newWidthList[column.id] = widthObj; }); Object.values(newWidthList).forEach(widthObj => { var _ref2, _widthObj$origin$widt; bodyMinWidth += (_ref2 = (_widthObj$origin$widt = widthObj.origin.width) !== null && _widthObj$origin$widt !== void 0 ? _widthObj$origin$widt : widthObj.origin.minWidth) !== null && _ref2 !== void 0 ? _ref2 : min; }); if (bodyMinWidth < wrapperWidth) { isScrollX.value = false; bodyWidth.value = wrapperWidth; const additionalWidth = wrapperWidth - bodyMinWidth; const hasMinItems = Object.values(newWidthList).filter(item => !item.origin.width); const hasWidthItems = Object.values(newWidthList).filter(item => item.origin.width); let addedWidth = 0; hasMinItems.forEach((item, index) => { const origin = newWidthList[item.id].origin; if (index !== hasMinItems.length - 1) { const widthObj = { id: item.id, width: origin.minWidth + Math.ceil(additionalWidth / hasMinItems.length) }; if (!isEqual(widthObj, widthMap.value[item.id])) { widthMap.value[item.id] = widthObj; } addedWidth += Math.ceil(additionalWidth / hasMinItems.length); } else { const widthObj = { id: item.id, width: origin.minWidth + additionalWidth - addedWidth }; if (!isEqual(widthObj, widthMap.value[item.id])) { widthMap.value[item.id] = widthObj; } } }); hasWidthItems.forEach(item => { const origin = newWidthList[item.id].origin; const widthObj = { id: item.id, width: origin.width }; if (!isEqual(widthObj, widthMap.value[item.id])) { widthMap.value[item.id] = widthObj; } }); } else { isScrollX.value = true; bodyWidth.value = bodyMinWidth; columns.value.forEach(column => { var _origin$width; const origin = newWidthList[column.id].origin; const widthObj = { id: column.id, width: (_origin$width = origin.width) !== null && _origin$width !== void 0 ? _origin$width : origin.minWidth }; if (!isEqual(widthObj, widthMap.value[column.id])) { widthMap.value[column.id] = widthObj; } }); } } }; const watchResizeDisableRef = ref(false); onDeactivated(() => { watchResizeDisableRef.value = true; }); onActivated(() => { watchResizeDisableRef.value = false; }); // 检测Table宽度和高度变化,计算内容宽度和高度 useResize(wrapperRef, () => { computeX(); computeY(); }, watchResizeDisableRef); useResize(bodyTableRef, () => { computeX(); }, computed(() => { return watchResizeDisableRef.value || !isWidthAuto.value; })); watch([columns, wrapperRef, () => props.bordered, isWidthAuto], () => { computeX(); }); watch([widthMap, propHeight, () => props.showHeader, () => props.bordered, wrapperRef, bodyWrapperRef, headerWrapperRef], () => { nextTick(computeY); }); // 数据变化的时候,要重置滚动的变量,不然数据不足的时候还是会用之前旧的 bodyWrapperRef watch(() => showData.value.length, () => { isScrollY.value = false; nextTick(computeY); }); return { widthMap, bodyWidth, bodyHeight, isScrollX, isScrollY, isWatchX }; } export { useTableLayout as default };