Skip to content

基于 Vue3、Element Plus 开发的一款表格组件,对Element Plus的el-table进行二次封装

Notifications You must be signed in to change notification settings

qdleader/element-plus-table

Repository files navigation

基于 Vue3、Element Plus 开发的一款表格组件,对 Element Plus 的 el-table 进行二次封装

只需要,传如columns,和接口即可把后台的表单搜索项,列表,及分页渲染出了,并支持自定义内容,可以提高开发效率30%左右。

TablePlus 组件上的绑定的所有属性和事件都会通过 v-bind="$attrs" 透传到 el-table 上。 TablePlus 组件内部暴露了 el-table DOM,可通过 TablePlus.value.element.方法名 调用其方法 也就是说你想使用 el-table 的任何属性、事件,目前通过属性透传都能支持。

安装

npm install element-plus-table -S

项目中引入

import { createApp } from 'vue'
import App from './App.vue'
import TablePlus from "element-plus-table"

const app = createApp(App);

app.use(TablePlus)

app.mount('#app')

在项目中使用入门案例

<template>
  <TablePlus
    ref="tablePlus"
    title="列表"
    :columns="columns"
    :request-api="getTableList"
    row-key="articleId"
  ></TablePlus>
</template>

<script setup lang="tsx">
import { ref } from "vue"
const rowItem = {
  articleId: 0,
  title: "文章标题",
  origin: 1,
  publishTime: "2024-09-01 12:00:00",
  publishStatus: 2
}
type rowItemType = typeof rowItem
interface paramsReq {
  pageSize: number
  pageNum: number
}
const tablePlus = ref()
// 模拟获取列表接口
const articleList = (params: paramsReq) => {
  return new Promise((resolve) => {
    const entities: rowItemType[] = []
    for (let i = 0; i < 10; i++) {
      entities.push({
        articleId: i,
        title: "文章标题" + i,
        origin: 1,
        publishTime: "2024-09-01 12:00:00",
        publishStatus: 2
      })
    }
    const ressult = {
      total: 100,
      pageNum: params.pageNum,
      pageSize: params.pageSize,
      list: entities
    }
    setTimeout(() => {
      resolve(ressult)
    }, 1500)
  })
}
const getTableList = (params: paramsReq) => {
  const newParams = JSON.parse(JSON.stringify(params))
  // 请求前参数可以在这里处理
  return articleList(newParams)
}

// 表格配置项
const columns = [
  { type: "index", label: "序号", width: 80 },
  {
    prop: "title",
    label: "文章标题0"
  },
  {
    prop: "title",
    label: "文章标题1",
    search: {
      el: "input",
      props: { maxlength: 30, placeholder: "请输入文章标题1" }
    }
  }
]
</script>

稍微复杂点案例

<template>
  <TablePlus
    ref="tablePlus"
    title="列表"
    :columns="columns"
    :request-api="getTableList"
    :init-param="initParam"
    :pagination="true"
    :data-callback="dataCallback"
    :reset-callback="resetCallback"
    row-key="articleId"
  >
    <!-- 表格 header 按钮 -->
    <template #tableHeader="scope">
      <el-button type="primary" :icon="CirclePlus" class="mb10">新建</el-button>
      <el-button
        type="primary"
        plain
        :disabled="!scope.isSelected"
        class="mb10"
        @click="batchPublish(scope.selectedListIds, 2)"
      >
        批量发布
      </el-button>
      <el-button
        type="danger"
        :icon="Delete"
        plain
        :disabled="!scope.isSelected"
        class="mb10"
        @click="batchDelete(scope.selectedListIds)"
      >
        批量删除
      </el-button>
    </template>
    <!-- 表格操作 -->
    <template #operation="scope">
      <el-button
        type="primary"
        link
        :icon="EditPen"
        @click="openDrawerEdit(scope.row)"
      >
        编辑
      </el-button>
      <el-button type="primary" link :icon="Delete">删除</el-button>
    </template>
  </TablePlus>
</template>

