如何二次封裝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閱讀 230,527評論 6 544
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,687評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,640評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,957評論 1 318
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,682評論 6 413
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 56,011評論 1 329
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 44,009評論 3 449
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 43,183評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,714評論 1 336
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,435評論 3 359
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,665評論 1 374
  • 沈念sama閱讀 39,148評論 5 365
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,838評論 3 350
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,251評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,588評論 1 295
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,379評論 3 400
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,627評論 2 380

推薦閱讀更多精彩內容