如何二次封装el-table

项目中使用了Element UI的表格组件el-table,按照官方提供的写法,展示的列越多,代码量也就越大。如果是开发后台管理系统,需要用到统计的地方有很多。不把时间花在重复的工作上,封装el-table,作为组件引用,只需要少量的配置,就能极大的提高开发效率。
el-table需要面对的场景多种多样,业务不同,呈现出的样式也不同,根据使用的难易程度,把它分为:

  • 1、显示数据从父视图传递,集成只需要一行代码的简易表格——<simpleTable>
  • 2、集成需要配置请求接口、查询参数,有分页,组件内请求数据的表格—— <myTable>

一、simpleTable

<template>
  <div ref="table" >
    <el-table :show-summary="isShowSummary" v-if="!fixHeight" :header-cell-style="{background:headerBgColor}" :data="tableData" ref="multipleTable" border style="width: 100%;" @selection-change="handleSelectionChange">
      <el-table-column v-if="isShowSelection" type="selection" width="55" align="center"></el-table-column>
      <el-table-column type="index" align="center" label="序号" min-width="50" v-if="isShowSerialNumber"></el-table-column>
      <template v-for="k in props">
        <el-table-column v-if="k.fixw" :min-width="k.fixw" align="center" :prop="k.prop" :label="k.label" :sortable="k.sort ? true : false">
          <slot :name="k.prop" :data="scope.row" slot-scope="scope">{{scope.row[k.prop]}}</slot>
        </el-table-column>
        <el-table-column v-else align="center" :prop="k.prop" :label="k.label" :sortable="k.sort ? true : false">
          <slot :name="k.prop" :data="scope.row" slot-scope="scope">{{scope.row[k.prop]}}</slot>
        </el-table-column>
      </template>
      <el-table-column align="center" :fixed="fixedType?'right':fixedType" label="操作" v-if="isShowOperation">
        <slot name="operation" :data="scope.row" slot-scope="scope"></slot>
      </el-table-column>
    </el-table>

    <el-table v-else :height="tableH" :show-summary="isShowSummary" :header-cell-style="{background:headerBgColor}" :data="tableData" ref="multipleTable" border style="width: 100%;" @selection-change="handleSelectionChange">
      <el-table-column v-if="isShowSelection" type="selection" width="55" align="center"></el-table-column>
      <el-table-column type="index" align="center" label="序号" min-width="50" v-if="isShowSerialNumber"></el-table-column>
      <template v-for="k in props">
        <el-table-column v-if="k.fixw" :min-width="k.fixw" align="center" :prop="k.prop" :label="k.label" :sortable="k.sort ? true : false">
          <slot :name="k.prop" :data="scope.row" slot-scope="scope">{{scope.row[k.prop]}}</slot>
        </el-table-column>
        <el-table-column v-else align="center" :prop="k.prop" :label="k.label" :sortable="k.sort ? true : false">
          <slot :name="k.prop" :data="scope.row" slot-scope="scope">{{scope.row[k.prop]}}</slot>
        </el-table-column>
      </template>
      <el-table-column align="center" :fixed="fixedType?'right':fixedType" label="操作" v-if="isShowOperation">
        <slot name="operation" :data="scope.row" slot-scope="scope"></slot>
      </el-table-column>
    </el-table>
  </div>
</template>
<script>
  export default {
    props: {
      headerBgColor: {
        type: String,
        default: 'white'
      },
      fixHeight:{   
        type: Boolean,
        default: false
      },
      tableH:{      
        type: Number,
        default: 0
      },
      isShowSelection: {
        type: Boolean,
        default: false
      },
      isShowSerialNumber: {
        type: Boolean,
        default: true
      },
      isShowOperation: {
        type: Boolean,
        default: true
      },
      isShowSummary: {
        type: Boolean,
        default: false
      },
      fixedType:{  
        type: Boolean,
        default: false
      },
      sort: {
        type: Array,
        default: () => []
      },
      props: Array,
      tableData: {
        type: Array,
        default: () => []
      },
    },
    data () {
      return {
      }
    },
    created () {},
    mounted(){},
    methods: {
      handleSelectionChange (val) {
        this.$emit('selectionChange', val)
      }
    }
  }
</script>

SimpleTable