<script setup lang="tsx">
import { ref, reactive } from "vue"
import { CirclePlus, Delete, EditPen } from "@element-plus/icons-vue"
const rowItem = {
  articleId: 0,
  title: "文章标题",
  origin: 1,
  publishTime: "2024-09-01 12:00:00",
  publishStatus: 2
}
type rowItemType = typeof rowItem
interface paramsReq {
  pageSize: number
  pageNum: number
}
const tablePlus = ref()
const initParam = reactive({
  type: "yyy",
  pageSize: 10,
  hotWordList: []
})
// 模拟获取列表接口
const articleList = (params: paramsReq) => {
  return new Promise((resolve) => {
    const entities: rowItemType[] = []
    for (let i = 0; i < 10; i++) {
      entities.push({
        articleId: i,
        title: "文章标题" + i,
        origin: 1,
        publishTime: "2024-09-01 12:00:00",
        publishStatus: 2
      })
    }
    const ressult = {
      total: 100,
      pageNo: params.pageNum,
      pageSize: params.pageSize,
      entities
    }
    setTimeout(() => {
      resolve(ressult)
    }, 1500)
  })
}
const dataCallback = (data: any) => {
  data?.entities.forEach((item: any) => {
    item.mechanismValue = [item.category, item.column]
  })
  return {
    list: data?.entities,
    total: data.total,
    pageNum: data.pageNo,
    pageSize: data.pageSize
  }
}
const getTableList = (params: paramsReq) => {
  const newParams = JSON.parse(JSON.stringify(params))
  // 请求前参数可以在这里处理
  return articleList(newParams)
}
// 批量删除用户信息
const batchDelete = async (articleIds: string[]) => {
  console.log("articleIds", articleIds)
  // await fetchAPI()
  tablePlus.value?.clearSelection()
  tablePlus.value?.getTableList()
}
const batchPublish = async (articleIds: string[], status: number) => {
  console.log("articleIds: string[], status: number", articleIds, status)
  // await fetchAPI()
  tablePlus.value?.clearSelection()
  tablePlus.value?.getTableList()
}
// 表格配置项
const columns = [
  { type: "selection", fixed: "left", width: 80 },
  { type: "index", label: "序号", width: 80 },
  {
    prop: "title",
    label: "文章标题0"
  },
  {
    prop: "title",
    label: "文章标题",
    search: {
      el: "input",
      props: { maxlength: 30, placeholder: "请输入文章标题" }
    }
  },
  {
    prop: "title",
    label: "文章标题2",
    search: {
      el: "input",
      order: 10,
      props: { maxlength: 30, placeholder: "请输入文章标题2" }
    }
  },
  {
    prop: "title",
    label: "文章标题3",
    isShow: false,
    search: {
      el: "input",
      order: 1,
      props: { placeholder: "请输入文章标题3" }
    }
  },
  {
    prop: "origin",
    label: "数据来源",
    width: 160,
    enum: [
      {
        label: "文章库",
        value: 1
      },
      {
        label: "自建新增 ",
        value: 2
      }
    ],
    search: { el: "tree-select", props: { filterable: true } }
  },

  {
    prop: "publishTime",
    label: "发布时间",
    width: 180,
    render: (scope) => {
      return <div>{scope.row.publishTime || "- -"}</div>
    }
  },

  {
    prop: "publishStatus",
    label: "是否发布",
    width: 160,
    enum: [
      {
        label: "已发布",
        value: 2
      },
      {
        label: "未发布",
        value: 1
      }
    ],
    search: { el: "tree-select", props: { filterable: true } },
    render: (scope) => {
      return (
        <>
          <el-switch
            model-value={scope.row.publishStatus}
            active-text={scope.row.publishStatus === 2 ? "已发布" : "未发布"}
            active-value={2}
            inactive-value={1}
            onClick={doPublish}
          />
        </>
      )
    }
  },
  { prop: "operation", label: "操作", fixed: "right", width: 200 }
]
const resetCallback = () => {
  console.log("resetCallBack")
  initParam.hotWordList = []
  tablePlus.value?.getTableList()
}
// 上架
const doPublish = async (params: any) => {
  console.log("doPublish", params)
  // await fetchAPI()
  tablePlus.value?.getTableList()
}
const openDrawerEdit = async (row: Partial<any>) => {
  console.log(row)
}
</script>
<style scoped>
.mb10 {
  margin-bottom: 10px;
}
</style>

表格中每一项都可以都可以通过render可使用 tsx 组件自定义渲染

