封装一个elementui的table组件

如何封装Table组件

由于最近在写一个测试网站,很多页面都需要用到表格,就做了一个表格封装的(根据自己需要的功能,仅列出部分)

以下两个表格用了同一个组件
表一功能:可模糊查询、多选、分页、跳转详情
在这里插入图片描述
表二:标签、分页、表内文字样式不一样
在这里插入图片描述

父组件

需要在父组件定义好数据之后传到子组件中:

  <Table
        :tableData="cpSchool || []"
        :config="config"
        :tableLabel="tableLabel"
      ></Table>

表格内容形式:

  tableLabel: [
        {
          prop: "_id", //prop
          label: "编号", //label
          type: "common", //种类
          class: null, //额外样式
          scope: false, //template
          scopeLabel: null, //template里面用的模板
        },
        {
          prop: "label", //prop
          label: "学校名称", //label
          type: "div", //种类
          method: "SMDeatil",
          className: "label", //额外样式
          scope: true, //template
          scopeLabel: "div", //template里面用的模板
        },
        {
          prop: "level", //prop
          label: "学校类别", //label
          type: "common", //种类
          class: null, //额外样式
          scope: false, //template
          scopeLabel: null, //template里面用的模板
        },
        {
          prop: "review", //prop
          label: "状态", //label
          type: "el-tag", //种类
          class: null, //额外样式
          scope: true, //template
          scopeLabel: "el-tag", //template里面用的模板
          scopeLabelName: ["已认证", "待审核"],
          scopeLabelType: ["primary", "warning"],
        },
        {
          fixed: "right",
          label: "操作", //label
          type: "el-button", //种类
          class: null, //额外样式
          scope: true, //template
          scopeLabel: "fixed", //template里面用的模板
          scopeLabelName: "年级班级设置",
        },
      ],

配置:选择是否分页、模糊搜索功能、多选

      config: {
        paging: true, //开启分页
        curPage: 1, // 当前页码,可选
        pageSize: 1, //每页的数据条数,可选
        search: false, //开启查询功能
        selection: false, //多选开启
      },

子组件

在子组件的props中接收父组件传过来的数据

 props: {
    tableData: {
      type: [Array, Object],
      required: true,
    },
    tableLabel: {
      type: [Array, Object],
      required: true,
    },
    config: {
      type: [Object],
      required: false,
    },
    search: {
      type: [String],
      required: false,
    },
  },

表头配置会稍微复杂一点,因为没办法更改props中的数据,所以我就直接将数据过滤的处理写在了表头内
给data赋值的情况有4种:1.同时开启搜索和分页 2.只开启搜索 3.只开启分页 4.不做任何过滤
2.搜索过滤

tableData.filter(
                (data) =>
                  !search ||
                  data[config.searchName[0]]
                    .toLowerCase()
                    .includes(search.toLowerCase()) ||
                  data[config.searchName[1]]
                    .toLowerCase()
                    .includes(search.toLowerCase())
              )

3.分页的过滤是

tableData.slice(
                (config.curPage - 1) * config.pageSize,
                config.curPage * config.pageSize
              )

结合一下就是以下形式:

  <el-table
        :data="
          config.search && config.paging
            ? tableData
                .filter(
                  (data) =>
                    !search ||
                    data[config.searchName[0]]
                      .toLowerCase()
                      .includes(search.toLowerCase()) ||
                    data[config.searchName[1]]
                      .toLowerCase()
                      .includes(search.toLowerCase())
                )
                .slice(
                  (config.curPage - 1) * config.pageSize,
                  config.curPage * config.pageSize
                )
            : config.search
            ? tableData.filter(
                (data) =>
                  !search ||
                  data[config.searchName[0]]
                    .toLowerCase()
                    .includes(search.toLowerCase()) ||
                  data[config.searchName[1]]
                    .toLowerCase()
                    .includes(search.toLowerCase())
              )
            : config.paging
            ? tableData.slice(
                (config.curPage - 1) * config.pageSize,
                config.curPage * config.pageSize
              )
            : tableData
        "
        border
        ref="multipleTable"
        @selection-change="handleSelectionChange"
        :cell-style="{ 'text-align': 'center', padding: '8px 0px' }"
        :header-cell-style="{
          background: '#f5f7fa',
          'text-align': 'center',
        }"
        tooltip-effect="dark"
        style="width: 100%"
      >