参数 说明 类型 默认值
headerBgColor 表头背景色 String white
fixHeight 是否固定表格高度 boolean false
tableH 表格高度(fixHeight为true, 则tableH必须设定) number 0
isShowSelection 是否开启选择功能 boolean false
isShowSerialNumber 是否显示序号 boolean true
isShowOperation 是否显示操作列 boolean true
isShowSummary 是否显示总计 boolean true
fixedType 是否固定右侧操作栏 boolean false
props 列标题以及对应的参数名数组 Array []
tableData 后台返回的数据 Array []

Table Events

事件名 说明 参数
selectionChange 当选择项发生变化时会触发该事件 row

使用方式:

<template>
   <div class="h-table">
        <simpleTable
         :tableData="chartData2.rows"
         :props="callProps">
          <template #operation="{ data }">
             <a href="javascript:;">查看详情</a>
          </template>
        </simpleTable> 
  </div>
</template>
<script>
import simpleTable from "./../components/simpleTable";
export default {
  name: "home",
  components: {
      simpleTable
  },
  data() {
    return {
         callProps: [
        {
          prop: "date",
          label: "日期",
          fixw: "150"    // 自定义某列宽度
        }, 
        {
          prop: "callNum",
          label: "外呼数",
          sort: true    // 是否可以筛选
        },
        {
          prop: "callSuccess",
          label: "外呼成功数",
        },
        {
          prop: "connectNum",
          label: "接通率",
        },
        {
          prop: "connectDuring",
          label: "外呼平均通话时长",
        },
      ],
      chartData2: {
        rows: [
          { date: "2020-03-04", callNum: 1393, callSuccess: 1093 },
          { date: "2020-03-05", callNum: 3530, callSuccess: 3230 },
          { date: "2020-03-06", callNum: 2923, callSuccess: 2623 },
          { date: "2020-03-07", callNum: 1723, callSuccess: 1423 },
          { date: "2020-03-08", callNum: 3792, callSuccess: 3492 },
          { date: "2020-03-09", callNum: 4593, callSuccess: 4293 },
        ],
      },
    };
  }
};
</script>
<style lang="scss" scoped>
 .h-table{
     width: 90%;
     margin-top: 20px;
     margin-left: 20px;
  }
</style>

二、myTable

<template>
  <div ref="table" v-loading="loading" >
    <el-table v-if="!fixHeigth" :data="tableData" :header-cell-style="{background:headerBgColor}" ref="multipleTable" border style="width: 100%;" @selection-change="handleSelectionChange" @sort-change="handleSortChange">
      <el-table-column v-if="isShowSelection" type="selection" width="55" align="center" :selectable="isSelectable"></el-table-column>
      <el-table-column align="center" label="序号" min-width="70" v-if="isShowSerialNumber">
        <template slot-scope="scope">
          <span>{{scope.$index+(currentPage-1)*pageSize+1}}</span>
        </template>
      </el-table-column>
      <template v-for="k in props">
        <el-table-column v-if="k.fixw" :min-width="k.fixw" align="center" :prop="k.prop" :label="k.label" :sortable="k.sort ? true : false">
          <slot :name="k.prop" :data="scope.row" slot-scope="scope">{{scope.row[k.prop]}}</slot>
        </el-table-column>
        <el-table-column v-else align="center" :prop="k.prop" :label="k.label" :sortable="k.sort ? true : false">
          <slot :name="k.prop" :data="scope.row" slot-scope="scope">{{scope.row[k.prop]}}</slot>
        </el-table-column>
      </template>
      <el-table-column align="center" :fixed="fixedType?'right':fixedType" label="操作" v-if="isShowOperation">
        <slot name="operation" :data="scope.row" slot-scope="scope"></slot>
      </el-table-column>
    </el-table>

    <el-table v-else :height="tableH" :data="tableData" :header-cell-style="{background:headerBgColor}" ref="multipleTable" border style="width: 100%;" @selection-change="handleSelectionChange" @sort-change="handleSortChange">
      <el-table-column v-if="isShowSelection" type="selection" width="55" align="center" :selectable="isSelectable"></el-table-column>
      <el-table-column align="center" label="序号" min-width="70" v-if="isShowSerialNumber">
        <template slot-scope="scope">
          <span>{{scope.$index+(currentPage-1)*pageSize+1}}</span>
        </template>
      </el-table-column>
      <template v-for="k in props">
        <el-table-column v-if="k.fixw" :min-width="k.fixw" align="center" :prop="k.prop" :label="k.label" :sortable="k.sort ? true : false">
          <slot :name="k.prop" :data="scope.row" slot-scope="scope">{{scope.row[k.prop]}}</slot>
        </el-table-column>
        <el-table-column v-else align="center" :prop="k.prop" :label="k.label" :sortable="k.sort ? true : false">
          <slot :name="k.prop" :data="scope.row" slot-scope="scope">{{scope.row[k.prop]}}</slot>
        </el-table-column>
      </template>
      <el-table-column align="center" :fixed="fixedType?'right':fixedType" label="操作" v-if="isShowOperation">
        <slot name="operation" :data="scope.row" slot-scope="scope"></slot>
      </el-table-column>
    </el-table>

    <div class="bottom-row" v-if="isShowPagination">
      <el-pagination
        @current-change="handleCurrentChange"
        :page-size="pageSize"
        :current-page.sync="currentPage"
        layout="prev, pager, next, jumper, total"
        :total="total">
      </el-pagination>
    </div>
  </div>
