el-table二次封装

为了提高开发效率对el-table进行二次封装,其中包含分页功能和搜索功能,代码如下:

* Props:
 *  id:组件唯一标识
 *  columns: 列属性数组参数
 *    slotName: 自定义渲染列的插槽名称
 *       ${prop}_header: 表格自带header插槽命名方法
 *    indexFn(index, row): 索引自定义方法名称
 *    其他属性同element一致(https://element.eleme.cn/#/zh-CN/component/table)
 *  pagination: 分页配置参数
 *    size-change:size改变时查询数据,如果组件需要做查询之外的操作,传size-change方法
 *    current-change:同size-change
 *    其他参数同element一致
 *  onFetchData: 请求数据
-->
<template>
  <div :id="id" class="tvt-table">
    <!-- 组件属性透传 v-bind, v-on -->
    <el-table v-bind="$attrs" v-on="$listeners" :border="border" :class="[borderBottom ? '' : 'noBorder', customClass]">
      <template v-for="(column, index) in columns">
        <!--表格索引-->
        <el-table-column v-if="column.type === 'index'" :key="`${index}_${level}_index`" type="index" v-bind="column">
          <template slot-scope="scope">
            <span v-if="column.indexFn">{{ column.indexFn(scope.$index, scope) }}</span>
            <span v-else>{{ scope.$index + 1 }}</span>
          </template>
        </el-table-column>
        <el-table-column v-else-if="column.type === 'selection'" type="selection" :key="`${column.prop}_selection`" v-bind="column"></el-table-column>
        <el-table-column
          v-else
          :key="column.prop || column.key"
          v-bind="column"
        >
          <!--element-ui内置自定义表头-->
          <template v-slot:header="scope">
            <slot v-if="$scopedSlots[`${column.prop}_header`]" :name="`${column.prop}_header`" :column="scope.column"></slot>
            <span v-else>{{ column.label }}</span>
          </template>
          <!--自定义列-->
          <template v-slot="scope">
            <slot v-if="column.slotName" :name="column.slotName" :row="scope.row" :column="column" :$index="scope.$index" />
            <span v-else-if="column.valueEnum" :class="['tvt-dot-status', column.valueEnum[scope.row[column.prop]] ? `tvt-dot-status-${column.valueEnum[scope.row[column.prop]].status}` : '']">{{
              column.valueEnum[scope.row[column.prop]] ? column.valueEnum[scope.row[column.prop]].text ||
              column.valueEnum[scope.row[column.prop]] :
              ''
            }}</span>
            <span v-else>{{ scope.row[column.prop] }}</span>
          </template>
        </el-table-column>
      </template>
      <template v-slot:append>
        <slot v-if="$scopedSlots.append" name="append"></slot>
      </template>
    </el-table>
    <div class="tvt-pagination" v-if="paginationConf">
      <el-pagination
        @size-change="handleSizeChange"
        @current-change="handleCurrentChange"
        :page-size.sync="paginationConf.size"
        :current-page.sync="paginationConf.current"
        v-bind="paginationConf"
      >
      </el-pagination>
    </div>
  </div>
</template>

<script>
  export default {
    name: 'TvtTable',
    props: {
      id: {
        type: String,
        default: ''
      },
      columns: {
        type: Array,
        default: () => []
      },
      pagination: {
        type: Object
      },
      border: {
        type: Boolean,
        default: false
      },
      borderBottom: { // 表格水平border
        type: Boolean,
        default: false
      },
      level: { // 1 - 一级表格 2 - 二级表格
        type: String,
        default: ''
      },
      customClass: {
        type: String,
        default: ''
      },
      backToFirstPage: { // 切换size,是否需要回到第一页
        type: Boolean,
        default: true
      }
    },
    computed: {
      // 分页参数
      paginationConf: {
        // 合并props和内置默认配置
        set (val) {
          return val
        },
        get() {
          return this.pagination ? {
            ...this.defaultPagination,
            ...this.pagination
          } : false
        }
      }
    },
    mounted(){
    },
    data () {
      return {
        defaultPagination: {
          layout: "total, sizes, prev, pager, next, jumper",
          'page-sizes': [10, 20, 30, 40],
          size: 10,
          current: 1
        }
      }
    },
    methods: {
      handleSizeChange (size, page) {
        const onSizeChange = this.paginationConf['size-change']
        this.handleFetchData({
          size,
          current: this.backToFirstPage ? 1 : this.paginationConf.current
        })
        if (onSizeChange) onSizeChange(size)
      },
      handleCurrentChange (current) {
        const onPageChange = this.paginationConf['current-change']
        this.handleFetchData({
          current,
          size: this.paginationConf.size
        })
        if (onPageChange) onPageChange(current)
      },
      handleFetchData (cond) {
        const { total, size, current } = { ...this.paginationConf, ...cond }
        if (total && (current - 1) * size > total) {
          return false
        }
        this.$emit('onFetchData', cond)
      }
    }
  }
</script>

<style lang="scss" scoped>
.tvt-table {
  .noBorder >>> td.el-table__cell {
    border-bottom: 0
  }
  .noBorder.el-table::before {
    height: 0;
  }
  .tvt-pagination {
    padding: 10px 0;
    text-align: right;
  }
  >>> .header-class {
    background: #e4e4e4;
    th.el-table__cell {
      background-color: #e4e4e4
    }
  }
  .tvt-dot-status {
    position: relative;
    display: inline-block;
    &::before {
      content: '';
      position: absolute;
      width: 6px;
      height: 6px;
      border-radius: 50%;
      top: 50%;
      -webkit-transform: translateY(-50%);
      transform: translateY(-50%);
      left: 0;
    }
  }
  .tvt-dot-status-success,
  .tvt-dot-status-error,
  .tvt-dot-status-default {
    padding-left: 10px;
  }
  .tvt-dot-status-default::before {
    background: #909399;
  }
  .tvt-dot-status-success::before {
    background: #67c23a;
  }
  .tvt-dot-status-error::before {
    background: #f56c6c;
  }
}
</style>

表格组件封装好后,具体的使用如下:

 <template>
          <tvt-table
            v-loading="tableLoading"
            ref="tvtTableRef"
            :data="list"
            :columns="columns"
            height="350"
            header-row-class-name="header-class"
            :filterCond="filterCond"
            :pagination="{
              total: total,
              current: filterCond.current,
              size: filterCond.size,
              background: true
            }"
            @onFetchData="handleQueryData"
            @selection-change="handleSelectionChange"
            style="width: 100%"
          >
            <!--可操作表头-->
            <template #number_header>
              <el-select v-model="value" placeholder="请选择">
                <el-option
                  v-for="item in options"
                  :key="item.value"
                  :label="item.label"
                  :value="item.value">
                </el-option>
              </el-select>
            </template>
            <!--自定义列插槽-->
            <!--可编辑列-->
            <template #bodyCell="{row, column }">
              <template v-if="column.key === "operation"">
                <el-button type="primary" size="mini" @click="handleTest(row)">编辑</el-button>
                <el-button type="danger" size="mini" @click="handleDelete(row)">删除</el-button>
              </template>
            </template>
          </tvt-table>
        </template>
        <script>
          export default {
            data () {
              list: [],
              tableLoading: false,
              columns: [{ label: "序号", type: "index" },
                { label: "站点名称", prop: "name", sortable: true },
                { label: "类型", prop: "type", valueEnum: {1: "IPC", 2: "NVR"} },
                { label: "位置", prop: "position" },
                { label: "联系方式", prop: "mobile" },
                { label: "input", prop: "number", slotName: "bodyCell" },
                { label: "operation", key: "operation", slotName: "bodyCell" }],
              filterCond: {
                search: "",
                current: 1,
                size: 10
              },
              value: "",
              options: [
                { value: "选项1", label: "黄金糕" },
                { value: "选项2", label: "双皮奶" }
              ],
            },
            methods: {
              handleQueryData () {},
              handleDelete() {},
              handleTest() {},
              handleSelectionChange() {}
            }
          }
        </script>

最后一起来看一下页面效果吧

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值