element ui简单表格封装

1.子组件

<template>
  <div class="simpleTable">
    <div class="table-box" :style="{ height: config.height ? config.height+'px' : '100%' }">
      <el-table
        ref="myTable"
        :data="config.tableData"
        :style="{width: '100%', position: config.height ? 'absolute' : 'relative' }"
        :height="config.height"
        :stripe="stripe"
        :class="config.noBg?'':'custom'"
        :row-key="getRowKeys"
        :expand-row-keys="expands"
        @expand-change="extendChange"
        >
        <el-table-column v-if="isExtend().show" type="expand">
          <template slot-scope="props">
            <slot :name="isExtend().slot" :row="props.row"></slot>
          </template>
        </el-table-column>
        <template v-for="(item,i) in config.tableConfig">
          <el-table-column
            :key='i'
            :prop="item.value"
            :label="item.label"
            v-if="display(item)"
            width="auto"
            :min-width="item.minWidth ? item.minWidth:'auto'"
            :show-overflow-tooltip='true'
          >
          <template slot="header" slot-scope="scope">
            <div style="height:100%; display:flex;padding:0">
              <span>{{ scope.column.label }}</span>
              <span v-if="item.filterable">
                <Poptip content="" placement="bottom" v-model="visibleFilter[item.value]" :transfer="tip_transfer">
                  <i class="ivu-icon ivu-icon-funnel" @click="filterIcon(item,i,config.tableConfig)"  :class="{on: getColumnFilter(item)._isFilter === 'Y'}"></i>
                  <div slot="content" v-if="item._isShowFilterPop">
                    <div class='simpopfilter'>
                      <div class="" style="padding: 10px 16px 4px;">
                        <input type="text" v-model="filterParam" @click.stop.prevent=""
                              @keyup="searchFiltersContent" placeholder="请搜索"
                              @keyup.8="searchFiltersContent" class="tip-search">
                      </div>
                      <ul>
                        <li class="filters-li" @click="filterTable(item, i, 'All')" >全部</li>
                        <template v-for="(filter,j) in filterListsBySearch">
                          <li class="filters-li" @click="filterTable(item, i, filter)" :key='j'
                            :class="{active: getColumnFilterActiveno(item)._activeKey === filter.value}" >{{filter.label}}</li>
                        </template>
                      </ul>
                    </div>
                  </div>
                </Poptip>
              </span>
              <span v-if="item.tip">
                <Tooltip placement="top" :transfer="true">
                  <i class="el-icon-question" style="font-size:16px;"></i>
                  <div slot="content">
                    {{ item.tip.content }}
                  </div>
                </Tooltip>
              </span>
            </div>
          </template>
          <template slot-scope="scope">
            <span v-if="!item.slot">
              {{ item.value.includes('.') ? (isType(scope.row[item.value.split('.')[0]]) ? scope.row[item.value.split('.')[0]][item.value.split('.')[1]] : '-') : (isType(scope.row[item.value]) ? scope.row[item.value] : '-') }}
            </span>
            <slot v-if="item.slot" :name="item.slot" :row="scope.row"></slot>
          </template>
          </el-table-column>
        </template>
      </el-table>
    </div>
    <div v-if="config.page" class="page">
      <el-pagination
      small
      :layout="config.layout ? config.layout : 'prev, pager, next, jumper'"
      @current-change="handleCurrentChange"
      :current-page.sync="config.page.currentPage"
      :page-size="config.page.size"
      :page-sizes="config.pageSizes ? config.pageSizes : [5, 10]"
      :total="config.page.total"
      :hide-on-single-page="ishide">
      </el-pagination>
    </div>
  </div>
