基于Element-ui 实现具有筛选、排序和分页功能的表格

'# 基于Element-ui 实现具有筛选、排序和分页功能的表格

一、背景与问题

在企业级应用中,表格组件是数据展示的核心组件。随着业务复杂度提升,传统静态表格已难以满足动态筛选、多维排序和分页浏览的需求。Element-ui 的 el-table 组件提供了基础功能,但需要开发者自行实现筛选、排序和分页的逻辑整合。

典型场景包括:

  • 电商后台的订单管理
  • CRM系统的客户信息展示
  • 金融系统的数据报表
  • 项目管理的工时统计

传统开发中常遇到的挑战包括:

  1. 筛选条件与排序维度的动态绑定
  2. 分页参数与过滤条件的联动处理
  3. 大数据量下的性能优化
  4. 多维度排序的实现方式
  5. 状态持久化与缓存机制

二、基本原理

1. 筛选机制

Element-ui 的 filter-method 接收 valuerow 参数,通过自定义逻辑过滤数据。其核心原理是:

  • 每个列定义中配置 filter-method
  • 表格通过遍历数据行,调用所有列的过滤方法
  • 最终返回符合条件的数据子集

2. 排序机制

通过 sort-by 属性绑定排序字段,结合 sort-orders 控制排序顺序。其核心原理是:

  • 使用 sort-by 指定排序字段
  • 通过 sort-orders 设置升序/降序
  • 使用 @sort-change 事件处理排序变化
  • 重新计算排序后的数据集

3. 分页机制

结合 el-pagination 组件实现分页,其核心原理是:

  • 通过 current-pagepage-size 控制分页参数
  • 在数据请求时计算偏移量
  • 在数据展示时切片显示对应页的数据

三、环境准备

1. 项目依赖

npm install element-ui axios

2. 基础配置(Vue 3 + TypeScript)

// main.ts
import { createApp } from 'vue'
import App from './App.vue'
import ElementPlus from '@element-plus/core'
import 'element-plus/dist/index.css'

createApp(App)
  .use(ElementPlus)
  .mount('#app')

四、核心实现

1. 筛选功能实现

<template>
  <el-table
    :data="filteredData"
    border
    fit
    highlight-current-row
  >
    <el-table-column
      prop="name"
      label="名称"
      :filters="[{ text: 'VIP', value: 'VIP' }]"
      :filter-method="filterHandler"
    />
    <!-- 其他列定义 -->
  </el-table>
</template>

<script>
export default {
  data() {
    return {
      filteredData: [],
      tableData: [] // 原始数据
    }
  },
  methods: {
    filterHandler(value, row) {
      // 实现筛选逻辑
      return row.name.includes(value)
    }
  }
}
</script>

关键代码解释:

  • filter-method 接收两个参数:筛选值(value)和当前行(row)
  • 返回布尔值决定是否保留该行
  • 支持正则表达式、模糊匹配等复杂逻辑

2. 排序功能实现

<template>
  <el-table
    :data="sortedData"
    border
    fit
    @sort-change="handleSortChange"
  >
    <el-table-column
      prop="name"
      label="名称"
      sortable
    />
    <!-- 其他列定义 -->
  </el-table>
</template>

<script>
export default {
  data() {
    return {
      sortedData: [],
      sortField: '',
      sortOrder: 'ascending'
    }
  },
  methods: {
    handleSortChange({ column, prop, order }) {
      this.sortField = prop
      this.sortOrder = order
      this.sortData()
    },
    sortData() {
      this.sortedData = [...this.tableData].sort((a, b) => {
        if (this.sortOrder === 'ascending') {
          return a[this.sortField] > b[this.sortField] ? 1 : -1
        } else {
          return a[this.sortField] < b[this.sortField] ? 1 : -1
        }
      })
    }
  }
}
</script>

关键代码解释:

  • @sort-change 事件处理排序变化
  • 使用数组的sort方法进行排序
  • 支持多列排序和多维度排序

3. 分页功能实现

<template>
  <div>
    <el-table
      :data="paginatedData"
      border
      fit
    >
      <!-- 列定义 -->
    </el-table>
    <el-pagination
      :current-page="currentPage"
      :page-size="pageSize"
      :total="total"
      @current-change="handlePageChange"
    />
  </div>
</template>

<script>
export default {
  data() {
    return {
      currentPage: 1,
      pageSize: 10,
      total: 0,
      tableData: [] // 原始数据
    }
  },
  computed: {
    paginatedData() {
      const start = (this.currentPage - 1) * this.pageSize
      const end = start + this.pageSize
      return this.tableData.slice(start, end)
    }
  },
  methods: {
    handlePageChange(page) {
      this.currentPage = page
    }
  }
}
</script>

关键代码解释:

  • 使用slice方法实现数据切片
  • 分页参数通过current-page和page-size控制
  • 总数据量通过total字段展示

五、完整案例

1. 综合案例:订单管理表格