<script setup lang="tsx">
const columns = reactive<ColumnProps<User.ResUserList>[]>([{
    prop: "publishTime",
    label: "发布时间",
    width: 180,
    render: (scope) => {
      return <span>{scope.row.publishTime || "- -"}</span>
    }
  },
];
</script>

表格搜索项可使用 tsx 组件自定义渲染

<script setup lang="tsx">
const columns = reactive<ColumnProps<User.ResUserList>[]>([
   {
    prop: "score",
    label: "分数",
    search: {
      // 自定义 search 组件
      render: ({ searchParam }) => {
        return (
          <div>
            <el-input vModel_trim={searchParam.minAge} placeholder="最小分数"/>
            <span>-</span>
            <el-input vModel_trim={searchParam.maxAge} placeholder="最大分数" />
          </div>
        );
      }
    }
  },
];
</script>

也就是说search 表单组件我们 可以自定义任意组件放上面,并且可以在请求发出前,对参数进行特殊处理

TablePlus 属性

参数 类型 是否必填 默认值 描述
columns ColumnProps [] TablePlus 组件会根据此字段渲染搜索表单与表格列(支持动态更新)
request-api Function - 获取表格数据的请求 API
data Array - 静态 tableData 数据(支持分页),若存在则不会使用 request-api 返回的 data
data-callback Function - 后台返回数据的回调函数,可对后台返回数据进行处理
reset-callback Function - 用户点击重置按钮的回调函数,可对搜索表单进行参数进行特殊处理
pagination Boolean - 是否显示分页组件:pagination 为 false 后台返回数据应该没有分页信息 和 list 字段,data 就是 list 数据
initParam Object {} 表格请求的初始化参数,该值变化会重新请求表格数据
rowKey String 'id' 当表格数据多选时,所指定的 id
tableSearchColumns ColumnProps [] TablePlus 组件会根据此字段渲染搜索表单支持动态更新)有这个参数后就会上面表单就会用这个参数去渲染
request-error Function - 表格 API 请求错误监听|

Column 配置(ColumnProps 属性)

参数 类型 是否必填 默认值 描述
type String - 对应列的类型("index"
tag Boolean false 前单元格值是否为标签展示,可通过 enum 数据中 tagType 字段指定 tag 类型
isShow Boolean true 当前列是否显示在表格内(只对 prop 列生效)
search SearchProps - 搜索项配置,详情见 SearchProps
enum Array Function -
fieldNames Object - 指定 label && value && children 的 key 值
headerRender Function - 自定义表头内容渲染(tsx 语法、h 语法)
render Function - 自定义表头内容渲染(tsx 语法、h 语法)

搜索项 配置(SearchProps):

参数 类型 是否必填 默认值 描述
el String - 当前项搜索框的类型,支持:input、input-number、select、select-v2、tree-select、cascader、date-picker、time-picker、time-select、switch、slider)
labelString String - 当搜索项 label,如果不指定默认取 column 的 label
props Object - 根据 element plus 官方文档来传递,通过属性透传将 search.props 属性全部透传到每一项搜索组件上,所以我们支持 input、select、tree-select、date-packer、time-picker、time-select、switch 大部分属性
key String - 当搜索项 key 不为 prop 属性时,可通过 key 指定
order Number - 搜索项排序(从小到大)
key String - 当搜索项 key 不为 prop 属性时,可通过 key 指定
defaultValue Any - 搜索项默认值(该值重置时会重置回初始值)
render Function - 自定义搜索内容渲染(tsx 语法、h 语法)

TablePlus 的方法:

参数 描述
element el-table 实例,可以通过TablePlus.value.element.***()来调用 el-table 的所有方法)
getTableList 获取、刷新表格数据的方法(携带所有参数)
tableData 当前页面所展示的数据
pageable 当前表格的分页数据
searchParam 所有的搜索参数,不包含分页
searchInitParam 所有的搜索初始化默认的参数
search 表格查询方法,相当于点击搜索按钮
reset 重置表格查询参数,相当于点击重置按钮
handleSizeChange 表格每页条数改变触发的事件
handleCurrentChange 表格当前页改变触发的事件
clearSelection 清空表格所选择的数据
enumMap 当前表格使用的所有字典数据(Map 数据结构)
isSelected 表格是否选中数据
selectedList 表格选中的数据列表
selectedListIds 表格选中的数据列表的id

如 在组件中 tablePlus.value?.getTableList() 即可获取最新列表数据

TablePlus 插槽:

插槽 描述
tableHeader 自定义表格头部左侧区域的插槽,一般情况该区域放操作按钮
toolButton 自定义表格头部左右侧侧功能区域的插槽
empty 当表格数据为空时自定义的内容
pagination 分页组件插槽

About

基于 Vue3、Element Plus 开发的一款表格组件,对Element Plus的el-table进行二次封装

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published