6348eb5a创建于 2024年4月16日历史提交
import { computed, ref, watchEffect, watch } from 'vue';
import type { ComputedRef, CSSProperties, Ref } from 'vue';
import { Column } from '../components/column/column-types';
import { ITable, DefaultRow, TableProps, UseTable, UseFixedColumn, UseTableLayout } from '../table-types';
import { useNamespace } from '../../../shared/hooks/use-namespace';
import { TableStore } from '../store/store-types';

export function useTable(props: TableProps, tableWidth: Ref): UseTable {
  const ns = useNamespace('table');
  const classes = computed(() => ({
    [ns.e('view')]: true,
    [ns.m('striped')]: props.striped,
    [ns.m('header-bg')]: props.headerBg,
    [ns.m('layout-auto')]: props.tableLayout === 'auto',
    [ns.m(`${props.size}`)]: true,
    [ns.m(`${props.borderType}`)]: Boolean(props.borderType),
  }));
  const styles: ComputedRef<CSSProperties> = computed(() => ({
    maxHeight: props.maxHeight,
    maxWidth: props.maxWidth,
    height: props.tableHeight,
    width: props.tableWidth,
  }));
  return { classes, styles };
}

export const useFixedColumn = (column: Ref<Column>): UseFixedColumn => {
  const ns = useNamespace('table');
  const stickyClass = computed(() => ({
    [ns.e('checkable-cell')]: column.value.type === 'checkable',
    [ns.m('sticky-cell')]: Boolean(column.value.fixedLeft) || Boolean(column.value.fixedRight),
    left: Boolean(column.value.fixedLeft),
    right: Boolean(column.value.fixedRight),
    [`is-${column.value.align}`]: true,
  }));

  const stickyStyle = computed(() => ({
    left: column.value.fixedLeft,
    right: column.value.fixedRight,
  }));

  return { stickyClass, stickyStyle };
};

export function useTableLayout(table: ITable<DefaultRow>): UseTableLayout {
  const tableWidth = ref();

  const updateColgroupWidth = () => {
    const cols = (table?.vnode?.el?.querySelectorAll('colgroup > col') || []) as HTMLElement[];
    if (!cols.length) {
      return;
    }
    const flatColumns = table.store.states.flatColumns;
    const columnMap: Record<string, Column> = {};
    flatColumns.value.forEach((column: Column) => {
      columnMap[column.id] = column;
    });
    for (let i = 0, len = cols.length; i < len; i++) {
      const col = cols[i];
      const columnId = col.getAttribute('column-id') as string;
      const column = columnMap[columnId];
      if (column) {
        col.setAttribute('width', column.realWidth as string);
      }
    }
  };

  const updateColumnWidth = () => {
    const tableClientWidth = table?.vnode?.el?.clientWidth;
    let tableMinWidth = 0;

    const flatColumns = table.store.states.flatColumns;
    const flexColumns = flatColumns.value.filter((column) => typeof column.width !== 'number');
    if (flexColumns.length) {
      flatColumns.value.forEach((column) => {
        tableMinWidth += Number(column.width || 80);
      });
      if (tableMinWidth <= tableClientWidth) {
        const totalFlexWidth = tableClientWidth - tableMinWidth;
        if (flexColumns.length === 1) {
          flexColumns[0].realWidth = Number(flexColumns[0].width || 80) + totalFlexWidth;
        } else {
          const allFlexColumnWidth = flexColumns.reduce((pre, column) => pre + Number(column.width || 80), 0);
          const flexWidthPercent = totalFlexWidth / allFlexColumnWidth;
          let exceptFistWidth = 0;
          flexColumns.forEach((column, index) => {
            if (index === 0) {
              return;
            }
            const perFlexWidth = Math.floor(Number(column.width || 80) * flexWidthPercent);
            exceptFistWidth += perFlexWidth;
            column.realWidth = Number(column.width || 80) + perFlexWidth;
          });
          flexColumns[0].realWidth = Number(flexColumns[0].width || 80) + totalFlexWidth - exceptFistWidth;
        }
      } else {
        flexColumns.forEach((column) => {
          column.realWidth = Number(column.width || 80);
        });
      }
      tableWidth.value = Math.max(tableMinWidth, tableClientWidth);
    } else {
      flatColumns.value.forEach((column) => {
        column.realWidth = column.width || 80;
        tableMinWidth += Number(column.realWidth);
      });
      tableWidth.value = tableMinWidth;
    }
    updateColgroupWidth();
  };

  return { tableWidth, updateColumnWidth };
}

export function useTableWatcher(props: TableProps, store: TableStore): void {
  watchEffect(() => {
    if (props.expandRowKeys) {
      store.setExpandRows(props.expandRowKeys);
    }
  });
  watch(
    () => props.data,
    () => {
      store.updateRows();
      store.updateColumns();
    },
    { deep: true }
  );
}