Skip to content

基于组合函数计算表格滚动高度

版本

  • vue:3.4.27
  • vueuse/core:14.1.0
  • ant-design-vue:4.2.5
  • mitt:3.0.1

源码

组合函数useComputeTableHeight

javascript
import { ref, onMounted, onUnmounted, watch, nextTick, computed } from 'vue';
import { useElementBounding, useElementSize, useRafFn } from '@vueuse/core';
import emits from '/@/utils/emits';

// 按照惯例,组合式函数名以“use”开头
export function useComputeTableHeight() {

  const subtractHeight = ref(32); // 表格与footer元素的距离,这个值默认导出,可以修改。

  const appHeight = ref(window.innerHeight); // 整个显示区域的高度

  const tableTop = ref(0); // 表格距离顶部距离

  const tableHeaderHeight = ref(0); // 表格表头高度

  const footerHeight = ref(0); // 底部分页栏目高度

  const tableRef = ref();

  const tableHight = computed(() => {
    // 整个显示区域的高度 - 表格距离顶部距离 - 表格表头高度 - 底部分页栏目高度 - 表格需要减去的高度
    return appHeight.value - tableTop.value - tableHeaderHeight.value - footerHeight.value - subtractHeight.value;
  });

  // 一个组合式函数也可以挂靠在所属组件的生命周期上
  // 来启动和卸载副作用
  onMounted(() => {
    initAppHeight();

    initTableTop();

    // 如果表头的宽度可以调整,需要监听表头的高度
    initTableHeader();

    // footer元素的高度,可以放分页组件等,根据业务要求来
    initFooterHeight();
  });

  const initAppHeight = () => {
    const appEl = document.getElementById('app');

    if (appEl) {
      const { height } = useElementSize(appEl as any);
      watch(
        height,
        (newVal: number, oldVal: number) => {
          // console.log('app元素的高度:', newVal);
          appHeight.value = newVal;
        },
        {
          immediate: true,
          deep: true,
        }
      );
    }
  };

  const initTableTop = () => {
    const tableEl = document.getElementById('xy-ant-table');

    if (tableEl) {
      const { top, update } = useElementBounding(tableEl as any, {
        windowResize: true, // 窗口大小变化时更新
        windowScroll: true, // 滚动时更新
        immediate: true, // 立即计算
      });
      // 如果表格的高度宽度没有变化的话,top不可以变化,所以需要用到update来更新
      // 举例:如果表格上方存在的筛选区域可以展开收起,展开收起因为不涉及表格宽度高度变化,所以表格的top不会变化
      emits.on('updateTableTop', () => {
        update();
      });
      watch(
        top,
        (newVal: number, oldVal: number) => {
          console.log('表格距离顶部:', newVal);
          tableTop.value = newVal;
        },
        {
          immediate: true,
          deep: true,
        }
      );
    }
  };

  const initTableHeader = () => {
    const tableHeaderEl = document.querySelector('#my-ant-table .ant-table-header');

    if (tableHeaderEl) {
      const { height } = useElementSize(tableHeaderEl as any);
      watch(
        height,
        (newVal: number, oldVal: number) => {
          console.log('表格表头的高度:', newVal);
          tableHeaderHeight.value = newVal;
        },
        {
          immediate: true,
          deep: true,
        }
      );
    }
  };

  const initFooterHeight = () => {
    const footerEl = document.querySelector('.smart-query-table-page');

    if (footerEl) {
      const { height } = useElementSize(footerEl as any);
      watch(
        height,
        (newVal: number, oldVal: number) => {
          // console.log('底部的高度:', newVal);
          footerHeight.value = newVal;
        },
        {
          immediate: true,
        }
      );
    }
  };

  onUnmounted(() => {
  });

  // 通过返回值暴露所管理的状态
  return { tableHight, subtractHeight, tableRef };
}

emits文件

javascript
import mitt, { Emitter } from 'mitt'

export default mitt() as Emitter<any>

使用

vue
import { useComputeTableHeight } from '/@/composables/useComputeTableHeight';

const { tableHight } = useComputeTableHeight();

<a-table id="my-ant-table" size="small">
</a-table>