根据element-ui封装属于自己的组件库之公用table组件

平时在开发中,会经常使用到element-ui等类似的UI组件库,而在业务开发中,经常会调用一些组件,如table组件,于是就想,可不可以将其封装起来,方便自己调用呢,于是说干就干。

封装的这个组件要有以下功能:

  • 首先想的是封装的这个组件要完全覆盖element-ui组件table原生的功能。
  • 不仅支持prop方式去渲染表格列,也支持render方式渲染。
  • 支持分页

于是,为了实现自己的这个想法,就利用vue-cli 3.0脚手架,搭建了一个项目工程,取名为vue-table
然后在components目录下新建一个BaseTable的目录,用来存放我们的这个公共table组件。
BaseTable目录下有两个文件index.vue, tableConfig.js
index.vue:处理table组件的相关逻辑。
tableConfig.js: 放置table组件一些默认的配置项。

这里用到vue2.4所提到的$attrs, $listeners两个属性,来简化代码。

index.vue的代码如下:

<template>
  <div v-bind="$attrs" class="base-table">
    <slot name="title"/>
    <slot/>
    <el-table
      :data="data"
      :ref="$attrs.ref"
      v-bind="tableAttrs"
      style="width: 100%"
      v-on="$listeners"
    >
      <div
        v-for="(col, index) in columnAttrs"
        :key="index"
      >
        <el-table-column
          v-if="!col.render"
          v-bind="col"
        />
        <el-table-column
          v-else
          v-bind="col"
        >
          <template slot-scope="scope">
            <expandDom
              :row="scope.row"
              :col="col"
              :render="col.render"
              :col-index="index"
            />
          </template>
        </el-table-column>

      </div>
    </el-table>
    <el-pagination
      v-if="paginationAttrs.isPagination"
      v-bind="paginationAttrs"
      class="pagination-container"
      @size-change="handleSizeChange"
      @current-change="handleCurrentChange"
    />
  </div>
</template>
<script>
import {
  defaultTableAttrs,
  defaultColumn,
  defaultPagination
} from './tableConfig'
export default {
  name: 'BaseTable',
  components: {
    expandDom: {
      functional: true,
      props: {
        row: Object,
        col: Object,
        render: Function,
        colIndex: [Number, String]
      },
      render(h, ctx) {
        const randomIndex = Math.random().toString(35).replace('.', '')
        const params = {
          row: { ...ctx.props.row },
          colIndex: ctx.props.colIndex || randomIndex
        }
        if (ctx.props.col) {
          params.col = ctx.props.col
        }
        return ctx.props.render && ctx.props.render(h, params)
      }
    }
  },
  props: {
    data: {
      type: Array,
      default() {
        return []
      }
    },
    columns: {
      type: Array,
      default() {
        return []
      }
    },
    // eslint-disable-next-line vue/require-default-prop
    pagination: {
      type: [Object, Boolean]
    }

  },
  data() {
    return {
      tableAttrs: {},
      columnAttrs: [],
      paginationAttrs: {}
    }
  },
  watch: {
    pagination: {
      handler(val) {
        this.getPagination()
      },
      deep: true
    }
  },
  created() {
    this.$nextTick(() => {
      this.init()
    })
  },
  methods: {
    init() {
      // 获取element table上的属性
      const tableAttrs = { }
      Object.keys(defaultTableAttrs).forEach(key => {
        if (this.$attrs[key] !== undefined) {
          tableAttrs[key] = this.$attrs[key]
        }
      })
      this.tableAttrs = Object.assign({}, defaultTableAttrs, tableAttrs)

      // 获取element table col上的属性
      this.columnAttrs = this.columns.map(column => {
        const obj = Object.assign({}, defaultColumn, column)
        return obj
      })
    },
    getPagination() {
      // 获取element 分页属性
      const pagination = this.pagination
      let paginationAttrs = {}
      if (pagination) {
        if (typeof pagination === 'object') {
          paginationAttrs = {
            ...defaultPagination,
            ...pagination,
            isPagination: true
          }
        } else {
          paginationAttrs = {
            ...defaultPagination,
            isPagination: true
          }
        }
      }
      Object.keys(paginationAttrs).forEach(key => {
        if (this.$attrs[key] !== undefined && key !== 'pagination') {
          paginationAttrs[key] = this.$attrs[key]
        }
      })
      this.paginationAttrs = paginationAttrs
    },
    handleSizeChange(pageSize) {
      this.$emit('size-change', pageSize)
    },
    handleCurrentChange(page) {
      this.$emit('current-change', page)
    }
  }
}
</script>
<style lang="scss" scoped>
.pagination-container{
  margin-top: 10px;
  text-align: right;
}
</style>



tableConfig.js代码如下:

export const defaultTableAttrs = {
  data: null,
  height: null,
  "max-height": null,
  stripe: false,
  border: false,
  size: null,
  fit: true,
  "show-header": true,
  "highlight-current-row": false,
  "current-row-key": null,
  "row-class-name": null,
  "row-style": null,
  "cell-class-name": null,
  "cell-style": null,
  "header-row-class-name": null,
  "header-row-style": null,
  "header-cell-class-name": null,
  "header-cell-style": null,
  "row-key": null,
  "empty-text": "暂无数据",
  "default-expand-all": false,
  "expand-row-keys": null,
  "default-sort": null,
  "tooltip-effect": null,
  "show-summary": false,
  "sum-text": "合计",
  "summary-method": null,
  "span-method": null,
  "select-on-indeterminate": true,
  indent: 16,
  lazy: null,
  load: null,
  "tree-props": { hasChildren: "hasChildren", children: "children" }
};

export const defaultColumn = {
  type: null,
  index: null,
  "column-key": null,
  label: null,
  prop: null,
  width: null,
  "min-width": null,
  fixed: null,
  "render-header": null,
  sortable: false,
  "sort-method": null,
  "sort-by": null,
  "sort-orders": ["ascending", "descending", null],
  resizable: true,
  formatter: null,
  "show-overflow-tooltip": false,
  align: "left",
  "header-align": null,
  "class-name": null,
  "label-class-name": null,
  selectable: null,
  "reserve-selection": false,
  filters: null,
  "filter-placement": null,
  "filter-multiple": true,
  "filter-method": null,
  "filtered-value": null
};

export const defaultPagination = {
  pageSize: 10,
  currentPage: 1,
  total: 0,
  layout: "total, sizes, prev, pager, next, jumper"
};

这样,就大功告成啦,于是去试试吧

<template>
  <div class="home">
    <BaseTable :data="tableData" :columns="columns" :height="300"></BaseTable>
  </div>
</template>

<script>
// @ is an alias to /src

export default {
  name: "home",
  components: {
    BaseTable: () => import("@/components/BaseTable")
  },
  data() {
    return {
      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 弄"
        }
      ],
      columns: [
        {
          prop: "name",
          label: "姓名"
        },
        {
          prop: "date",
          label: "日期"
        },
        {
          prop: "address",
          label: "地址",
          sortable: true,
          render(h, params) {
            console.log(params);
            return h("el-tag", {}, "哈哈");
          }
        }
      ]
    };
  }
};
</script>

最终页面显现效果如下:
在这里插入图片描述
非常nice,喜欢的朋友记得收藏呀!

评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值