vue3+elementuiplus的table表格动态高度

table表格流体高度

1、前提

了解自定义指令、hooks

2、核心思路

通过自定义指令(new ResizeObserver)监听表格变化,然后通过hooks去更新表格高度。

3、核心代码

src/directives/resize.ts

TypeScript 复制代码
// import { debounce } from '@/utils';

import { type Directive } from "vue";

const resizeDirective: Directive = {
  mounted(el, binding) {
    // update 要高效,否则会导致 ResizeObserver loop completed with undelivered notifications.
    // 这里通过 setTimeout 延迟实际更新到下个 tick
    let update = (entry: ResizeObserverEntry) => {
      setTimeout(() => {
        binding.value(entry);
      }, 0);
    };
    if (binding.arg) {
      try {
        let delay = Number.parseInt(binding.arg);
        console.log(delay);
        // update = debounce(binding.value, delay);
      } catch (error) {
        console.log(error);
      }
    }
    // 创建 ResizeObserver 实例
    const resizeObserver = (el.__resizeObserver__ = new ResizeObserver((entries) => {
      // 当目标元素的大小发生变化时,执行回调函数
      update(entries[0]);
    }));
    // 开始监听目标元素的大小变化
    resizeObserver.observe(el);
  },
  unmounted(el) {
    el.__resizeObserver__.disconnect();
  },
};

export default resizeDirective;

src/hooks/useTableConfig.ts

TypeScript 复制代码
import { type TableInstance } from "element-plus";

/** 获取表格的基本配置 */
export const useTableConfig = <T>(padding: number = 20) => {
  const tableLoading = ref<boolean>(false);
  const pageData = ref<T[]>([]);
  const total = ref<number>(0);
  const tableRef = ref<TableInstance | null>(null);
  const selectedTableIds = ref<string[]>([]);

  /**表格高度 */
  const tableFluidHeight = ref<number>(0);

  const tableResize = (rect: DOMRectReadOnly) => {
    tableFluidHeight.value = rect.height - padding * 2;
  };

  return {
    tableLoading,
    pageData,
    total,
    tableRef,
    selectedTableIds,
    tableFluidHeight,
    tableResize,
  };
};

这里padding:20的原因是

src/components/BaseTableSearchContainer/index.vue

html 复制代码
<template>
  <div class="flex flex-col h-full">
    <slot name="search" />
    <div ref="centerRef" v-resize="onResize" class="flex-1 overflow-auto">
      <div :class="centerClass" class="p-20px bg-light-50">
        <slot name="table" />
      </div>
    </div>
    <div style="background: white">
      <slot name="pagination" />
    </div>
  </div>
</template>

<script setup lang="ts">
import { useTemplateRef } from "vue";
defineProps({ centerClass: { type: String, default: "" } });
const emit = defineEmits(["sizeChanged"]);

const centerRef = useTemplateRef<HTMLElement>("centerRef");
const onResize = (e: ResizeObserverEntry) => {
  // console.log("resize", e, centerRef.value, centerRef.value?.getBoundingClientRect().height);
  emit("sizeChanged", e.contentRect);
};
</script>

<style lang="scss" scoped></style>

使用:

html 复制代码
<template>
  <div class="app-container">
    <BaseTableSearchContainer @size-changed="tableResize">
      <template #search>
        <TBSearchContainer :is-show-toggle="true">
          <template #left> </template>
          <template #right> </template>
        </TBSearchContainer>
      </template>
      <template #table>
        <el-table
          ref="tableRef"
          v-loading="tableLoading"
          :data="pageData"
          highlight-current-row
          row-key="Id"
          border
          :height="tableFluidHeight"
          style="text-align: center; flex: 1"
          @select="handleTableSelect"
          @select-all="handleTableSelect"
        >
        </el-table>
      </template>
      <template #pagination>
        <Pagination
          v-if="total > 0"
          v-model:total="total"
          v-model:page="queryParams.pageIndex"
          v-model:limit="queryParams.pageSize"
          @pagination="handleGetTableList"
        />
      </template>
    </BaseTableSearchContainer>
  </div>
</template>

<script setup lang="ts">
const {
  tableLoading,
  pageData,
  total,
  tableRef,
  tableFluidHeight,
  tableResize,
} = useTableConfig<MoItemPackItem>();
</script>

<style scoped lang="scss"></style>
相关推荐
鱼樱前端42 分钟前
uni-app快速入门章法(二)
前端·uni-app
silent_missile1 小时前
vue3父组件和子组件之间传递数据
前端·javascript·vue.js
克里斯蒂亚诺更新2 小时前
微信小程序app.js中每30秒调用一次wx.getLocation
javascript·微信小程序·小程序
IT_陈寒2 小时前
Vue 3.4 实战:这7个Composition API技巧让我的开发效率飙升50%
前端·人工智能·后端
鄃鳕2 小时前
C++坑系列,C++ std::atomic 拷贝构造函数问题分析与解决方案
java·javascript·c++
JIngJaneIL3 小时前
图书馆自习室|基于SSM的图书馆自习室座位预约小程序设计与实现(源码+数据库+文档)
java·数据库·vue.js·spring boot·论文·毕设·图书馆自习室
少年阿闯~~3 小时前
HTML——1px问题
前端·html
Never_Satisfied3 小时前
在JavaScript / HTML中,实现`<iframe>` 自适应高度
开发语言·javascript·html
Mike_jia3 小时前
SafeLine:自托管WAF颠覆者!一键部署守护Web安全的雷池防线
前端
brzhang4 小时前
把网页的“好句子”都装进侧边栏:我做了个叫 Markbox 的收藏器,开源!
前端·后端·架构