深入理解element-plus table二次封装:从理论到实践的全面指南

前言

在许多中后台管理系统中,表格占据着半壁江山,如果使用element plus组件库,那么少不了要用到table组件,可是table组件的功能过于基础,因此,我在table组件的实现基础之上进一步封装,从而实现功能更强大的table组件。

在实现table组件的功能之前,我们首先需要先来看看用法,由于使用示例比较多,可能将会有几篇文章主要介绍所有示例用法,介绍完示例之后将会有专门的文章基于使用方式去详细讲解封装思路。

毕竟我们要实现一个东西,就应该需要先理解这个东西怎么用的,从如何使用再去推导如何实现就会很有思路了。

所以在实现之前,我们需要先来具体了解一下每个示例的用法和效果。

首先这个组件被我封装成以插件的形式来使用,我们可以看到在main.ts下的使用代码如下所示:

import { createApp } from 'vue'
import App from './App.vue'
//...
import ElementTable from './components/index'


const app = createApp(App);
//....
app.use(ElementTable);
app.mount('#app')

如此一来,我们就可以全局使用该组件了。

示例1-基础使用

组件支持传入column和data属性,即表格列数据和表体数据,前面我们已经说过了,我们是在全局当中注册好了,因此在vue文件当中可以直接使用。示例代码如下:

 <element-table :column="column" :data="tableData" />

然后就是ts代码,如下所示:

import { ElTableColumnProps } from '../components/tableProps';
/* 引入ElTableColumnProps定义column可获得类型提示 */
const column: ElTableColumnProps[] = [
  {
    type: "index",
    width: "60px",
    label: "序号",
  },
  {
    prop: "name",
    label: "名字",
  },
  {
    prop: "date",
    label: "日期",
  },
  {
    prop: "address",
    label: "地址",
  },
];
// 后续如无特殊说明,表体数据都是这个
const tableData = [
  {
    date: "2016-05-02",
    name: "佘太君",
    address: "上海市普陀区金沙江路 1518 弄",
  },
  {
    date: "2016-05-04",
    name: "王小虎",
    address: "上海市普陀区金沙江路 1517 弄",
  },
  {
    date: "2016-05-01",
    name: "王小帅",
    address: "上海市普陀区金沙江路 1519 弄",
  },
  {
    date: "2016-05-03",
    name: "王小呆",
    address: "上海市普陀区金沙江路 1516 弄",
  },
];

从这个示例,我们可以看到,我们的column传入一个对象数组,对象的属性包含prop,label,type,width等属性,其中type值为index,代表制定一个索引列,然后label和prop分别指定列名以及对应绑定的表体数据字段名,width则指定列宽。

上述代码展示效果如下所示:

示例2--基础的render table

render渲染函数html部分和前面示例1保持一致,唯一不同的是ts代码,我们只需要绑定column和data属性数据即可,一个示例代码如下所示:

import { h } from 'vue';
// 这里是导入的类型
import { ElTableColumnProps } from '../components/tableProps';
const column: ElTableColumnProps[] = [
  {
    type: "index",
    width: "60px",
    label: "序号",
  },
  {
    label: "名字",
    prop: "name",
    render: (data, scope) => {
      const { row, column } = scope;
      const propKey = column.property;
      return h('div', null, { default: () => `render 结果 -- ${row[propKey]}== ${data}` })
    },
  },
  {
    prop: "date",
    label: "日期",
  },
  {
    prop: "address",
    label: "地址",
  },
];

上述代码展示效果如下所示:

从这个示例,我们可以看到,render是一个渲染函数,代表自定义渲染列。

这里尤其需要注意render函数的参数,第一个参数指的是数据,第二个参数则指的是当前表格上下文,我们可以从中获取一些属性,例如列数据column,行数据row等等,从而实现自定义渲染表体。

示例3--插槽用法

关于使用插槽,我们通常使用一个template标签,并制定#加属性值来表示,如示例:

 <element-table :column="column" :data="tableData">
    <template #name="{ row }">
      <div>
        <span>
          <code>name</code>
          插槽--{{ row.name }}
        </span>
      </div>
    </template>
    <template #default>
      <div>
        <span>
          默认插槽名字为
          <strong>default</strong>
        </span>
      </div>
    </template>
  </element-table>

这里分成了两种插槽,第一种是具名插槽,通过#[属性名(这里的属性名通过column里的slotName属性指定)]指定,第二种则是默认插槽,通过#default(与前面具名插槽原理类似)指定,然后在配置的column列数据中,我们通过slotName来指定插槽名,代码如下所示:

const column = [
  {
    type: "index",
    width: "60px",
    label: "序号",
  },
  {
    label: "具名插槽",
    slotName: "name",
  },
  {
    label: "默认插槽",
    slotName: "default",
  },
  {
    prop: "date",
    label: "日期",
  },
  {
    prop: "address",
    label: "地址",
  },
];

上述代码展示效果如下所示:

示例4--边框

边框table,只是在组件当中传入一个border属性即可,其它跟前面示例没什么两样。代码如下所示:

<element-table border :column="column" :data="tableData" />

ts代码忽略,以上代码展示效果如下图所示:

示例5--自定义列渲染

