动态计算高度

你的理解完全正确!在不重构现有布局代码(不迁移到 Flex)的前提下,监听搜索框高度变化并动态重新计算表格高度,确实是风险最小、改动成本最低的方案。

针对存量代码,我们核心要解决的问题就是:
表格高度 = 总高度(100vh) - Logo高度 - 分页高度 - 间距 - 动态的搜索框高度

在 Vue 3 中,最现代且性能最好的实现方式是使用 ResizeObserver API。它比旧的 window.onresize 强大得多,因为它可以专门监听某个 DOM 元素(搜索框)的尺寸变化。

以下是具体的实现代码:

核心思路

  1. Ref 绑定 :给包裹搜索框的容器打上 ref
  2. 监听变化 :在 onMounted 中启动 ResizeObserver 监听这个容器。
  3. 动态计算 :每当搜索框高度变了,就更新表格的 height 属性。

代码实现

假设你原来的 CSS 是写死的 height: calc(100vh - 200px)(这 200px 通常包含了 Logo、分页和 padding),现在的逻辑变成了:

vue 复制代码
<template>
  <div class="page-container">
    <div class="header" style="height: 60px">Logo</div>

    <div ref="searchBoxRef" class="search-box">
      <el-input
        v-model="query"
        type="textarea"
        :autosize="{ minRows: 1, maxRows: 6 }"
        placeholder="请输入内容撑开高度"
      />
    </div>

    <div class="table-wrapper">
      <el-table :data="tableData" :height="tableHeight" border>
        <el-table-column prop="date" label="Date" />
        <el-table-column prop="name" label="Name" />
      </el-table>
    </div>

    <div class="pagination" style="height: 50px">
      <el-pagination total="100" />
    </div>
  </div>
</template>

<script setup>
import { ref, onMounted, onBeforeUnmount } from 'vue'

const query = ref('')
const tableData = [] // 你的数据

// 1. 定义 ref 拿到 DOM
const searchBoxRef = ref(null)

// 2. 定义表格高度,给个默认值防止闪烁
const tableHeight = ref('500px')

// 3. 定义页面上除了搜索框和表格之外的【固定高度之和】
// 这里需要你自己算一下:Logo高度(60) + 分页高度(50) + 上下Padding/Margin(假设40) = 150
// 如果这一块也很难算,后面我有更暴力的减法方案
const FIXED_OFFSET = 150 

let observer = null

onMounted(() => {
  if (!searchBoxRef.value) return

  // 实例化 ResizeObserver
  observer = new ResizeObserver((entries) => {
    for (const entry of entries) {
      // 获取搜索框现在的实际高度 (offsetHeight 包含 border 和 padding)
      // 注意:entry.contentRect 不包含 padding,建议直接读取 DOM 的 offsetHeight 更稳妥
      const searchHeight = entry.target.offsetHeight
      
      // 动态计算表格高度
      // 这里的逻辑是:屏幕总高 - 其他固定杂项 - 搜索框高度
      tableHeight.value = `calc(100vh - ${FIXED_OFFSET}px - ${searchHeight}px)`
    }
  })

  // 开始监听
  observer.observe(searchBoxRef.value)
})

onBeforeUnmount(() => {
  // 组件销毁时记得断开监听,防止内存泄漏
  if (observer) observer.disconnect()
})
</script>

<style scoped>
.page-container {
  padding: 20px;
  /* 存量代码可能没有 flex,保持现状即可 */
}
.search-box {
  /* 只需要保证它没有定死 height,能被内容撑开即可 */
  margin-bottom: 10px;
}
.pagination {
  margin-top: 10px;
}
</style>

关键细节说明

  1. 为什么用 ResizeObserver 而不是 watch 监听输入内容?

    • 如果你监听 query 字符串的变化来推算高度,会极其复杂(要计算行高、字体大小、换行逻辑)。
    • ResizeObserver 是浏览器原生 API,它直接告诉你"这个 div 现在有多高",不管是因为字多了换行,还是因为浏览器窗口变窄导致换行,它都能捕获,这是最精准的
  2. 关于 FIXED_OFFSET (固定高度差) 的计算

    如果你的存量代码里,除了搜索框和表格,其他部分(Logo、分页、各种 margin)高度非常乱,很难算出一个精准的数字,你可以采用**"全减法"**策略。

    修改 tableHeight 的计算逻辑:

    javascript 复制代码
    // 在 onMounted 里面算,不需要自己手动加减
    const windowHeight = window.innerHeight // 窗口总高
    const headerHeight = document.querySelector('.header').offsetHeight // 动态获取 Logo区高度
    const paginationHeight = document.querySelector('.pagination').offsetHeight // 动态获取 分页区高度
    const margins = 40 // 预估的间距
    
    // 然后每次 ResizeObserver 回调里:
    tableHeight.value = `${windowHeight - headerHeight - paginationHeight - margins - searchHeight}px`

    (注:这种全动态减法需要监听 window.resize 来更新 windowHeight,稍微麻烦点。如果你能确定其他区域高度大致固定,建议直接写死 FIXED_OFFSET 常量,维护起来最简单。)

  3. Element Plus 表格的 :height

    Element Plus 的 el-table 组件支持直接传入 CSS 字符串(如 calc(xxx))。当你更新 tableHeight.value 时,表格会自动触发重绘,调整内部滚动条的高度,完全符合你的需求。

总结

对于存量代码,"ResizeObserver + 动态 calc" 是性价比最高的方案。它不需要你改动外层 HTML 结构,只需要给搜索框加个钩子,然后动态改一下 Table 的高度属性即可。

相关推荐
小魔女千千鱼13 分钟前
在 Vue 中,this 的行为在箭头函数和普通函数中是不同的
前端·javascript·vue.js
Cassie燁1 小时前
el-table源码解读2-2——createStore()初始化方法
前端·javascript·vue.js
北极糊的狐2 小时前
按钮绑定事件达成跳转效果并将树结构id带入子页面形成参数完成查询功能并将返回的数据渲染到页面上2022.5.29
前端·javascript·vue.js
老华带你飞3 小时前
考试管理系统|基于java+ vue考试管理系统(源码+数据库+文档)
java·开发语言·前端·数据库·vue.js·spring boot·后端
练习前端两年半3 小时前
【Vue3 高级技巧】函数重载+Watch:打造类型安全的通用事件监听 Hook
前端·javascript·vue.js
q_19132846955 小时前
基于SpringBoot+Vue.js的高校竞赛活动信息平台
vue.js·spring boot·后端·mysql·程序员·计算机毕业设计
我是小邵5 小时前
【踩坑实录】一次 H5 页面在 PC 端的滚动条与轮播图修复全过程(Vue + Vant)
前端·javascript·vue.js
梦6505 小时前
Vue 实现动态路由
前端·javascript·vue.js
丶乘风破浪丶5 小时前
Vue项目中判断相同请求的实现方案:从原理到实战
前端·javascript·vue.js
xiaohe06016 小时前
📦 Uni ECharts 是如何使用定制 echarts 的?一篇文章轻松掌握!
vue.js·uni-app·echarts