</template>
<script>
export default {
  data(){
    return {
      isFilter: {},
      filterLists: [],
      tip_transfer: true, // 作用参见iview tip transfer属性
      filterParam: '',
      filterListsBySearch: [],
      visibleFilter: {},
      expands: [],
      getRowKeys(row) {
        return row.id
      }
    }
  },
  computed:{
    ishide(){
      return !!(this.config.tableData.length || this.config.page.total<this.config.page.size)
    },
    stripe() {
      if (this.config.hasOwnProperty('stripe')) {
        return this.config.stripe
      } else {
        return true
      }
    }
  },
  props:{
    config:Object,
    getData:Function, //获取数据函数
  },
 /**
  * 【config】配置说明    可参考bill-cost-seo.vue页面的建议优化表
  *  tableData:表格数据
  *  stripe:斑马纹,默认true
  *  height:表格高度,默认不限高
  *  page:页码配置
  *  isExtend:展开行配置,注意父组件要配置slot插槽
  * 
  *  tableConfig:表格配置说明
  *  label:表头
  *  value:对应字段
  *  display:列是否展示,默认true
  *  minWidth:设置表格最小宽度
  *  filterable:配置筛选
  *  tip:添加提示,默认无
  *  slot:自定义插槽
  */
   
  mounted(){
  },
  watch:{
    $route: function (){
      for (const key in this.visibleFilter) {
        if (this.visibleFilter.hasOwnProperty(key)) {
          this.visibleFilter[key] = false
        }
      }
        // this.visibleFilter = false
    },
  },
  methods: {
    extendChange(row, expandedRows) {
      if (expandedRows.length) {
        this.expands = []
        if (row) {
          this.expands.push(row.id)// 每次push进去的是每行的ID
        }
      } else {
        this.expands = []// 默认不展开
      }
      if (expandedRows.length) {
        let func = this.config.isExtend.func
        this.$parent[func](row)
      }
    },
    isExtend() {
      if (this.config.hasOwnProperty('isExtend')) {
        return { show: this.config.isExtend.show , slot: this.config.isExtend.slot}
      } else {
        return {show:false,slot:''}
      }
    },
    conditionChange(params,item) {
      let keys = Object.keys(params)
      let count = 0
      this.isFilter[item.value] = true
      keys.map(key=>{
        if(typeof params[key] === 'object' && !params[key]){ //判断null
          count++
          delete params[key] //删除原来需要传的字段,现在不需要传的
        }
      })
      if(count === keys.length){ //没有条件要传
        this.isFilter[item.value] = false
      }
      this.$emit('onfilter', params)
    },
      //特殊类型过滤
    popFilterFunc(item,index){
      let config = item.specialFilter
      config.show  = true
      config.index  = index
    },
    filterIcon(item, columnNo,config) {
      // 清空tip中搜索条件
      this.filterParam = ''
      if (item.filterable.remoteFilters) {
        this.getRemoteFilterOptions(item,columnNo)
      } else {
        this.filterLists =item.filterable.filterLists
        this.filterListsBySearch = item.filterable.filterLists
      }
      for (let obj in config) {
        config[obj]._isShowFilterPop = false
      }
      item._isShowFilterPop = true
    },
      // 远程获取过滤条件
    getRemoteFilterOptions (item) {
      this.filterLists = []
      this.filterListsBySearch = []
      let filterAPI_string = item.filterable.filterAPI
      let filterAPI = this.$validate.valueFromExpression(this.apiCenter, filterAPI_string)
      this.$httpRequestEntrance.httpRequestEntrance('GET', filterAPI, '' , (responseData) => {
        for (let it of responseData.data) {
          let label = it[item.filterable.displayName]
            // 排除掉空数据
          if (this.$validate.isEmpty(label)) {
            this.filterLists.push({label: label,
              value: it[item.filterable.filterValue]})
          }
        }
        // this.filterListsBySearch = this.filterLists
      })
    },
    // 获取排序状态active状态
    getColumnFilter (item) {
      return {_isFilter: item._isFilter}
    },
      // 获取排序状态active状态中的当前状态
    getColumnFilterActiveno (item) {
      return {_activeKey: item._activeKey}
    },
       // 列筛选功能
    filterTable: function (ele, i, valx) {
      let params = {}
      if (valx === 'All') {
        ele._isFilter = 'N'
        params[ele.filterable.filterParam] = ''
      } else {
        ele._isFilter = 'Y'
        params[ele.filterable.filterParam] = valx.value
      }
      for (const key in this.visibleFilter) {
        if (this.visibleFilter.hasOwnProperty(key)) {
          this.visibleFilter[key] = false
        }
      }
        // 设置当前状态数据key
      ele._activeKey = valx.value
      this.$emit('onfilter', params)
    },
    display(item) {
      if (item.hasOwnProperty('display')) {
        return item.display
      } else {
        return true
      }
    },
    searchFiltersContent() {
      this.filterListsBySearch = this.filterLists
      this.filterListsBySearch = this.filterListsBySearch.filter((item)=> {
        return item.label.toUpperCase().includes(this.filterParam.toUpperCase())
      })
    },
    isType(data) {
      if (Object.prototype.toString.call(data) === '[object Object]') {
        if (Object.keys(data).length === 0) {
          return false
        } else {
          return data
        }
      } else if (Object.prototype.toString.call(data) === '[object Array]') {
        if (data.length === 0) {
          return false
        } else {
          return data
        }
      } else {
        if (data === 0) {
          return true
        } else {
          return data
        }
      }
    },
    render(){
    },
    handleCurrentChange(){
      this.getData()
    },
  },
  components: {
    Az
  }
}
</script>
<style>
.el-table th{
  padding: 0;
}
.el-table .el-table__expanded-cell {
  padding: 0;
}
.el-table th>.cell{
  height:40px;
  font-size:14px;
  font-family:PingFangSC-Medium,PingFang SC;
  font-weight:500;
  color:rgba(53,53,53,1);
  line-height:40px;
 }
 .el-table td{
  padding: 11px 0px 12px;
}
 .el-table .cell{
  height:17px;
  font-size:12px;
  font-family:PingFangSC-Regular,PingFang SC;
  font-weight:400;
  color:rgba(1,22,44,1);
  line-height:17px;
 }
 .el-table .cell .ivu-poptip {
   padding: 0 5px;
 }
 .el-table .cell .ivu-tooltip {
   padding: 0;
 }
 .el-table .cell .ivu-tooltip .ivu-tooltip-rel {
   padding: 0 5px;
 }