在前面的示例3当中,我们已经初窥自定义列渲染的实现了,接下来这个示例,我们将基于示例3,实现更为复杂的自定义渲染列示例。我们将会引入element-plus的icon(图标)组件和popover(悬浮对话框)组件。代码如下所示:

  <element-table :column="column" :data="tableData" style="width: 100%">
    <template #date="scope">
      <div style="display: flex; align-items: center">
        <el-icon>
          <timer />
        </el-icon>
        <span style="margin-left: 10px">{{ scope.row.date }}</span>
      </div>
    </template>
    <template #name="scope">
      <el-popover effect="light" trigger="hover" placement="top" width="auto">
        <template #default>
          <div>name: {{ scope.row.name }}</div>
          <div>address: {{ scope.row.address }}</div>
        </template>
        <template #reference>
          <el-tag>{{ scope.row.name }}</el-tag>
        </template>
      </el-popover>
    </template>
    <template #default="scope">
      <el-button size="small" @click="handleEdit(scope.$index, scope.row)"
        >Edit</el-button
      >
      <el-button size="small" type="danger" @click="handleDelete(scope.$index, scope.row)"
        >Delete</el-button
      >
    </template>
  </element-table>

接下来,来看我们的ts代码,如下所示:

import { Timer } from "@element-plus/icons-vue";

interface User {
  date: string;
  name: string;
  address: string;
}

const handleEdit = (index: number, row: User) => {
  console.log(index, row);
};
const handleDelete = (index: number, row: User) => {
  console.log(index, row);
};

const column = [
  {
    type: "index",
    width: "60px",
    label: "序号",
  },
  {
    prop: "date",
    label: "日期",
    width: 180,
    slotName: "date",
  },
  {
    prop: "name",
    width: 180,
    label: "名字",
    slotName: "name",
  },
  {
    prop: "address",
    label: "Operations",
    slotName: "default",
  },
];

const tableData: User[] = [
  //...
];

这个示例其实也还是插槽的用法,只不过多了绑定按钮事件。上述代码展示效果如下所示:

示例6-自定义表头

自定义表头与自定义列渲染是同一个原理,也是插槽用法,只不过自定义列的插槽名属性叫做slotName,而自定义表头的插槽名则叫做headerSlot,然后就可以像自定义列那样自定义表头即可。如以下一个示例:

 <element-table :column="column" :data="filterTableData" style="width: 100%">
    <template #header>
      <el-input v-model="search" size="small" placeholder="Type to search" />
    </template>
    <template #default="scope">
      <el-button size="small" @click="handleEdit(scope.$index, scope.row)"
        >Edit</el-button
      >
      <el-button size="small" type="danger" @click="handleDelete(scope.$index, scope.row)"
        >Delete</el-button
      >
    </template>
  </element-table>

然后我们的ts代码就可以基于搜索框,实现数据的过滤,利用ref函数创建一个响应式数据,也就是search。代码如下所示:

import { ref, computed } from "vue";

interface User {
  date: string;
  name: string;
  address: string;
}

const search = ref("");
//...注意这里
const filterTableData = computed(() =>
  tableData.filter(
    (data) =>
      !search.value || data.name.toLowerCase().includes(search.value.toLowerCase())
  )
);

const handleEdit = (index: number, row: User) => {
  console.log(index, row);
};
const handleDelete = (index: number, row: User) => {
  console.log(index, row);
};

const column = [
  {
    prop: "date",
    label: "日期",
    width: 180,
    slotName: "date",
  },
  {
    prop: "name",
    width: 180,
    label: "名字",
    slotName: "name",
  },
  {
    align: "right",
    slotName: "default",
    //这里就是自定义表头的自定义插槽名
    headerSlot: "header",
  },
];

const tableData: User[] = [
  //...
];

以上代码展示效果如下图所示:

输入搜索值之后,展示效果如下图所示:

示例7--自定义索引值

自定义索引值示例很简单,只需要配置列的index属性值为一个函数即可,代码如下:

const indexMethod = (index: number) => index * 2;
const column = [
  {
    type: "index",
    //主要是这里
    index: indexMethod,
  },
 //...
];
const tableData = [
    // ...
]

其余的没什么变化,html代码也很简单,如下所示:

<element-table :column="column" :data="tableData" style="width: 100%"></element-table>

以上代码展示效果如下图所示:

项目附件:点此下载

相关推荐
_Legend_King4 分钟前
vue3 + elementPlus 日期时间选择器禁用未来及过去时间
javascript·vue.js·elementui
爱吃青椒不爱吃西红柿‍️5 分钟前
华为ASP与CSP是什么?
服务器·前端·数据库
余生H6 分钟前
transformer.js(三):底层架构及性能优化指南
javascript·深度学习·架构·transformer
一棵开花的树,枝芽无限靠近你8 分钟前
【PPTist】添加PPT模版
前端·学习·编辑器·html
陈王卜11 分钟前
django+boostrap实现发布博客权限控制
java·前端·django
景天科技苑19 分钟前
【vue3+vite】新一代vue脚手架工具vite,助力前端开发更快捷更高效
前端·javascript·vue.js·vite·vue项目·脚手架工具
SameX21 分钟前
HarmonyOS Next 安全生态构建与展望
前端·harmonyos
石小石Orz28 分钟前
Three.js + AI:AI 算法生成 3D 萤火虫飞舞效果~
javascript·人工智能·算法
小行星12530 分钟前
前端预览pdf文件流
前端·javascript·vue.js
join831 分钟前
解决vue-pdf的签章不显示问题
javascript·vue.js·pdf