基於 antd 風格的 element-table + pagination 的二次封裝

前言

本次封裝基於 antd 風格, 實現高度可配置的表格封裝配置。原本想經過 vue.extends 去封裝的,奈何幾個月沒寫過 vue ,並且對 vueextends 不熟悉因此放棄了...javascript

以前有小夥伴確實引用了個人代碼,發現封裝出現了一些紕漏,對此十分抱歉,以前封裝的太倉促了。幾個月前的代碼,如今從新封裝又有了新的體會。css

更新時間 【2018.11.09】,效果以下:html

API 說明

  • columns : 必選, 列描述數據對象, Array
  • dataSource : 必選, 數據數組
  • options : 必選, 表格參數控制, maxHeight、stripe 等等..
  • fetch : 獲取數據的 Function
  • pagination : 分頁信息,不傳則不顯示分頁
  • row-click :當某一行被點擊時會觸發該事件
  • selection-change : 當選擇項發生變化時會觸發該事件
  • 其餘的 api 能夠自行添加

其餘說明我在代碼註釋中寫的很清楚了,請自行查看。vue

根據條件渲染: 只經過 render 去判斷參數不一樣而渲染不同的表格數據。 render 函數能夠渲染任何你想要的組件java

值得注意的是,this 對象的綁定不要出錯了,若是須要更多加強的功能,各位能夠自行添加...react

Home.vue 組件

<template>
    <div>
      <h2>Home</h2>
      <CommonTable :columns="columns" :dataSource="tableData" :options="options" :fetch="fetchTableData" :pagination="pagination" @row-click="handleRowClick" @selection-change="handleSelectionChange" />
    </div>
</template>