<template>
  <div class="order-table">
    <el-form :model="searchForm" label-width="120px">
      <el-row :gutter="20">
        <el-col :span="8">
          <el-form-item label="订单编号">
            <el-input v-model="searchForm.orderNo" />
          </el-form-item>
        </el-col>
        <el-col :span="8">
          <el-form-item label="客户名称">
            <el-input v-model="searchForm.customerName" />
          </el-form-item>
        </el-col>
        <el-col :span="8">
          <el-form-item label="订单状态">
            <el-select v-model="searchForm.status" placeholder="请选择">
              <el-option label="全部" value="" />
              <el-option label="已支付" value="PAID" />
              <el-option label="未支付" value="UNPAID" />
            </el-select>
          </el-form-item>
        </el-col>
      </el-row>
    </el-form>
    
    <el-table
      :data="displayData"
      border
      fit
      highlight-current-row
      @sort-change="handleSortChange"
    >
      <el-table-column
        prop="orderNo"
        label="订单编号"
        sortable
      />
      <el-table-column
        prop="customerName"
        label="客户名称"
        :filters="[{ text: 'VIP', value: 'VIP' }]"
        :filter-method="filterHandler"
      />
      <el-table-column
        prop="status"
        label="订单状态"
        :filters="[{ text: '已支付', value: 'PAID' }, { text: '未支付', value: 'UNPAID' }]"
        :filter-method="filterHandler"
      />
      <el-table-column
        prop="amount"
        label="订单金额"
        sortable
      />
      <el-table-column
        prop="createTime"
        label="创建时间"
        sortable
      />
    </el-table>
    
    <el-pagination
      :current-page="currentPage"
      :page-size="pageSize"
      :total="total"
      @current-change="handlePageChange"
    />
  </div>
</template>

<script>
export default {
  data() {
    return {
      searchForm: {
        orderNo: '',
        customerName: '',
        status: ''
      },
      currentPage: 1,
      pageSize: 10,
      total: 0,
      tableData: [], // 原始数据
      filteredData: [], // 筛选后的数据
      sortedData: [] // 排序后的数据
    }
  },
  computed: {
    displayData() {
      return this.sortedData.slice(
        (this.currentPage - 1) * this.pageSize, 
        this.currentPage * this.pageSize
      )
    }
  },
  methods: {
    // 筛选逻辑
    filterHandler(value, row) {
      if (!value) return true
      return row[this.columnKey] && row[this.columnKey].toString().includes(value)
    },
    
    // 排序逻辑
    handleSortChange({ column, prop, order }) {
      this.sortField = prop
      this.sortOrder = order
      this.sortData()
    },
    
    sortData() {
      this.sortedData = [...this.filteredData].sort((a, b) => {
        if (this.sortOrder === 'ascending') {
          return a[this.sortField] > b[this.sortField] ? 1 : -1
        } else {
          return a[this.sortField] < b[this.sortField] ? 1 : -1
        }
      })
    },
    
    // 分页逻辑
    handlePageChange(page) {
      this.currentPage = page
    },
    
    // 数据加载
    async loadData() {
      // 模拟数据请求
      this.tableData = await this.fetchData()
      
      // 筛选处理
      this.filteredData = this.tableData.filter(row => {
        return this.searchForm.orderNo ? row.orderNo.includes(this.searchForm.orderNo) : true
      })
      
      // 排序处理
      this.sortData()
      
      // 更新分页信息
      this.total = this.filteredData.length
    }
  },
  mounted() {
    this.loadData()
  }
}
</script>

关键代码解释:

  1. 综合了筛选、排序和分页的完整流程
  2. 使用计算属性displayData进行数据展示
  3. loadData方法中处理数据加载和状态更新
  4. 通过filterHandler方法实现多列筛选
  5. 使用sortData方法进行动态排序

六、源码解析

1. 筛选逻辑

filterHandler(value, row) {
  if (!value) return true
  return row[this.columnKey] && row[this.columnKey].toString().includes(value)
}
  • columnKey 是当前列的字段名
  • 支持字符串匹配,可扩展为正则表达式
  • 需要处理数值类型字段的转换

2. 排序逻辑

sortData() {
  this.sortedData = [...this.filteredData].sort((a, b) => {
    if (this.sortOrder === 'ascending') {
      return a[this.sortField] > b[this.sortField] ? 1 : -1
    } else {
      return a[this.sortField] < b[this.sortField] ? 1 : -1
    }
  })
}
  • 使用数组的sort方法进行排序
  • 支持多维排序(可扩展为多列排序)
  • 需要注意数值类型的比较

3. 分页逻辑

get displayData() {
  return this.sortedData.slice(
    (this.currentPage - 1) * this.pageSize, 
    this.currentPage * this.pageSize
  )
}
  • 使用数组的slice方法实现数据切片
  • 需要注意分页参数的更新逻辑
  • 可结合虚拟滚动优化大屏展示

七、进阶使用

1. 动态筛选条件