</template>
<script>
  export default {
    props: {
      headerBgColor: {
        type: String,
        default: 'white'
      },
      isShowSelection: {
        type: Boolean,
        default: false
      },
      immediate: {
        type: Boolean,
        default: true
      },
      fixHeigth:{   //固定高度
        type: Boolean,
        default: false
      },
      isShowSerialNumber: {
        type: Boolean,
        default: true
      },
      isShowOperation: {
        type: Boolean,
        default: true
      },
      isShowPagination: {
        type: Boolean,
        default: true
      },
      isSecondLayer: {
        type: Boolean,
        default: true
      },
      isPost: {
        type: Boolean,
        default: true
      },
      isCustomTime:{  // 起始时间划分为两个参数的情况
        type: Boolean,
        default: false
      },
      tableH:{        // 表格高度,横向内容超过可视区域时适配小屏幕电脑
        type: Number,
        default: 0
      },
      fixedType:{  // 是否固定右侧操作栏
        type: Boolean,
        default: false
      },
      isArray: {
        type: Boolean,
        default: true
      },
      callback: Function,
      sort: {
        type: Array,
        default: () => []
      },
      query: Object,
      props: Array,
      action: String,
      isSelectable: Function,
      dataList: String,
      selected: String
    },
    data () {
      return {
        loading: false,
        tableData: [],
        total: 0,
        pageSize: 10,
        currentPage: 1
      }
    },
    async created () {
      this.immediate && await this.search()
    },
    methods: {
      async search (i, isScroll) {
        this.currentPage = i > 0 ? i : this.currentPage
        let query = JSON.parse(JSON.stringify(this.query))
        for (let key in query) {
          if (Array.isArray(query[key])) {
            query[key] = query[key].toString()
          }
        }
        let req = {
          pageNum: this.currentPage,
          pageSize: this.pageSize,
          ...query
        }
        if(this.isCustomTime){
          let paytime=this.query.payTime || [];
           req.payTimeStart=paytime[0]
           req.payTimeEnd=paytime[1]
        }
        this.loading = true
        if (this.isPost) {
            this.$api.post(this.action, req, r => {
              this.loading = false
              this.handleOperation(r, isScroll)
            })
        } else {
          this.$api.get4(this.action, req, r => {
            this.loading = false
            this.handleOperation(r, isScroll)
          })
        }
      },
      handleOperation (r, isScroll) {
        if (r.flag) {
          this.callback && this.callback(r) // 如果要对返回值做额外操作
          if (this.isSecondLayer) {  // 有分页
            if(r.data.allNum){
               this.total = +r.data.allNum
            }else{
               this.total = +r.data.total
            }
            if (!this.dataList) {  // 如果接口返回的data数据为dataList,根据实际情况而定
              this.tableData = r.data.dataList
            } else {  // 其他参数名时取值
              this.tableData = r.data[this.dataList]
            }
          } else {  // 没有分页
            if (this.isArray) {  // 如果数据类型为数组
              this.tableData = r.data
            } else {   // 如果数据类型为非数组
              this.tableData = []
              this.tableData.push(r.data)
            }
          }
          this.selected && this.handleTest()
          isScroll && this.$refs.table.scrollIntoView({behavior: 'smooth', block: 'start'})
        }
      },
      handleCurrentChange (index) {
        this.search(index, true)
      },
      handleSortChange (val) {
        this.$emit('sortChange', val)
      },
      handleSelectionChange (val) {
        this.$emit('selectionChange', val)
      },
      handleSizeChange (val) {
        this.pageSize = val
        this.search(1, true)
      },
      handleTest () {
        const rows = this.selected.split(',')
        this.tableData.forEach((row, i) => {
          rows.forEach(_ => {
            if (row.id === parseInt(_)) {
              this.$nextTick(() => {
                this.$refs.test.toggleRowSelection(row, true)
              })
            }
          })
        })
      },
      clearSelected () {
        this.$refs.multipleTable.clearSelection()
      }
    }
  }