.ivu-poptip-body {
   padding: 0;
 }
 .el-table .cell .ivu-poptip .ivu-poptip-rel{
   padding: 0;
 }
.el-table .cell .ivu-poptip .ivu-poptip-rel i.on {
    color: #2d8cf0;
}
.el-table .cell i.on {
    color: #2d8cf0;
}
 .el-table--striped .el-table__body tr.el-table__row--striped td {
   background:rgba(249,251,253,1);
 }
 .el-pager li.active{
   background-color: #409EFF;
   color: #fff;
   cursor: default;
   border-radius: 3px;
 }
 .el-pager li,.el-pager li.btn-quicknext{
   color:#8e8e8e
 }

.el-tooltip__popper {
    max-width: 250px;
}

</style>

<style lang="less" scoped>
.table-box{
  position: relative;
  overflow: hidden;
}
.simpopfilter{
    max-height: 200px;
    max-width: 206px;
    overflow: auto;
  }
   // 表头筛选内容样式-开始
  .filters-li {
    padding: 0 16px;
    line-height: 28px;
    text-align: left;
    cursor: pointer;
    color: #595959;
  }
  .filters-li:hover {
    background-color: @color-gray-F;
  }
  .active {
    color: @color-blue;
    background-color: @color-gray-F;
  }
.ivu-icon-funnel {
    color: #bbbec4;
}
.custom /deep/ th{
  background:rgba(245,247,249,1);
}
.el-table::before {
    height: 0;
}
.page{
  float: right;
  margin-top: 18px;
}
  .active {
    color: @color-blue;
    background-color: @color-gray-F;
  }
</style>

2.父组件
···

        <div class="list-body">
          <simpleTable :config='advise_Config' :getData='getAdvceTableData' @onfilter="doAdviseFilter">
            <template slot="itemName" slot-scope="scope">
              <a :href="`#/${advise_Config.hrefDetail}/${scope.row.resource_id}`">{{ advise_Config.radioValue === 'eip' ? scope.row.params.ip : scope.row.resource_name }}</a>
            </template>
            <template slot="cost" slot-scope="scope">
              <span>{{ isType(scope.row.cost) ? `¥${scope.row.cost}` : '-' }}</span>
            </template>
            <template slot="params" slot-scope="scope">
              <span v-if="advise_Config.radioValue === 'instance'">{{ isType(scope.row.params) ? `${scope.row.params.cpu}核-${scope.row.params.mem}GB-${scope.row.params.root_volume}GB` : '-'  }}</span>
              <span v-if="advise_Config.radioValue === 'volume'">{{ isType(scope.row.params) ? `${scope.row.params.size}GB` : '-'  }}</span>
              <span v-if="advise_Config.radioValue === 'eip'">{{ isType(scope.row.params) ? `${scope.row.params.bandwidth}Mbps` : '-' }}</span>
            </template>
            <template slot="params_optm" slot-scope="scope">
              <span v-if="advise_Config.radioValue === 'instance'">{{ isType(scope.row.params_optm) ? `${scope.row.params_optm.cpu}核-${scope.row.params_optm.mem}GB-${scope.row.params_optm.root_volume}GB` : '-'  }}</span>
              <span v-if="advise_Config.radioValue === 'volume'">{{ isType(scope.row.params_optm) ? `${scope.row.params_optm.size}GB` : '-'  }}</span>
              <span v-if="advise_Config.radioValue === 'eip'">{{ isType(scope.row.params_optm) ? `${scope.row.params_optm.bandwidth}Mbps` : '-' }}</span>
            </template>
            <template slot="advice" slot-scope="scope">
              <span>{{ scope.row.advice === 'erase' ? '建议释放' : (scope.row.advice === 'degrade' ? '建议降配' : (scope.row.advice === 'upgrade' ? '建议升配' : '-')) }}</span>
            </template>
            <template slot="provider" slot-scope="scope">
              <span>{{ provider[scope.row.provider] }}</span>
            </template>
            <template slot="cost_optm" slot-scope="scope">
              <div class="costContent">
                <div>{{ isType(scope.row.cost_optm) ? `¥${scope.row.cost_optm}` : '-' }}</div>
                <img v-if="scope.row.cost_optm - scope.row.cost > 0" src="../../../assets/content_icon/up.png" />
                <img v-if="scope.row.cost_optm - scope.row.cost < 0" src="../../../assets/content_icon/down.png" />
              </div>
            </template>
            <template slot="operate" slot-scope="scope">
              <a @click="doIgnore(scope.row)">忽略</a>
            </template>
            <div slot='tableExtend'>
              <extendTable :detailConfig="advise_Config.isExtend.detailConfig"></extendTable>
            </div>
          </simpleTable>
        </div>

···


Snipaste_2020-12-08_17-51-56.png
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 219,427评论 6 508
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,551评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 165,747评论 0 356
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,939评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,955评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,737评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,448评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,352评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,834评论 1 317
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,992评论 3 338
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,133评论 1 351
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,815评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,477评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,022评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,147评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,398评论 3 373
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,077评论 2 355

推荐阅读更多精彩内容