实现固定表格首尾列不随着滚动条滚动

在表格布局中,固定首尾列是一种常见需求,特别是在需要大量数据展示的情况下。

效果展示为:

1. 实现方法

HTML 结构

<div class="table-wrapper">
  <table class="fixed-columns-table">
    <thead>
      <tr>
        <th class="fixed-left">第一列</th>
        <th>第二列</th>
        <th>第三列</th>
        <th>第四列</th>
        <th>第五列</th>
        <th>第六列</th>
        <th>第七列</th>
        <th class="fixed-right">第八列</th>
      </tr>
    </thead>
    <tbody>
      <tr>
        <td class="fixed-left">数据1</td>
        <td>数据2</td>
        <td>数据3</td>
        <td>数据4</td>
        <td>数据5</td>
        <td>数据6</td>
        <td>数据7</td>
        <td class="fixed-right">数据8</td>
      </tr>
      <tr>
        <td class="fixed-left">数据9</td>
        <td>数据10</td>
        <td>数据11</td>
        <td>数据12</td>
        <td>数据13</td>
        <td>数据14</td>
        <td>数据15</td>
        <td class="fixed-right">数据16</td>
      </tr>
      <tr>
        <td class="fixed-left">数据17</td>
        <td>数据18</td>
        <td>数据19</td>
        <td>数据20</td>
        <td>数据21</td>
        <td>数据22</td>
        <td>数据23</td>
        <td class="fixed-right">数据24</td>
      </tr>
    </tbody>
  </table>
</div>

CSS 样式,使用 position: sticky 实现:

.table-wrapper {
  width: 100%;
  overflow-x: auto;
  overflow-y: hidden;
  position: relative;
}

.fixed-columns-table {
  width: 200%; /* 使表格宽度超过容器,出现滚动条 */
  border-collapse: collapse;
  position: relative;
}

/* 固定第一列 */
.fixed-left {
  position: sticky;
  left: 0;
  background-color: #eeeeee; /* 防止背景遮挡 */
  z-index: 2; /* 确保在其他列之上 */
  box-shadow: 2px 0 4px rgba(0, 0, 0, 0.1); /* 给左侧添加阴影 */
}

/* 固定最后一列 */
.fixed-right {
  position: sticky;
  right: 0;
  background-color: #eeeeee; /* 防止背景遮挡 */
  z-index: 2; /* 确保在其他列之上 */
  box-shadow: -2px 0 4px rgba(0, 0, 0, 0.1); /* 给右侧添加阴影 */
}

/* 样式调整,防止列宽在滚动时出现重叠 */
.fixed-columns-table th,
.fixed-columns-table td {
  padding: 10px;
  text-align: center;
  border: 1px solid #ddd;
}

2. 性能优化

当表格数据量大时,渲染所有数据会导致 DOM 节点数量过多,降低渲染性能。使用虚拟滚动技术,仅渲染可见区域的数据行。

虚拟滚动技术(Virtual Scrolling)是一种优化技术,特别适用于大数据量列表或表格的渲染,能够显著提高性能,减少 DOM 节点的数量,从而提升浏览器渲染的效率。其核心思想是:仅渲染用户当前可见的部分数据,而其他不在可视区域的数据不渲染或销毁。

2.1 问题背景

在传统的表格或列表渲染中,当数据量非常大时,所有数据都会被渲染到页面上。浏览器会将这些 DOM 节点都加载并进行渲染和布局,导致:

1、内存占用过高:大量的 DOM 节点会占用大量内存,影响页面性能。

2、渲染性能差:渲染大量的 DOM 元素会导致页面响应缓慢,特别是在快速滚动时,表现尤为明显。

3、浏览器崩溃风险:在极端情况下,渲染超大量的数据可能会导致浏览器崩溃。

2.2 虚拟滚动的原理

虚拟滚动技术通过监听滚动事件,并根据当前的滚动位置来动态决定哪些数据项需要渲染。具体流程如下:

1、计算可视区域:首先确定表格或列表的可视区域的高度(在表格中是行高,或者列表的项高),以及容器的高度(例如,表格的高度)。通过这些信息可以计算出可视区域内应该渲染多少行数据。

2、动态计算和渲染:当用户滚动时,虚拟滚动会根据当前滚动位置计算出哪些数据行应该渲染,并且只渲染这些数据。其他不在可视区域的数据行将不会渲染,或者已经渲染过的数据将被销毁。

3、占位元素:为了保持表格的布局一致,虚拟滚动需要根据当前渲染的行数来插入占位元素,这些占位元素的高度总和等于表格或列表的总高度。这样,用户可以继续滚动,但 DOM 树不会随着滚动条的滑动而增加。

2.3 在 Vue 中实现虚拟滚动

在 Vue 项目中,我们可以使用第三方库如 vue-virtual-scroller 来简化虚拟滚动的实现。其是一个专为 Vue 设计的虚拟滚动组件,可以轻松实现虚拟滚动的功能。

1、安装 vue-virtual-scroller

npm install vue-virtual-scroller --save

2、基本使用方法

首先,我们需要在 Vue 组件中引入并注册 vue-virtual-scroller 组件,然后用它来包装数据列表或表格。 

在 main.js 或组件中注册 vue-virtual-scroller:

import { createApp } from 'vue';
import { VirtualScroller } from 'vue-virtual-scroller';
import 'vue-virtual-scroller/dist/vue-virtual-scroller.css';

const app = createApp(App);
app.component('VirtualScroller', VirtualScroller);
app.mount('#app');

在表格或列表中使用 VirtualScroller 来包裹需要虚拟滚动的部分:

<template>
  <div class="table-container">
    <VirtualScroller :items="tableData" :item-height="30" class="virtual-table">
      <template #default="{ item }">
        <div class="table-row">
          <div class="table-cell">{{ item.joinDate }}</div>
          <div class="table-cell">{{ item.name }}</div>
          <div class="table-cell">{{ item.age }}</div>
          <div class="table-cell">{{ item.role }}</div>
          <div class="table-cell">{{ item.department }}</div>
          <div class="table-cell">{{ item.city }}</div>
          <div class="table-cell">{{ item.email }}</div>
          <div class="table-cell">{{ item.operation }}</div>
        </div>
      </template>
    </VirtualScroller>
  </div>
</template>

<script>
export default {
  data() {
    return {
      tableData: [
        { joinDate: '2020-01-01', name: 'John', age: 25, role: 'Developer', department: 'IT', city: 'New York', email: 'john@example.com', operation: 'Edit' },
        { joinDate: '2021-02-01', name: 'Jane', age: 28, role: 'Manager', department: 'HR', city: 'London', email: 'jane@example.com', operation: 'View' },
        // Add more data...
      ]
    };
  }
};
</script>

<style scoped>
.table-container {
  height: 400px; 
  overflow-y: auto;
}

.table-row {
  display: flex;
  padding: 8px;
  border-bottom: 1px solid #ddd;
}

.table-cell {
  flex: 1;
  padding: 5px;
}
</style>

关键点解释:

- items 属性:传入的数据数组。

- item-height 属性:每个数据项的高度。它需要是一个固定值,这样 Vue Virtual Scroller 才能正确计算可视区域内需要渲染多少行。

- default 插槽:通过该插槽渲染每一行数据,插槽的作用是根据虚拟滚动的计算,动态渲染当前可视的行。

3. 注意事项

1、固定列宽度设置

建议为固定列设置固定宽度,如 width: 150px,防止内容撑开导致布局异常。

th.fixed-left, 
td.fixed-left { 
  width: 150px; 
}

2、内容溢出处理

如果列内容较多,可以通过以下方式限制溢出:

td {
  white-space: nowrap; /* 禁止换行 */
  overflow: hidden; /* 隐藏溢出内容 */
  text-overflow: ellipsis; /* 超出部分以省略号显示 */
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值