vue3.0中实现动态计算表格高度问题的解决方案

1,926 阅读1分钟

实现表格动态高度的滚动,技术基于Element plus + vue3.0 + vite + ts

方案一:

方案一关键实现代码

<div ref="container">
    <el-form id="queryForm"></el-form>
    <el-table :height="tableHeight"></el-table>
</div>
<script setup lang="ts">
import { reactive,ref,toRefs } from 'vue';
const state = reactive({
    tableHeight:500,
    
})
const { tableHeight } toRefs
// 获取表格高度
function getTableHeight() {
  let queryFormHeight = document.getElementById('queryForm')?.clientHeight as number;//搜索重置Form的高度
  let containerHeight = container.value?.clientHeight as number;//局部路由视图容器高度
  state.tableHeight = containerHeight - queryFormHeight - 24 - 68 - 40;//路由视图高度-Form高度-padding-分页-新建修改删除等的高度
}
</script>

咋一看这样的实现方案有点low,不通用,每个文件考来考去的,看下面一种,方案二

实现效果

image.png

方案二:

第一步,封装一个通用全局组件:

<template>
  <div class="app-operation-brand" ref="refBrand">
    <slot></slot>
  </div>
</template>

<script lang='ts'>
// 添加名称用于缓存页面数据
export default { name: 'AppOperationBrand'}
</script>
<script lang='ts' setup>
// 动态计算数据显示区高度
import { ref } from 'vue';
import refHeightHooks from '@/hooks/refHeight';

const refBrand = ref<HTMLDivElement | null>(null);

const emits = defineEmits(['getTabHeightFn'])
const props = defineProps({
  pagination: {
    type: Boolean,
    required: false,
    default: false
  },
  elNextHeight: {//其他dom的时候,计算好了高度然后传进来
    type: Number,
    required: false,
    default: 0
  }
})
refHeightHooks({el: refBrand, pagination: props.pagination,elNextHeight:props.elNextHeight}).then(res => {

  if (props.pagination) {
    const { baseHeight, optionHeight, pagHeight } = res;
    emits('getTabHeightFn', {baseHeight, optionHeight, pagHeight});
    //无分页高度表体高度(不含菜单栏,边框,顶部),Form or 其它元素高度,有分页表体高度
  } else {
    const { baseHeight, optionHeight } = res;
    emits('getTabHeightFn', { baseHeight, optionHeight });
    //无分页高度表体高度(不含菜单栏,边框,顶部),Form or 其它元素高度
  }
});
</script>

第二部,封装全局组件用到的hooks中方法refHeightHooks

/**
 * 用于计算数据显示区域可滚动区间高度
 */
/**
 * 用于计算数据显示区域可滚动区间高度
 */
import { onMounted } from 'vue'
type Options = {
  el: any, // 只有一个dom的时候
  pagination: boolean, // 是否有分页组件
  elNextHeight?: number // 其他dom的时候,计算好了高度然后传进来
}
export default function (option: Options): Promise<any> {
  return new Promise((resolve) => {
    onMounted(() => {
      let baseHeight = 500; // 默认高度
      const optionHeight = option.el.value.offsetHeight;
      baseHeight = document.body.offsetHeight - optionHeight - 184; // 顶部高度 + 菜单栏高度 + 边框 = 204
      
      baseHeight = option.elNextHeight ? baseHeight - option.elNextHeight : baseHeight;
      let pagHeight = baseHeight;
      if (option.pagination) {
        pagHeight = baseHeight - 68; // 分页组件默认68高度
        return resolve({ baseHeight, optionHeight, pagHeight })//无分页高度表体高度(不含菜单栏,边框,顶部),Form or 其它元素高度,有分页表体高度
      } else {
        return resolve({ baseHeight, optionHeight })
      }
    })
  })
}

第三步,挂载到全局,在main.js中如下操作:

//引入
import AppOperationBrand from '@/components/AppOperationBrand/index.vue'
// 注册全局组件
app
  .component('AppOperationBrand', AppOperationBrand)
  .mount('#app');

第四步,在界面的Form上包裹上这么一层组件

<template>
    <app-operation-brand @getTabHeightFn="getTabHeightFn" :pagination="true" :elNextHeight="24">
          <el-form ref="queryRef">
          </el-form>
    </app-operation-brand>
    <el-table :max-height="pHeight"></el-table>
<template>
<script lang="ts" setup>
import { ref } from 'vue'
// 计算数据列表高度
const pHeight = ref(0);
function getTabHeightFn(data: heightData) {
  pHeight.value = data.baseHeight as number;
}

实现效果如下

image.png