实现支持作用域插槽的通用数据表格组件
2026/6/25 16:21:51 网站建设 项目流程

实现支持作用域插槽的通用数据表格组件

在 Vue 中,作用域插槽(Scoped Slots)是让父组件自定义子组件内部渲染的利器。下面实现一个<DataTable>组件,它接收data(行数据)和columns(列配置)数组,并在每个<td>中提供插槽,让父组件按列自定义单元格内容。


1. 子组件:DataTable.vue(Vue 3 +<script setup>
  • 核心逻辑
    • 遍历columns,为每一列生成<th>
    • 遍历data生成<tr>,再遍历columns生成<td>
    • 每个<td>内,优先检查父组件是否传递了对应列的具名插槽(以列字段field命名),若存在则使用插槽并传递rowcolumnindex等作用域数据;否则显示默认的row[field]值。
<template> <table class="data-table"> <thead> <tr> <th v-for="col in columns" :key="col.field"> {{ col.title || col.field }} </th> </tr> </thead> <tbody> <tr v-for="(row, rowIndex) in data" :key="rowIndex"> <td v-for="col in columns" :key="col.field"> <!-- 作用域插槽:使用列字段作为插槽名,同时提供后备内容 --> <slot :name="col.field" :row="row" :column="col" :index="rowIndex"> <!-- 默认显示 --> {{ row[col.field] }} </slot> </td> </tr> </tbody> </table> </template> <script setup> defineProps({ data: { type: Array, required: true, default: () => [] }, columns: { type: Array, required: true, // 列对象格式:{ field: 'name', title: '姓名' } default: () => [] } }) </script> <style scoped> .data-table { border-collapse: collapse; width: 100%; } .data-table th, .data-table td { border: 1px solid #ddd; padding: 8px 12px; text-align: left; } .data-table th { background-color: #f5f5f5; } </style>

2. 父组件使用示例

父组件通过v-slot指令(或#缩写)为指定列提供自定义渲染。作用域数据包括:

  • row:当前行的完整数据对象
  • column:当前列配置
  • index:行索引
<template> <div> <DataTable :data="tableData" :columns="columns"> <!-- 自定义 'status' 列:显示不同颜色的标签 --> <template #status="{ row }"> <span :class="row.status === 'active' ? 'tag-active' : 'tag-inactive'"> {{ row.status }} </span> </template> <!-- 自定义 'actions' 列:放置操作按钮 --> <template #actions="{ row, index }"> <button @click="editRow(row, index)">编辑</button> <button @click="deleteRow(index)">删除</button> </template> <!-- 其他未自定义的列(如 name, age)会自动使用默认渲染 --> </DataTable> </div> </template> <script setup> import { ref } from 'vue' import DataTable from './DataTable.vue' const columns = [ { field: 'name', title: '姓名' }, { field: 'age', title: '年龄' }, { field: 'status', title: '状态' }, { field: 'actions', title: '操作' } ] const tableData = ref([ { name: '张三', age: 28, status: 'active' }, { name: '李四', age: 34, status: 'inactive' }, { name: '王五', age: 22, status: 'active' } ]) const editRow = (row, index) => { alert(`编辑第 ${index + 1} 行:${row.name}`) } const deleteRow = (index) => { tableData.value.splice(index, 1) } </script> <style scoped> .tag-active { color: green; font-weight: bold; } .tag-inactive { color: red; } </style>

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询