</script>
<style lang="scss" scoped>
</style>

myTable

参数 说明 类型 默认值
headerBgColor 表头背景色 String white
fixHeight 是否固定表格高度 boolean false
tableH 表格高度(fixHeight为true, 则tableH必须设定) number 0
isShowSelection 是否开启选择功能 boolean false
isShowSerialNumber 是否显示序号 boolean true
isShowOperation 是否显示操作列 boolean true
isShowSummary 是否显示总计 boolean true
fixedType 是否固定右侧操作栏 boolean false
props 列标题以及对应的参数名数组 Array []
tableData 后台返回的数据 Array []
immediate 是否创建即请求数据 boolean true
isShowPagination 是否显示底部的分页器 boolean true
isSecondLayer 是否有分页 boolean true
isPost 是否为post请求 boolean true
isCustomTime 起始时间划分为两个参数的情况 boolean false
isArray 返回数据是否为数组形式 boolean true
query 查询参数 Object { }
action 请求接口 String 必传
dataList 获取data数据的key值 String r.data[dataList]

使用方式:

  • 1、数据结构为非数组,只显示一行的统计类表格
data:{
    redAmount: "632.00"
    people: 3
    gift: 11
}
<template>
  <div>
        <el-date-picker
        style="width:220px;"
        size="small"
        clearable
        value-format="yyyy-MM-dd"
        v-model="searchInfo.time"
        type="daterange"
        :picker-options="$utils.pickerOptions"
        range-separator="至"
        start-placeholder="时间选择"
        end-placeholder="时间选择">
      </el-date-picker>
      <el-button type="primary" size="small" @click="$refs.table.search(1)">查询</el-button>
      <mytable style="padding: 10px;" :isArray="false" :action="action" :query="searchInfo" :props="props" ref="table" :isShowSerialNumber="false" :isShowPagination="false" :isSecondLayer="false" :isShowOperation="false"></mytable>
  </div>
</template>
<script>
export default {
  data() {
    return {
        action: this.$api.baseUrl + 'xxx/xxx/xxxx',
        searchInfo: {
           time: ''
        },
        props: [
        {
          prop: 'uvNum',
          label: '落地页uv'
        },
        {
          prop: 'people',
          label: '红包领取人数'
        },
        {
          prop: 'gift',
          label: '坚果礼包领取人数'
        }
      ],
    };
  },
};
</script>
  • 2、常用统计表
<mytable dataList="records" :fixedType="true" style="padding: 10px;" :action="action1" :query="searchInfo" :props="props1" ref="table1">
            <template #status="{data}">
               <p class="status-reject" v-if="data.status === 0">审核不通过</p>
               <p class="status-pass" v-if="data.status === 1">审核通过</p>
               <p class="status-wait" v-else>未审核</p>
            </template>
            <template #operation="{data}">
              <p class="detail" v-if="!data.status"  @click="statusAction(data,1)">审核通过</p>
              <p></p>
            </template>
</mytable>
<script>
export default {
  data() {
    return {
        action1: this.$api.baseUrl + 'xxx/xxx/xxxx',
        searchInfo: {
           time: ''
        },
        props1: [
        {
          prop: 'uvNum',
          label: '落地页uv'
        },
        {
          prop: 'people',
          label: '红包领取人数'
        },
        {
          prop: 'gift',
          label: '坚果礼包领取人数'
        },
        {
          prop: 'status' ,
          label: '审核状态'
        }
      ],
    };
  },
};
</script>
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,214评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,307评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,543评论 0 341
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,221评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,224评论 5 371
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,007评论 1 284
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,313评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,956评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,441评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,925评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,018评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,685评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,234评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,240评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,464评论 1 261
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,467评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,762评论 2 345

推荐阅读更多精彩内容