行内配置:这里只配置了几种类型(普通、更改表格内容样式(需要将className传过来并且提前在组件写好样式)、根据不同字段显示不同的el-tag、操作)

  <el-table-column v-if="config.selection" type="selection" width="55">
        </el-table-column>
        <template v-for="(column, i) in tableLabel">
          <!-- 普通类型 -->
          <el-table-column
            v-if="column.type === 'common'"
            :prop="column.prop"
            :label="column.label"
            :key="i"
          >
          </el-table-column>
          <!-- template里为div的,可加样式 -->
          <el-table-column
            v-if="column.scopeLabel === 'div'"
            :prop="column.prop"
            :label="column.label"
            :key="i"
          >
            <template slot-scope="scope">
              <div
                :class="column.className"
                @click="bindMethod(column.method, scope.row)"
              >
                {{ scope.row[column.prop] }}
              </div>
            </template>
          </el-table-column>
          <!-- template里为el-tag -->
          <el-table-column
            v-if="column.scopeLabel === 'el-tag'"
            :prop="column.prop"
            :label="column.label"
            :key="i"
          >
            <template slot-scope="scope">
              <el-tag
                :type="
                  scope.row[column.prop]
                    ? column.scopeLabelType[0]
                    : column.scopeLabelType[1]
                "
                disable-transitions
              >
                {{
                  scope.row[column.prop]
                    ? column.scopeLabelName[0]
                    : column.scopeLabelName[1]
                }}
              </el-tag>
            </template>
          </el-table-column>
          <el-table-column
            v-if="column.label === '操作'"
            :label="column.label"
            :key="i"
            :fixed="column.fixed"
          >
            <template slot-scope="scope">
              <el-button
                type="text"
                size="small"
                @click="operation(scope.$index, scope.row)"
                >{{ column.scopeLabelName }}</el-button
              >
            </template>
          </el-table-column>
        </template>

动态绑定方法

可以给每一行添加一个你想要的方法,首先将方法名从数据中传递过来,接着在子组件中定义一个方法,这个方法接收这个父组件传过来的参数,例如以下的bindMethod接收了传递过来的参数

  <el-table-column
            v-if="column.scopeLabel === 'div'"
            :prop="column.prop"
            :label="column.label"
            :key="i"
          >
            <template slot-scope="scope">
              <div
                :class="column.className"
                @click="bindMethod(column.method, scope.row)"
              >
                {{ scope.row[column.prop] }}
              </div>
            </template>
          </el-table-column>
    bindMethod(methodName, row) {
      this[methodName](row);
    },

子组件调用父组件的方法并且传值

  1. 非常方便的一个方法
  2. 子组件方法SMDeatil,通过this. p a r e n t 调 用 父 组 件 的 方 法 并 且 传 参 , 但 是 要 注 意 t h i s . parent调用父组件的方法并且传参,但是要注意this. parentthis.parent并不是该组件的父组件,而是 Element ui 的组件
    SMDeatil(row) {
      this.$parent.pSMDeatil(row);
    },

当你在父组件引用子组件的时候还在外面套了多层 UI 组件导致报错
TypeError:this.parent.xxx is not a function
例如以下就会报错

			<el-tabs v-model="activeName" @tab-click="handleClick">
				<Table></Table>
 				</el-tabs>

这样写不会报错

<div>
 	<Table></Table>	 
