vue3+ts 结合el-table二次封装表格组件

本文介绍如何使用 Element UI 的 Table 组件创建高度可定制化的表格,包括自定义列模板、实现行增删功能及响应式数据更新。通过具体示例展示了如何设置列属性、绑定事件以及使用插槽来增强表格的交互性和灵活性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

效果图

 Table组件

<template>
  <el-table :data="tableData" style="width: 80%" v-bind="{ border: true }">
    <el-table-column type="selection" width="50" align="center" />
    <el-table-column type="index" label="序号" width="100" fixed="left" align="center">
      <template #default="{ $index }">
        <i>{{ $index + 1 }}</i>
      </template>
    </el-table-column>
    <el-table-column
      v-for="col in option"
      :key="col.prop"
      :label="col.label"
      :prop="col.prop"
      :width="col.width"
      :align="col.align"
      v-bind="{ ...col.attrs }"
    >
      <template #header>
        <!-- <span v-if="col.editable"><button>可编辑</button></span> -->
        <span>{{ col.label }}</span>
      </template>
      <template #default="{ row, $index }" v-if="col.slot">
        <slot :name="col.slot" :row="row" :index="$index"></slot>
      </template>
    </el-table-column>
  </el-table>
</template>

<script lang="ts" setup>
import { TableOption, TableData } from './tableData'
type Props = {
  option: Array<TableOption>
  tableData: Array<TableData>
}
const props = defineProps<Props>()
watch(props.tableData, (newVal, oldVal) => {
  console.log(newVal, oldVal)
})
</script>
<style></style>

其中表格的勾选列和序号列也可以添加v-if来控制隐藏

Table的类型接口和列

export interface TableOption {
  // 字段名称
  prop?: string
  // 表头
  label: string
  // 对应列的宽度
  width?: string | number
  // 对齐方式
  align?: 'left' | 'center' | 'right'
  // 自定义列模板的插槽名
  slot?: string
  // 是否是操作项
  action?: boolean
  // 是否可以编辑
  editable?: boolean
  // 属性
  attrs?: object
}

export interface TableData {
  date?: string
  name?: string
  address?: string
}

export interface FormData {
  name?: string
}

export const option: TableOption[] = [
  {
    label: 'Date',
    prop: 'date',
    width: 200,
    slot: 'dateSlot',
    editable: true,
    attrs: {
      sortable: ''
    }
  },
  {
    label: 'Name',
    prop: 'name',
    slot: 'nameSlot',
    attrs: {
      sortable: ''
    }
  },
  {
    label: 'Address',
    prop: 'address',
    slot: 'addressSlot',
    attrs: {
      sortable: ''
    }
  },
  {
    label: 'Edit',
    prop: 'edit',
    slot: 'editSlot'
  }
]

 调用

<template>
  <el-row class="mb-4">
    <el-button type="primary" @click="addRow">新增行</el-button>
    <el-button type="success">Success</el-button>
  </el-row>
  <common-table :option="option" :tableData="tableData">
    <template #dateSlot="{ row }">
      <div>{{ row.date }}</div>
    </template>
    <template #nameSlot="{ row }">
      <div>
        {{ row.name }}
      </div>
    </template>
    <template #addressSlot="{ row }">
      <div>
        {{ row.address }}
      </div>
    </template>
    <template #editSlot="{ row, index }">
      <div>
        <el-button @click="deleteRow(row, index)">删除</el-button>
        <el-button @click="viewRow(row)">查看</el-button>
      </div>
    </template>
  </common-table>
</template>
<script setup lang="ts">
import CommonTable from '../commonTable/CommonTable.vue'
import { option, TableData } from './tableData'
const tableData = reactive<TableData[]>([
  {
    date: '2016-05-03',
    name: '1',
    address: '北京'
  },
  {
    date: '2016-05-02',
    name: '2',
    address: '上海'
  },
  {
    date: '2016-05-04',
    name: '3',
    address: '南京'
  }
])
const addRow = () => { // 添加行
  const data = {
    date: '22222',
    name: 'asjdlasjdlad',
    address: 'asjd;sad'
  }
  tableData.push(data)
}
const deleteRow = (row: TableData, index: number) => { // 删除行
  tableData.splice(index, 1)
}
</script>
<style></style>