<script> import axios from 'axios' import CommonTable from '../components/Table' export default{ components:{ CommonTable }, data(){ return { columns: [ { prop: 'id', label: '編號', width: 60 }, { prop: 'title', label: '標題', // render 能夠根據你想要渲染的方式渲染 // jsx 不提供 v-model 指令,若你想要使用,,推薦使用插件 babel-plugin-jsx-v-model // jsx https://github.com/vuejs/babel-plugin-transform-vue-jsx render: (row, index) => { return ( <span style="color: blue" onClick={e => this.handleClick(e, row)}>{row.title}</span> ) } }, { prop: 'author', label: '做者' }, { button: true, label: '按鈕組', group: [{ // you can props => type size icon disabled plain name: '編輯', type: 'warning', icon: 'el-icon-edit', plain: true, onClick: (row, index) => { // 箭頭函數寫法的 this 表明 Vue 實例  console.log(row, index) } }, { name: '刪除', type: 'danger', icon: 'el-icon-delete', disabled: false, onClick(row) { // 這種寫法的 this 表明 group 裏的對象 this.disabled = true console.log(this) } }] } ], tableData: [ { id: 1, title: '標題1', author: '郭大大' }, { id: 2, title: '標題2', author: '郭大大2' } ], pagination: { total: 0, pageIndex: 1, pageSize: 15 }, options: { mutiSelect: true, index: true, // 顯示序號, 多選則 mutiSelect loading: false, // 表格動畫 initTable: true, // 是否一掛載就加載數據 } } }, methods: { handleClick(e, row){ //transform-vue-jsx 的nativeOnClick 失效 , 因此採用 event.cancelBubble 控制點擊事件的冒泡... 若是點擊事件不影響你的點擊行事件,能夠不傳 e.cancelBubble = true // 中止冒泡,不然會觸發 row-click console.log(row) }, fetchTableData() { this.options.loading = true axios.post('https://www.easy-mock.com/mock/5b3f80edfa972016b39fefbf/example/tableData', { pageIndex: this.pagination.pageIndex, pageSize: this.pagination.pageSize }).then(res => { const { list, total } = res.data.data this.tableData = list this.pagination.total = total this.options.loading = false }).catch((error) => { console.log(error) this.options.loading = false }) }, handleRowClick(row, event, column){ // 點擊行的事件,同理能夠綁定其餘事件 console.log('click row:',row, event, column) }, handleSelectionChange(selection){ console.log(selection) } } } </script>
複製代碼

Table.vue 組件

<template>
  <div>
    <el-table v-loading="options.loading" :data="dataSource" :max-height="options.maxHeight" :stripe="options.stripe" :border="options.border" @row-click="handleRowClick" @selection-change="handleSelectionChange" header-row-class-name="table-header-row">

      <!--selection選擇框-->
      <el-table-column v-if="options.mutiSelect" type="selection" style="width:50px" align="center"></el-table-column>

      <!--序號-->
      <el-table-column v-if="options.index" label="序號" type="index" width="50" align="center"></el-table-column>

      <!--數據列-->
      <template v-for="(column, index) in columns">
        <el-table-column :key="index" :prop="column.prop" :label="column.label" :align="column.align||'center'" :width="column.width" :fixed="column.fixed">
          <template slot-scope="scope">

            <template v-if="!column.render">
              {{scope.row[column.prop]}}
            </template>

             <!-- render -->
            <template v-else>
              <RenderDom :row="scope.row" :index="index" :render="column.render" />
            </template>

            <!-- render button -->
            <template v-if="column.button">
              <template v-for="(btn, i) in column.group">
                <el-button :key="i" :type="btn.type" :size="btn.size || 'mini'" :icon="btn.icon" :disabled="btn.disabled" :plain="btn.plain" @click.stop="btn.onClick(scope.row, scope.$index)" >{{btn.name}}</el-button>
              </template>
            </template>

            <!-- slot 你能夠其餘經常使用項 -->

          </template>

        </el-table-column>
      </template>

    </el-table>

     <!-- 分頁 -->
    <el-pagination v-if="pagination" :total="pagination.total" :page-sizes="[20, 50, 100, 500, 5000]" layout="total, sizes, prev, pager, next, jumper" @size-change="handleSizeChange" @current-change="handleIndexChange" style="margin-top: 20px;text-align: right" ></el-pagination>

  </div>
</template>

<script> export default { components: { RenderDom: { functional: true, // 函數式組件 - 無 data 和 this 上下文 => better render props: { row: Object, index: Number, render: Function }, /** * @param {Function} createElement - 原生建立dom元素的方法, 棄用,推薦使用 jsx * @param {Object} ctx - 渲染的節點的this對象 * @argument 傳遞參數 row index */ render(createElement, ctx){ const { row, index } = ctx.props return ctx.props.render(row, index) } } }, props:{ dataSource: Array, options: Object, // 表格參數控制 maxHeight、stripe 等等... columns: Array, fetch: Function, // 獲取數據的函數 pagination: Object // 分頁,不傳則不顯示 }, created() { // 傳入的options覆蓋默認設置 this.$parent.options = Object.assign({ maxHeight: 500, stripe: true, // 是否爲斑馬紋 border: true }, this.options) this.options.initTable && this.fetch() }, methods: { handleSizeChange(size) { // 切換每頁顯示的數量 this.pagination.pageSize = size this.fetch() }, handleIndexChange(current) { // 切換頁碼 this.pagination.pageIndex = current this.fetch() }, handleSelectionChange(selection) { this.$emit('selection-change', selection) }, handleRowClick(row, event, column) { this.$emit('row-click', row, event, column) } } } </script>

<style> .el-table th, .el-table tr.table-header-row { background: #e5c5d2; /* 示例, 對錶格樣式上的修飾 */ } </style>
複製代碼

結語

上述代碼封裝完整性可能不是這麼高,但思路在呢,若是須要更多配置,各位能夠在進行增強...ios

吐槽一下,原本是想 props 數據來重寫 table 參數,相似 react:git

<Home>
  <ComonTable {...props} > </Home>

// ComonTable
<el-table {...props.options}>
</el-table> 複製代碼

因此想到繼承,本身又不熟悉。 並且發現 vue 展開綁定多個屬性是不能夠的: 多是我沒 google 到。若是能夠,請大佬告知一聲,謝謝github

相關文章
相關標籤/搜索