</div>
  • 5
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
ElementUItable 组件提供了非常丰富的功能和接口,但是在实际项目中,我们经常需要对其进行二次封装,以满足自己的业务需求。下面是一个简单的 ElementUI table 的二次封装示例: ```vue <template> <el-table :data="tableData" :height="height" :max-height="maxHeight" :stripe="stripe" :border="border" :fit="fit" :show-header="showHeader" :highlight-current-row="highlightCurrentRow" :row-class-name="rowClassName" :row-style="rowStyle" :cell-class-name="cellClassName" :cell-style="cellStyle" :header-row-class-name="headerRowClassName" :header-row-style="headerRowStyle" :header-cell-class-name="headerCellClassName" :header-cell-style="headerCellStyle" :row-key="rowKey" @select="handleSelect" @select-all="handleSelectAll" @selection-change="handleSelectionChange" @cell-mouse-enter="handleCellMouseEnter" @cell-mouse-leave="handleCellMouseLeave" @cell-click="handleCellClick" @cell-dblclick="handleCellDblClick" @row-click="handleRowClick" @row-contextmenu="handleRowContextMenu" @row-dblclick="handleRowDblClick" @header-click="handleHeaderClick" @header-contextmenu="handleHeaderContextMenu" @sort-change="handleSortChange" @filter-change="handleFilterChange" > <slot></slot> </el-table> </template> <script> export default { name: "MyTable", props: { tableData: { type: Array, default: () => [] }, height: { type: [Number, String], default: "" }, maxHeight: { type: [Number, String], default: "" }, stripe: { type: Boolean, default: true }, border: { type: Boolean, default: true }, fit: { type: Boolean, default: true }, showHeader: { type: Boolean, default: true }, highlightCurrentRow: { type: Boolean, default: true }, rowClassName: { type: Function, default: () => undefined }, rowStyle: { type: Function, default: () => undefined }, cellClassName: { type: Function, default: () => undefined }, cellStyle: { type: Function, default: () => undefined }, headerRowClassName: { type: Function, default: () => undefined }, headerRowStyle: { type: Function, default: () => undefined }, headerCellClassName: { type: Function, default: () => undefined }, headerCellStyle: { type: Function, default: () => undefined }, rowKey: { type: [String, Function], default: "" } }, methods: { handleSelect(selection, row) { this.$emit("select", selection, row); }, handleSelectAll(selection) { this.$emit("select-all", selection); }, handleSelectionChange(selection) { this.$emit("selection-change", selection); }, handleCellMouseEnter(row, column, cell, event) { this.$emit("cell-mouse-enter", row, column, cell, event); }, handleCellMouseLeave(row, column, cell, event) { this.$emit("cell-mouse-leave", row, column, cell, event); }, handleCellClick(row, column, cell, event) { this.$emit("cell-click", row, column, cell, event); }, handleCellDblClick(row, column, cell, event) { this.$emit("cell-dblclick", row, column, cell, event); }, handleRowClick(row, event, column) { this.$emit("row-click", row, event, column); }, handleRowContextMenu(row, event) { this.$emit("row-contextmenu", row, event); }, handleRowDblClick(row, event) { this.$emit("row-dblclick", row, event); }, handleHeaderClick(column, event) { this.$emit("header-click", column, event); }, handleHeaderContextMenu(column, event) { this.$emit("header-contextmenu", column, event); }, handleSortChange({ column, prop, order }) { this.$emit("sort-change", { column, prop, order }); }, handleFilterChange(filters) { this.$emit("filter-change", filters); } } }; </script> ``` 这里我们定义了一个名为 `MyTable` 的组件,并将其 props 与 ElementUI table 组件的 props 一一对应。在组件的模板中,我们使用了 `<slot></slot>`,表示组件的插槽,这样可以让用户在使用组件时自定义表格的列和内容。在组件的方法中,我们将 ElementUI table 的事件通过 `$emit` 的方式向上传递,这样可以使得组件的使用更加灵活。 使用这个组件时,我们只需要在父组件中引入 `MyTable` 组件,并将需要的 props 和插槽传入即可: ```vue <template> <my-table :table-data="tableData" :stripe="false" :highlight-current-row="false" @row-click="handleRowClick" > <el-table-column label="姓名" prop="name"></el-table-column> <el-table-column label="年龄" prop="age"></el-table-column> <el-table-column label="地址" prop="address"></el-table-column> </my-table> </template> <script> import MyTable from "@/components/MyTable"; export default { name: "MyPage", components: { MyTable }, data() { return { tableData: [ { name: "张三", age: 18, address: "北京市" }, { name: "李四", age: 20, address: "上海市" }, { name: "王五", age: 22, address: "广州市" } ] }; }, methods: { handleRowClick(row) { console.log(row); } } }; </script> ``` 这样,我们就完成了一个简单的 ElementUI table 的二次封装,并且可以在父组件中灵活使用。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值