<think>好的,我现在需要帮助用户解决如何用Vue 3.3和TypeScript对Element Plus的el-table进行二次封装的问题。首先,我得回顾用户提供的引用内容,看看有哪些现有的资料可以参考。 引用1提到可以通过二次封装提升代码复用性和灵活性,步骤包括安装依赖,但用户可能已经知道这一点,所以重点应该在示例上。引用2和3展示了基本的封装思路,比如子组件的结构、表头和数据的动态绑定。特别是引用3中的示例代码,展示了如何通过遍历tableHeader来生成el-table-column,这应该是一个关键点。引用4提供了一个博客链接,可能包含更详细的步骤,但用户可能需要具体的代码示例而不是外部链接。 用户使用的是Vue 3.3和TypeScript,因此需要确保代码符合Composition API和TypeScript的类型定义。例如,使用defineProps和泛型来定义组件的props类型。用户可能希望封装后的组件支持动态表头、分页、排序等功能,所以需要包含这些功能的实现。 接下来,我需要整理一个结构清晰的步骤,包括创建子组件、定义类型、处理props、插槽的使用、分页逻辑和事件处理。同时,要确保代码中的TypeScript语法正确,比如接口定义和泛型的使用。例如,TableColumn接口和TableProps泛型接口的使用可以增强类型安全。 另外,用户可能需要自定义列模板,因此需要使用作用域插槽,允许父组件覆盖默认的列显示。分页部分需要处理current-page和page-size的变化事件,并触发父组件的分页动作。 最后,生成相关问题时要涵盖用户可能感兴趣的扩展点,比如插槽扩展、表单集成、性能优化和自定义样式。这些问题可以帮助用户进一步深入封装组件的功能。</think># Vue 3.3 + TypeScript 封装 el-table 组件指南 ## 一、基础封装实现(6步详解) 1. **创建子组件** `TableComponent.vue` ```typescript <script setup lang="ts"> import { ref } from &#39;vue&#39; interface TableColumn { label: string prop: string width?: number sortable?: boolean } interface TableProps<T = any> { data: T[] columns: TableColumn[] pageSize?: number currentPage?: number } const props = defineProps<TableProps>() const emit = defineEmits([&#39;page-change&#39;, &#39;sort-change&#39;]) </script> <template> <el-table :data="props.data" @sort-change="emit(&#39;sort-change&#39;, $event)" > <el-table-column v-for="(col, index) in props.columns" :key="index" :prop="col.prop" :label="col.label" :width="col.width" :sortable="col.sortable || false" > <template #default="{ row }"> <slot :name="col.prop" :row="row"> {{ row[col.prop] }} </slot> </template> </el-table-column> </el-table> <el-pagination v-if="props.pageSize && props.currentPage" :page-size="props.pageSize" :current-page="props.currentPage" @current-change="emit(&#39;page-change&#39;, $event)" /> </template> ``` 2. **父组件调用示例** ```typescript <script setup lang="ts"> import TableComponent from &#39;./TableComponent.vue&#39; interface User { id: number name: string age: number } const columns: TableColumn[] = [ { prop: &#39;name&#39;, label: &#39;姓名&#39; }, { prop: &#39;age&#39;, label: &#39;年龄&#39;, sortable: true } ] const tableData = ref<User[]>([ { id: 1, name: &#39;张三&#39;, age: 25 }, { id: 2, name: &#39;李四&#39;, age: 30 } ]) const handlePageChange = (page: number) => { console.log(&#39;当前页码:&#39;, page) } </script> <template> <TableComponent :data="tableData" :columns="columns" @page-change="handlePageChange" > <!-- 自定义姓名列 --> <template #name="{ row }"> <el-tag>{{ row.name }}</el-tag> </template> </TableComponent> </template> ``` ## 二、进阶功能实现 1. **类型增强**(使用泛型) ```typescript interface TableProps<T = any> { data: T[] columns: TableColumn[] // 添加更多类型约束... } ``` 2. **动态表头配置** ```typescript // 可配置化表头示例 const dynamicColumns = computed(() => { return props.columns.map(col => ({ ...col, align: col.align || &#39;left&#39; })) }) ``` 3. **分页封装**(组合式API) ```typescript const pagination = reactive({ pageSize: 10, currentPage: 1, total: 0 }) // 分页请求示例 const fetchData = async () => { const res = await api.getList({ page: pagination.currentPage, size: pagination.pageSize }) tableData.value = res.data pagination.total = res.total } ``` ## 三、最佳实践建议 1. 使用`provide/inject`管理表格配置[^3] 2. 通过`expose`暴露el-table实例方法 ```typescript const tableRef = ref() defineExpose({ clearSelection: () => tableRef.value?.clearSelection() }) ``` 3. 添加全局样式覆盖(推荐SASS) ```scss :deep(.el-table__header) { th { background-color: #f5f7fa; } } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值