filterHandler(value, row) {
  const filters = this.searchForm
  return Object.entries(filters).every(([key, val]) => {
    if (!val) return true
    return row[key] && row[key].toString().includes(val)
  })
}
  • 支持多条件筛选
  • 可扩展为逻辑运算(AND/OR)

2. 多列排序

sortData() {
  this.sortedData = [...this.filteredData].sort((a, b) => {
    let result = 0
    this.sortFields.forEach(field => {
      if (result === 0) {
        result = a[field] > b[field] ? 1 : -1
      }
    })
    return result
  })
}
  • 支持多列排序
  • 需要处理不同字段类型

3. 复杂分页逻辑

get displayData() {
  const start = (this.currentPage - 1) * this.pageSize
  const end = start + this.pageSize
  return this.sortedData.slice(start, end)
}
  • 支持分页参数的动态更新
  • 可结合懒加载优化性能

八、性能与工程实践

1. 性能优化

  • 虚拟滚动:使用vue-virtual-scroller组件优化大数据展示
  • 分页加载:按需加载数据,避免一次性加载全部数据
  • 防抖处理:对频繁触发的筛选操作进行防抖处理

2. 异常处理

try {
  await this.loadData()
} catch (error) {
  this.$message.error('数据加载失败')
}
  • 需要处理网络异常
  • 需要处理数据转换错误

3. 安全考虑

  • 输入校验:对用户输入进行严格校验
  • 数据过滤:对返回数据进行安全过滤
  • 敏感字段处理:对敏感字段进行脱敏处理

九、常见问题与踩坑

1. 分页跳转数据未更新

<el-pagination
  :current-page="currentPage"
  @current-change="handlePageChange"
/>
  • 问题:分页参数更新但数据未重新加载
  • 解决:在handlePageChange中重新调用数据加载方法

2. 排序失效

@sort-change="handleSortChange"
  • 问题:排序后数据未更新
  • 解决:确保排序逻辑正确,检查字段类型

3. 筛选条件丢失

filterHandler(value, row) {
  return row[this.columnKey].includes(value)
}
  • 问题:筛选条件未持久化
  • 解决:使用refreactive保存筛选状态

十、最佳实践

1. 应用场景

  • 数据量较大(>1000条)
  • 需要多维度筛选
  • 需要动态排序
  • 需要分页浏览

2. 不适用场景

  • 数据量较小(<100条)
  • 需要实时数据更新
  • 需要复杂的表单交互
  • 需要数据导出功能

3. 推荐方案

  • 使用el-table的原生功能
  • 使用ref管理状态
  • 使用计算属性优化性能
  • 使用debounce优化筛选性能

十一、总结

基于Element-ui实现具有筛选、排序和分页功能的表格,需要深入理解其工作原理和实现机制。通过合理使用filter-method@sort-changeel-pagination等核心特性,可以构建出功能完善的表格组件。

在实际开发中,需要根据业务需求选择合适的实现方式。对于大数据量场景,建议结合虚拟滚动和分页加载技术;对于实时性要求高的场景,需要优化数据更新机制。同时,要注意异常处理和安全防护,确保系统的稳定性和安全性。

本方案通过完整的代码示例和深入分析,展示了如何在Vue 3项目中实现高级表格功能。通过合理的设计和实现,可以构建出既符合业务需求又具有良好性能的表格组件。

最后修改于:2026年09月15日 20:39

评论已关闭

推荐阅读

AIGC实战——Transformer模型
2024年12月01日
Socket TCP 和 UDP 编程基础(Python)
2024年11月30日
python , tcp , udp
如何使用 ChatGPT 进行学术润色?你需要这些指令
2024年12月01日
AI
最新 Python 调用 OpenAi 详细教程实现问答、图像合成、图像理解、语音合成、语音识别(详细教程)
2024年11月24日
ChatGPT 和 DALL·E 2 配合生成故事绘本
2024年12月01日
omegaconf,一个超强的 Python 库!
2024年11月24日
【视觉AIGC识别】误差特征、人脸伪造检测、其他类型假图检测
2024年12月01日
[超级详细]如何在深度学习训练模型过程中使用 GPU 加速
2024年11月29日
Python 物理引擎pymunk最完整教程
2024年11月27日
MediaPipe 人体姿态与手指关键点检测教程
2024年11月27日
深入了解 Taipy:Python 打造 Web 应用的全面教程
2024年11月26日
基于Transformer的时间序列预测模型
2024年11月25日
Python在金融大数据分析中的AI应用(股价分析、量化交易)实战
2024年11月25日
AIGC Gradio系列学习教程之Components
2024年12月01日
Python3 `asyncio` — 异步 I/O,事件循环和并发工具
2024年11月30日
llama-factory SFT系列教程:大模型在自定义数据集 LoRA 训练与部署
2024年12月01日
Python 多线程和多进程用法
2024年11月24日
Python socket详解,全网最全教程
2024年11月27日
python之plot()和subplot()画图
2024年11月26日
理解 DALL·E 2、Stable Diffusion 和 Midjourney 工作原理
2024年12月01日