|
@@ -74,6 +74,12 @@ export function useTableScroll(
|
|
|
let footerEl: HTMLElement | null;
|
|
|
let bodyEl: HTMLElement | null;
|
|
|
|
|
|
+ /**
|
|
|
+ * table wrapper padding 的高度
|
|
|
+ * @description 来自于 .vben-basic-table .ant-table-wrapper
|
|
|
+ */
|
|
|
+ const tableWrapperPadding = 6;
|
|
|
+
|
|
|
function handleScrollBar(bodyEl: HTMLElement, tableEl: Element) {
|
|
|
const hasScrollBarY = bodyEl.scrollHeight > bodyEl.clientHeight;
|
|
|
const hasScrollBarX = bodyEl.scrollWidth > bodyEl.clientWidth;
|
|
@@ -93,21 +99,33 @@ export function useTableScroll(
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * 计算分页器高度
|
|
|
+ * @param tableEl table element
|
|
|
+ * @returns number
|
|
|
+ */
|
|
|
function caclPaginationHeight(tableEl: Element): number {
|
|
|
const { pagination } = unref(propsRef);
|
|
|
- // Pager height
|
|
|
- let paginationHeight = 2;
|
|
|
+
|
|
|
+ let paginationHeight = 0;
|
|
|
if (!isBoolean(pagination)) {
|
|
|
- paginationEl = tableEl.querySelector('.ant-pagination') as HTMLElement;
|
|
|
+ // 从 Dom 获取
|
|
|
+ if (!paginationEl) {
|
|
|
+ paginationEl = tableEl.querySelector('.ant-pagination') as HTMLElement;
|
|
|
+ }
|
|
|
if (paginationEl) {
|
|
|
+ // 分页 margin-top
|
|
|
+ const paginationElMarginTop = parseInt(getComputedStyle(paginationEl).marginTop);
|
|
|
+ // 分页高度
|
|
|
const offsetHeight = paginationEl.offsetHeight;
|
|
|
- paginationHeight += offsetHeight || 0;
|
|
|
+ paginationHeight = offsetHeight + paginationElMarginTop;
|
|
|
} else {
|
|
|
- // TODO First fix 24
|
|
|
- paginationHeight += 24;
|
|
|
+ // 找不到分页组件,缺省给予默认分页 margin-top + 高度
|
|
|
+ paginationHeight = 10 + 24;
|
|
|
}
|
|
|
} else {
|
|
|
- paginationHeight = -8;
|
|
|
+ // 不显示分页,pagination 为 false 的时候
|
|
|
+ paginationHeight = 0;
|
|
|
}
|
|
|
return paginationHeight;
|
|
|
}
|
|
@@ -134,43 +152,105 @@ export function useTableScroll(
|
|
|
return headerHeight;
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * 计算从表头一直到body底部的总高度
|
|
|
+ * @param tableEl table element
|
|
|
+ * @param headEl table 页头 element
|
|
|
+ * @returns number
|
|
|
+ */
|
|
|
function calcBottomAndPaddingHeight(tableEl: Element, headEl: Element) {
|
|
|
- const { pagination, isCanResizeParent, useSearchForm } = unref(propsRef);
|
|
|
- // Table height from bottom height-custom offset
|
|
|
- let paddingHeight = 30;
|
|
|
+ const { isCanResizeParent } = unref(propsRef);
|
|
|
let bottomIncludeBody = 0;
|
|
|
if (unref(wrapRef) && isCanResizeParent) {
|
|
|
- const tablePadding = 12;
|
|
|
- const formMargin = 16;
|
|
|
- let paginationMargin = 10;
|
|
|
+ // 继承父元素高度
|
|
|
const wrapHeight = unref(wrapRef)?.offsetHeight ?? 0;
|
|
|
|
|
|
let formHeight = unref(formRef)?.$el.offsetHeight ?? 0;
|
|
|
if (formHeight) {
|
|
|
- formHeight += formMargin;
|
|
|
- }
|
|
|
- if (isBoolean(pagination) && !pagination) {
|
|
|
- paginationMargin = 0;
|
|
|
+ // 来自于 .vben-basic-table-form-container .ant-form 以及 .vben-basic-table-form-container
|
|
|
+ formHeight += 16 + 16 * 2;
|
|
|
}
|
|
|
- if (isBoolean(useSearchForm) && !useSearchForm) {
|
|
|
- paddingHeight = 0;
|
|
|
- }
|
|
|
-
|
|
|
- const headerCellHeight =
|
|
|
- (tableEl.querySelector('.ant-table-title') as HTMLElement)?.offsetHeight ?? 0;
|
|
|
|
|
|
- console.log(wrapHeight - formHeight - headerCellHeight - tablePadding - paginationMargin);
|
|
|
- bottomIncludeBody =
|
|
|
- wrapHeight - formHeight - headerCellHeight - tablePadding - paginationMargin;
|
|
|
+ bottomIncludeBody = wrapHeight - tableWrapperPadding - formHeight;
|
|
|
} else {
|
|
|
- // Table height from bottom
|
|
|
+ // 缺省 wrapRef 情况下
|
|
|
bottomIncludeBody = getViewportOffset(headEl).bottomIncludeBody;
|
|
|
}
|
|
|
|
|
|
- return {
|
|
|
- paddingHeight,
|
|
|
- bottomIncludeBody,
|
|
|
- };
|
|
|
+ return bottomIncludeBody;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 计算 table 在 modal 内 modal 所占用的高度
|
|
|
+ * @param tableEl table element
|
|
|
+ * @returns number
|
|
|
+ */
|
|
|
+ function calcModalHeight(tableEl: Element) {
|
|
|
+ // 找一下 table 是否在 modal 内,获得 modal、wrap、footer,并考虑 fullscreen 的情况
|
|
|
+ let modalEl: Nullable<HTMLElement> = null;
|
|
|
+ let modalWrapEl: Nullable<HTMLElement> = null;
|
|
|
+ let modalFooterEl: Nullable<HTMLElement> = null;
|
|
|
+ let modalElIterator: HTMLElement = tableEl.parentElement!;
|
|
|
+ let modalIsFullscreen = false;
|
|
|
+ while (modalElIterator !== document.body) {
|
|
|
+ if (modalElIterator.classList.contains('ant-modal')) {
|
|
|
+ modalEl = modalElIterator;
|
|
|
+ modalWrapEl = modalEl.parentElement;
|
|
|
+ modalFooterEl = modalElIterator.querySelector('.ant-modal-content>.ant-modal-footer');
|
|
|
+ modalIsFullscreen = modalWrapEl?.classList.contains('fullscreen-modal') ?? false;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ modalElIterator = modalElIterator.parentElement!;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (modalEl) {
|
|
|
+ // table 在 modal 内
|
|
|
+
|
|
|
+ // modal top
|
|
|
+ const { top: modalTop = 0 } = modalEl ? getViewportOffset(modalEl) : {};
|
|
|
+
|
|
|
+ // 来自于 .ant-modal,非全屏为 24,全屏为 0
|
|
|
+ const modalBottom = modalIsFullscreen ? 0 : 24;
|
|
|
+
|
|
|
+ // modal footer 高度
|
|
|
+ const modalFooterHeight = modalFooterEl?.offsetHeight ?? 0;
|
|
|
+
|
|
|
+ // modal footer 边距,来自于 .ant-modal .ant-modal-footer
|
|
|
+ const modalFooterMarginTop = modalFooterEl
|
|
|
+ ? modalIsFullscreen
|
|
|
+ ? 0
|
|
|
+ : parseInt(getComputedStyle(modalFooterEl).marginTop)
|
|
|
+ : 0;
|
|
|
+
|
|
|
+ // 来自于 .ant-modal .ant-modal-body > .scrollbar
|
|
|
+ const modalScrollBarHeight = 14;
|
|
|
+
|
|
|
+ return (
|
|
|
+ (modalTop > modalBottom ? modalTop : modalBottom) +
|
|
|
+ modalFooterHeight +
|
|
|
+ modalFooterMarginTop +
|
|
|
+ modalScrollBarHeight
|
|
|
+ );
|
|
|
+ }
|
|
|
+
|
|
|
+ // table 不住 modal 内
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 根据样式返回一些间距高度
|
|
|
+ * @returns number
|
|
|
+ */
|
|
|
+ function getMarginPaddingHeight() {
|
|
|
+ const { isCanResizeParent } = unref(propsRef);
|
|
|
+
|
|
|
+ if (unref(wrapRef) && isCanResizeParent) {
|
|
|
+ // 继承父元素高度
|
|
|
+ return tableWrapperPadding;
|
|
|
+ }
|
|
|
+ return (
|
|
|
+ tableWrapperPadding + 16 // 来自于 .vben-basic-table-form-container 或是 .p-4
|
|
|
+ );
|
|
|
}
|
|
|
|
|
|
async function calcTableHeight() {
|
|
@@ -204,18 +284,29 @@ export function useTableScroll(
|
|
|
const paginationHeight = caclPaginationHeight(tableEl);
|
|
|
const footerHeight = caclFooterHeight(tableEl);
|
|
|
const headerHeight = calcHeaderHeight(headEl);
|
|
|
- const { paddingHeight, bottomIncludeBody } = calcBottomAndPaddingHeight(tableEl, headEl);
|
|
|
+ const bottomIncludeBody = calcBottomAndPaddingHeight(tableEl, headEl);
|
|
|
+
|
|
|
+ const modalHeight = calcModalHeight(tableEl);
|
|
|
|
|
|
- let height =
|
|
|
+ const marginPaddingHeight = getMarginPaddingHeight();
|
|
|
+
|
|
|
+ // Math.floor 宁愿小1px,也不溢出
|
|
|
+ let height = Math.floor(
|
|
|
bottomIncludeBody -
|
|
|
- (resizeHeightOffset || 0) -
|
|
|
- paddingHeight -
|
|
|
- paginationHeight -
|
|
|
- footerHeight -
|
|
|
- headerHeight -
|
|
|
- (getShowFooter.value ? layoutFooterHeight : 0) -
|
|
|
- // 取高度ceil值
|
|
|
- 1;
|
|
|
+ (resizeHeightOffset || 0) -
|
|
|
+ paginationHeight -
|
|
|
+ footerHeight -
|
|
|
+ headerHeight -
|
|
|
+ // 弹窗(如果有)相关高度
|
|
|
+ modalHeight -
|
|
|
+ // 页面 footer 高度(非弹窗的时候)
|
|
|
+ (getShowFooter.value && modalHeight <= 0 ? layoutFooterHeight : 0) -
|
|
|
+ // 样式间距高度
|
|
|
+ marginPaddingHeight -
|
|
|
+ // 预留非整数高度溢出(如实际高度为100.5,offsetHeight 的值为101)
|
|
|
+ 1,
|
|
|
+ );
|
|
|
+
|
|
|
height = (height > maxHeight! ? (maxHeight as number) : height) ?? height;
|
|
|
setHeight(height);
|
|
|
|