@fesjs/fes-design
Version:
fes-design for PC
441 lines (432 loc) • 13.7 kB
JavaScript
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 };