欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

elementUI?el-table二次封裝的詳細實例

 更新時間:2023年03月31日 10:39:28   作者:畫意橋邊  
在項目中會多次使用表格展示數(shù)據(jù),不對這個table進行二次封裝成我們自己想要的,重復(fù)的代碼量的工作會比較大,下面這篇文章主要給大家介紹了關(guān)于elementUI?el-table二次封裝的相關(guān)資料,需要的朋友可以參考下

前言

很多中后臺業(yè)務(wù)的系統(tǒng)中,表格是最高頻的組件之一,其中一般包括搜索條件、表格展示、表格操作列、分頁等。那么我們二次封裝的這個表格組件就需要包含以下幾個功能點:

1、數(shù)據(jù)自動獲取和刷新

2、自定義列配置

3、分頁功能

4、根據(jù)搜索條件進行搜索功能

5、加載中狀態(tài)和空數(shù)據(jù)狀態(tài)

一、先上頁面最終效果

二、創(chuàng)建目錄yxt-table如下圖

index.vue為父級頁面

yxt-table.vue為表格組件

二、數(shù)據(jù)自動獲取和刷新

因為表格的數(shù)據(jù)一般都比較簡單,就是根據(jù)搜索條件,調(diào)用接口請求一個到列表,然后將列表數(shù)據(jù)一一展示到表格上,再對特定的列進行一些過濾轉(zhuǎn)化等個性化操作。但是萬變不離其宗,這個步驟基本每個表格都要進行一遍,所以考慮到通用性(其實是為了偷懶),將請求接口獲取數(shù)據(jù)這一步放在組件里面實現(xiàn)。

    created () {
        this.getData()
    },
    methods: {
        getData () {
            const fun = this.apiUrl
            fun().then(res => {
                this.tableData = res[this.otherConfig.list] || []
                this.tableTotal = res.pageInfo?.total || 0
            })
        }
    }

三、自定義列配置

組件接收一個數(shù)組作為自定義列

tableColumn: [
    { prop: 'name', label: '名稱' },
    { prop: 'code', label: '編碼' },
    { prop: 'status', label: '狀態(tài)' }
]

 index.vue

<!-- index.vue -->
<template>
  <div>
    <yxt-table :apiUrl="yxtTableList" 
               :tableColumn="tableColumn"></yxt-table>
  </div>
</template>
 
<!-- index.vue -->
<script>
import yxtTable from './yxt-table.vue'
import { yxtTableList } from 'https/yxtDemo.js'
export default {
    name: 'yxtDemoTable',
    components: {
        yxtTable
    },
    data () {
        return {
            yxtTableList,
            tableColumn: [
                { prop: 'name', label: '名稱' },
                { prop: 'code', label: '編碼' },
                { prop: 'status', label: '狀態(tài)' }
            ]
        }
    }
}
</script>

 yxt-table.vue

<!-- yxt-table.vue -->
<template>
  <div>
    <el-table :data="tableData">
      <el-table-column v-for="item in tableColumn"
                       :key="item.prop"
                       :prop="item.prop"
                       :label="item.label"></el-table-column>
    </el-table>
  </div>
</template>
 
<!-- yxt-table.vue -->
<script>
export default {
    name: 'yxtTable',
    props: {
        apiUrl: { // 列表接口(必填)
            type: Function,
            required: true
        },
        tableColumn: { // 自定義列配置
            type: Array,
            default: () => []
        },
        otherConfig: { //
            type: Object,
            default: () => {
                return {
                    list: 'list'
                }
            }
        }
    },
    data () {
        return {
            tableData: []
        }
    },
    created () {
        this.getData()
    },
    methods: {
        getData () {
            const fun = this.apiUrl
            fun().then(res => {
                this.tableData = res[this.otherConfig.list] || []
                this.tableTotal = res.pageInfo?.total || 0
            })
        }
    }
}
</script>

至此,一個表格可以實現(xiàn)了

1、otherConfig說明

由于我們的接口請求放在組件里面了,但是我們對接的接口可能由于業(yè)務(wù)的不同項目組的不同開發(fā)人員的不同,而導(dǎo)致接口返回的列表的字段名不同,這里通過傳參的形式做一下兼容

2、上面這樣只能實現(xiàn)簡單的展示功能,還有些數(shù)據(jù)比如 狀態(tài)1 需要轉(zhuǎn)化為打卡成功,狀態(tài)0 需要轉(zhuǎn)化為打卡失敗進行顯示,這類需求可以通過filter進行轉(zhuǎn)化

<!-- yxt-table.vue -->
      <el-table-column v-for="item in tableColumn"
                       :key="item.prop"
                       :prop="item.prop"
                       :label="item.label">
        <template v-slot:default="scope">
          <div v-if="item.dictCode">
            {{ scope.row[item.prop] | filterStatus(dict[item.dictCode]) }}
          </div>
          <div v-else>
            {{ scope.row[item.prop] }}
          </div>
        </template>
      </el-table-column>
 
    props: {
        dict: { // 全部字典
            type: Object,
            default: () => {}
        }
    },
    filters: {
        filterStatus (value, array, code = 'code', name = 'name') {
            if (!value && value !== 0) { // 要把0摘出來,一般0都是正常的數(shù)據(jù),所以不能只用  !value
                return ''
            }
            const find = array.find(e => (e[code] === value.toString()) || (e[code] === +value)) // 字符型數(shù)值型都得匹配
            if (find) {
                return find[name]
            } else { // 沒有匹配的就原樣返回
                return value
            }
        }
    },
<!-- index.vue -->
    <yxt-table :apiUrl="yxtTableList" 
               :tableColumn="tableColumn"
               :dict="dict"></yxt-table>
 
    data () {
        return {
           tableColumn: [
                { prop: 'name', label: '名稱' },
                { prop: 'code', label: '編碼' },
                { prop: 'status', label: '狀態(tài)', dictCode: 'status' }
            ],
            dict: {
                status: [
                    { code: 0, name: '打卡失敗' },
                    { code: 1, name: '打卡成功' }
                ]
            }
        }
    }

這里dict設(shè)置為對象的原因是為了裝進更多字典

3、思考一下,如果要在表格中展示這樣的自定義圖標怎么辦? 

使用插槽slot,在tableColumn里面設(shè)置某行屬性的slot為true,改造el-table-column如下:

<!-- yxt-table.vue -->     
     <el-table-column v-for="(item, index) in tableColumn"
                       :key="index"
                       :prop="item.prop"
                       :label="item.label">
        <template v-if="item.slot"
                  v-slot:default="scope">
          <slot :name="item.prop"
                :row="scope.row"
                :index="scope.$index"></slot>
        </template>
        <template v-else v-slot:default="scope">
          <div v-if="item.dictCode">
            {{ scope.row[item.prop] | filterStatus(dict[item.dictCode]) }}
          </div>
          <div v-else>
            {{ scope.row[item.prop] }}
          </div>
        </template>
      </el-table-column>
<!-- index.vue -->    
    <yxt-table :apiUrl="yxtTableList"
               :tableColumn="tableColumn"
               :otherConfig="otherConfig"
               :dict="dict">
      <template v-slot:icon="{row, index}">
        <i :class="row.status ? 'el-icon-circle-check' : 'el-icon-circle-close'"></i>
      </template>
    </yxt-table>
 
    data () {
        return {
            tableColumn: [
                { prop: 'name', label: '名稱' },
                { prop: 'code', label: '編碼' },
                { prop: 'status', label: '狀態(tài)', dictCode: 'status' },
                { prop: 'icon', label: '圖標', slot: true }
            ]
        }
    }

 4、在實際項目中,除了字典轉(zhuǎn)化,還有一些比較定制化的展示需求,這個可以通過傳入一個函數(shù)format進行計算,然后在這個方法里面將最后的計算結(jié)果return

<!-- yxt-table.vue -->
      <el-table-column v-for="(item, index) in tableColumn"
                       :key="index"
                       :prop="item.prop"
                       :label="item.label">
        <template v-if="item.slot"
                  v-slot:default="scope">
          <slot :name="item.prop"
                :row="scope.row"
                :index="scope.$index"></slot>
        </template>
        <template v-else v-slot:default="scope">
          <div v-if="item.dictCode">
            {{ scope.row[item.prop] | filterStatus(dict[item.dictCode]) }}
          </div>
          <div v-else-if="item.format">
            {{ item.format(scope.row) }}
          </div>
          <div v-else>
            {{ scope.row[item.prop] }}
          </div>
        </template>
      </el-table-column>
<!-- index.vue -->
    data () {
        return {
            tableColumn: [
                { prop: 'name', label: '名稱' },
                { prop: 'code', label: '編碼' },
                { prop: 'status', label: '狀態(tài)', dictCode: 'status' },
                { prop: 'icon', label: '圖標', slot: true },
                { prop: 'phone',
                    label: '電話號碼',
                    format: (row) => {
                        return `${row.name}-${row.code}(${row.phone})`
                    } }
            ]
        }
    }

5、表格一般還有批量操作,所以需要多選和單選以及針對特定場景設(shè)置禁選

 yxt-table.vue

<!-- yxt-table.vue -->
<template>
  <div class="yxt-table">
    <!-- 批量操作按鈕,因為每個需求不同,批量操作的功能也不同,所以這里只放一個插槽,不設(shè)置默認內(nèi)容,所有按鈕均在父級設(shè)置 -->
    <div class="multiple-operation">
      <slot name="multiple-operation"
            :selectionData="selectionData"></slot>
    </div>
    <!-- 頁面主表格 -->
    <el-table :data="tableData"
              :row-key="rowKey"
              @selection-change="selectionChange">
      <!-- 可選框(多選) -->
      <el-table-column v-if="selection === 'multiple'"
                       type="selection"
                       align="center"
                       width="55"
                       :reserve-selection="rowKey ? true : false"
                       :selectable="selectable"/>
      <!-- 可選框(單選) -->
      <el-table-column v-else-if="selection === 'single'"
                       align="center"
                       width="30">
        <template v-slot:default="scope">
          <el-radio v-model="selectionRadio"
                    :label="scope.$index"
                    :disabled="selectable ? !selectable(scope.row) : false"
                    @change="selectionChangeSingle(scope.row)">
            {{ '' }}
          </el-radio>
        </template>
      </el-table-column>
      <el-table-column v-for="(item, index) in tableColumn"
                       :key="index"
                       :prop="item.prop"
                       :label="item.label">
        <template v-if="item.slot"
                  v-slot:default="scope">
          <slot :name="item.prop"
                :row="scope.row"
                :index="scope.$index"></slot>
        </template>
        <template v-else v-slot:default="scope">
          <div v-if="item.dictCode">
            {{ scope.row[item.prop] | filterStatus(dict[item.dictCode]) }}
          </div>
          <div v-else-if="item.format">
            {{ item.format(scope.row) }}
          </div>
          <div v-else>
            {{ scope.row[item.prop] }}
          </div>
        </template>
      </el-table-column>
    </el-table>
  </div>
</template>
 
<!-- yxt-table.vue -->
<script>
export default {
    name: 'yxtTable',
    props: {
        apiUrl: { // 列表接口(必填)
            type: Function,
            required: true
        },
        tableColumn: { // 自定義列配置
            type: Array,
            default: () => []
        },
        otherConfig: { // 其他配置
            type: Object,
            default: () => {
                return {
                    list: 'list' // 接口返回數(shù)據(jù)的列表字段的字段名(因為在組件里面調(diào)接口,可能不同業(yè)務(wù)不同項目組不同一個開發(fā)者返回給前端的參數(shù)名不一致,這里進行兼容)
                }
            }
        },
        dict: { // 全部字典
            type: [Array, Object],
            default: () => []
        },
        selection: { // 是否顯示可選框(多選-multiple 、單選-single )
            type: String
        },
        selectable: { // 當(dāng)前行是否可選擇
            type: Function
        },
        rowKey: { // 表格唯一key(適用于分頁多選表格,保留之前的選擇,不傳則為單頁選擇)
            type: [Number, String, Function],
            default: ''
        }
    },
    filters: {
        filterStatus (value, array, code = 'code', name = 'name') {
            if (!value && value !== 0) { // 要把0摘出來,一般0都是正常的數(shù)據(jù),所以不能只用  !value
                return ''
            }
            const find = array.find(e => (e[code] === value.toString()) || (e[code] === +value)) // 字符型數(shù)值型都得匹配
            if (find) {
                return find[name]
            } else { // 沒有匹配的就原樣返回
                return value
            }
        }
    },
    data () {
        return {
            tableData: [],
            tableTotal: 0,
            selectionRadio: '',
            selectionData: []
        }
    },
    created () {
        this.getData()
    },
    methods: {
        getData () {
            const fun = this.apiUrl
            fun().then(res => {
                this.tableData = res[this.otherConfig.list] || []
                this.tableTotal = res.pageInfo?.total || 0
            })
        },
 
        // 多選,選擇行數(shù)據(jù)change
        selectionChange (selection) {
            this.selectionData = selection
        },
 
        // 單選,選擇行數(shù)據(jù)change
        selectionChangeSingle (selection) {
            this.selectionData = [selection]
        }
    }
}
</script>
<style scoped lang="scss">
.yxt-table {
  margin: 30px;
  .multiple-operation {
    margin-bottom: 10px;
  }
}
</style>

 index.vue

<!-- index.vue -->
<template>
  <div>
    <yxt-table :apiUrl="yxtTableList"
               :tableColumn="tableColumn"
               :otherConfig="otherConfig"
               :dict="dict"
               selection="multiple"
               :selectable="isSelectable">
      <!-- 圖標插槽 -->
      <template v-slot:icon="{row, index}">
        <i :class="row.status ? 'el-icon-circle-check' : 'el-icon-circle-close'"></i>
      </template>
      <!-- 批量操作按鈕插槽 -->
      <template v-slot:multiple-operation="{selectionData}">
        <el-button type="primary"
                   size="small"
                   @click="handleClick1(selectionData)">批量操作1</el-button>
        <el-button type="success"
                   size="small"
                   @click="handleClick2(selectionData)">批量操作2</el-button>
      </template>
    </yxt-table>
    <yxt-table :apiUrl="yxtTableList"
               :tableColumn="tableColumn"
               :otherConfig="otherConfig"
               :dict="dict"
               selection="single"
               :selectable="isSelectable">
      <!-- 圖標插槽 -->
      <template v-slot:icon="{row, index}">
        <i :class="row.status ? 'el-icon-circle-check' : 'el-icon-circle-close'"></i>
      </template>
      <!-- 批量操作按鈕插槽 -->
      <template v-slot:multiple-operation="{selectionData}">
        <el-button type="primary"
                   size="small"
                   @click="handleClick1(selectionData)">單選操作</el-button>
      </template>
    </yxt-table>
  </div>
</template>
 
<!-- index.vue -->
<script>
import yxtTable from './yxt-table.vue'
import { yxtTableList } from 'https/yxtDemo.js'
export default {
    name: 'yxtDemoTable',
    components: {
        yxtTable
    },
    data () {
        return {
            yxtTableList,
            tableColumn: [
                { prop: 'name', label: '名稱' },
                { prop: 'code', label: '編碼' },
                { prop: 'status', label: '狀態(tài)', dictCode: 'status' },
                { prop: 'icon', label: '圖標', slot: true },
                { prop: 'phone',
                    label: '電話號碼',
                    format: (row) => {
                        return `${row.name}-${row.code}(${row.phone})`
                    } }
            ],
            tableConfig: {
                stripe: 'stripe',
                border: 'border',
                height: '200',
                maxHeight: '200',
                showHeader: true
            },
            otherConfig: {
                list: 'tasks'
            },
            dict: {
                status: [
                    { code: 0, name: '打卡失敗' },
                    { code: 1, name: '打卡成功' }
                ]
            }
        }
    },
    methods: {
        handleClick1 (selectionData) {
            console.log('1', selectionData)
        },
        handleClick2 (selectionData) {
            console.log('2', selectionData)
        },
        isSelectable (row) {
            return row.selectable !== 0
        }
    }
}
</script>
<style scoped lang="scss">
.el-icon-circle-check {
  font-size: 28px;
  color: #67C23A;
}
.el-icon-circle-close {
  font-size: 28px;
  color: #F00;
}
</style>

6、操作列

根據(jù)業(yè)務(wù)需求,可以在操作列設(shè)置幾個默認按鈕,通過setupConfig設(shè)置開關(guān),如果有除了默認按鈕之外的操作需求,再通過插槽slot進行插入

<!-- yxt-table.vue -->
      <!-- 操作列 -->
      <el-table-column v-if="setupConfig.width !== 0"
                       :fixed="setupConfig.fixed"
                       :width="setupConfig.width"
                       label="操作">
        <template v-slot:default="scope">
          <slot name="setup"
                :row="scope.row"
                :index="scope.$index"></slot>
          <!-- 查看 -->
          <el-button v-if="setupConfig.view"
                     type="text"
                     @click="setupEvents('view', scope.row)">查看</el-button>
          <!-- 編輯 -->
          <el-button v-if="setupConfig.edit"
                     type="text"
                     @click="setupEvents('edit', scope.row)">編輯</el-button>
          <!-- 刪除 -->
          <el-button v-if="setupConfig.del"
                     type="text"
                     @click="setupEvents('del', scope.row)">刪除</el-button>
          <!-- 操作日志 -->
          <el-button v-if="setupConfig.log"
                     type="text"
                     @click="setupEvents('log', scope.row)">操作日志</el-button>
        </template>
      </el-table-column>
 
    props: {
        setupConfig: {
            type: Object,
            default: () => {
                return {
                    width: 'auto'
                }
            }
        }
    },
    methods: {
        setupEvents (setupType, row) { // 操作列方法 查看/編輯/刪除/操作日志
            this.$emit(setupType, row)
        }
    }

 index.vue做相應(yīng)的處理,這里不貼代碼了

7、分頁 

pagination控制是否需要分頁組件,如果不需要分頁則設(shè)置為false。根據(jù)業(yè)務(wù)需求,可傳入pageSizes控制條數(shù)下拉框的條數(shù)選項

<!-- yxt-table.vue -->
    <!-- 分頁 -->
    <el-pagination v-if="pagination"
                   class="pagination tablePage"
                   :pager-count="5"
                   :page-sizes="pageSizes || [10, 20, 50, 100]"
                   :total="tableTotal || 0"
                   :page-size="pageInfo.pageSize || 10"
                   :current-page="pageInfo.startPage || 1"
                   layout="total, sizes, prev, pager, next, jumper"
                   @size-change="sizeChange"
                   @current-change="pageChange"></el-pagination>
 
 
 
    props: {
        pagination: { // 是否需要分頁,默認需要
            type: Boolean,
            default: true
        },
        pageSizes: {
            type: Array
        }
    },
    methods: {
        getData () {
            const fun = this.apiUrl
            const pageInfo = { // 分頁信息
                pageSize: this.pageInfo.pageSize,
                startPage: this.pageInfo.startPage
            }
            let param = { // 其他的搜素條件
 
            }
            if (this.pagination) { // 如果需要分頁,則傳分頁信息
                param = { ...param, ...pageInfo }
            }
            fun(param).then(res => {
                this.tableData = res[this.otherConfig.list] || []
                this.tableTotal = res.pageInfo?.total || 0
            })
        },
 
        // 條數(shù)變化
        sizeChange (size) {
            this.pageInfo.startPage = 1
            this.pageInfo.pageSize = size
            this.getData()
        },
 
        // 頁碼變化
        pageChange (page) {
            this.pageInfo.startPage = page
            this.getData()
        }
    }

 8、el-table還有一個展開行功能expand,根據(jù)業(yè)務(wù)需求,也可以加進組件里

<!-- yxt-table.vue -->
      <!-- 展開行 -->
      <el-table-column v-if="expand"
                       type="expand">
        <template v-slot:default="scope">
          <slot name="expand"
                :row="scope.row"
                :index="scope.$index"></slot>
        </template>
      </el-table-column>
      
    props: {
        expand: { // 是否展開行
            type: Boolean,
            default: false
        }
    }
<!-- index.vue -->
    <yxt-table :apiUrl="yxtTableList"
               :tableColumn="tableColumn"
               :expand="true">
      <template v-slot:expand="{row, index}">
        <div>
          <p>序號:{{index}}</p>
          <p>內(nèi)容:{{row}}</p>
        </div>
      </template>
    </yxt-table>

四、根據(jù)搜索條件進行搜索更新表格數(shù)據(jù)

新增一個yxt-search.vue

<!-- yxt-search.vue -->
<template>
  <div class="yxt-search">
    <div v-for="(item,index) in searchConfig"
         :key="index"
         class="yxt-search-item">
      <el-input v-if="item.type==='input'"
                v-model="searchModel[item.key]"
                size="medium"
                :clearable="item.clearable || true"
                :placeholder="item.placeholder || '請輸入'"
                :maxlength="item.maxlength"></el-input>
      <el-select v-if="item.type==='select'"
                 v-model="searchModel[item.key]"
                 size="medium"
                 style="width: 100%"
                 :clearable="item.clearable || true"
                 :filterable="item.filterable || true"
                 :disabled="item.disabled || false"
                 :multiple="item.multiple || false"
                 :allow-create="item.allowCreate"
                 :placeholder="item.placeholder || '請選擇'">
        <el-option v-for="(selectItem, selectIndex) in item.selectList"
                   :key="selectIndex"
                   :label="selectItem[item.listLabel]"
                   :value="selectItem[item.listValue]"></el-option>
      </el-select>
    </div>
    <div v-if="searchConfig.length" class="yxt-search-button">
      <el-button size="medium" type="primary" @click="search">搜索</el-button>
      <el-button size="medium" type="primary" plain @click="reset">重置</el-button>
      <!-- 其他的按鈕需求通過插槽傳入 -->
      <slot name="searchBtn" :searchData="searchModel"></slot>
    </div>
  </div>
</template>
 
<!-- yxt-search.vue -->
<script>
export default {
    name: 'yxtSearch',
    props: {
        searchConfig: { // 搜索條件配置項
            type: Array,
            required: true,
            default () {
                return []
            }
        },
        searchModel: { // 搜索條件綁定值
            type: Object,
            required: true,
            default () {
                return {}
            }
        },
        searchReset: { // 搜索條件默認值重置值
            type: Object
        }
    },
    data () {
        return {
        }
    },
    methods: {
        search () {
            this.$emit('search', this.searchModel)
        },
        reset () {
            if (this.searchReset) { // 如果傳入有默認值,則重置后為默認值
                Object.keys(this.searchModel).forEach((item) => {
                    this.searchModel[item] = this.searchReset[item]
                })
            } else {
                Object.keys(this.searchModel).forEach((item) => {
                    this.searchModel[item] = ''
                })
            }
        }
    }
}
</script>
<style scoped lang="scss">
.yxt-search {
  display: flex;
  flex-direction: row;
  flex-wrap: wrap;
  justify-content: flex-start;
  .yxt-search-item {
    flex: 1;
    margin: 0 10px 10px 0;
    width: calc((100% - 30px) / 4);  // 這里的30px = (分布個數(shù)4-1)*間隙1px, 可以根據(jù)實際的分布個數(shù)和間隙區(qū)調(diào)整
    min-width: calc((100% - 30px) / 4);
    max-width: calc((100% - 30px) / 4);
    &:nth-child(4n) { // 去除每行最后一個(第4n個)的margin-right
      margin-right: 0;
    }
  }
  .yxt-search-button {
    margin: 0 0 10px 0;
    width: 100%;
    text-align: right;
  }
}
</style>
<!-- yxt-table.vue -->
    <yxt-search :searchConfig="searchConfig"
                :searchModel="searchModel"
                :searchReset="searchReset"
                @search="getData(1)">
      <template v-slot:searchBtn="{searchData}">
        <!-- 其他的按鈕需求通過插槽傳入 -->
        <slot name="searchBtn" :searchData="searchData"></slot>
      </template>
    </yxt-search>
 
    props: {
        searchConfig: { // 搜索條件配置項
            type: Array,
            default () {
                return []
            }
        },
        searchReset: { // 搜索條件默認值重置值
            type: Object
        }
    },
    data () {
        return {
            searchModel: this.searchReset ? JSON.parse(JSON.stringify(this.searchReset)) : {}
        }
    },
    methods: {
        getData (startPage) {
            if (startPage) { // 如果傳入值,則從改值的頁碼數(shù)開始
                this.pageInfo.startPage = startPage
            }
            let param = { // 其他的搜素條件
                ...this.searchModel
            }
            ...
        }
    }
<!-- index.vue -->
    <yxt-table :apiUrl="yxtTableList"
               :tableColumn="tableColumn"
               :searchConfig="searchConfig"
               :searchReset="searchReset">
      <template v-slot:searchBtn="{searchData}">
        <el-button size="medium" type="success" @click="handleClickExport(searchData)">導(dǎo)出</el-button>
      </template>
    </yxt-table>
 
     data () {
        return {
            searchConfig: [
                { type: 'input', key: 'name' },
                { type: 'input', key: 'code' },
                { type: 'select',
                    key: 'status',
                    selectList: [
                        { code: 0, name: '打卡失敗' },
                        { code: 1, name: '打卡成功' }
                    ],
                    listLabel: 'name',
                    listValue: 'code' }
            ],
            searchReset: {
                name: '張三',
                code: '',
                status: 1
            }
        }
    },
    methods: {
        handleClickExport (data) {
            console.log(data)
        }
    }

五、加載中狀態(tài)和空數(shù)據(jù)狀態(tài)

加載中:el-table 添加 v-loading="loading",getData里面,發(fā)送請求之前設(shè)置為true,獲得數(shù)據(jù)后設(shè)置為false

空數(shù)據(jù):通過插槽empty設(shè)置

 六、完整代碼:

index.vue
<!-- index.vue -->
<template>
  <div>
    <yxt-table :apiUrl="yxtTableList"
               :tableColumn="tableColumn"
               :otherConfig="otherConfig"
               :dict="dict"
               selection="multiple"
               :selectable="isSelectable"
               :setupConfig="setupConfig"
               :searchConfig="searchConfig"
               :searchReset="searchReset"
               @view="view"
               @log="log">
      <!-- 圖標插槽 -->
      <template v-slot:icon="{row, index}">
        <i :class="row.status ? 'el-icon-circle-check' : 'el-icon-circle-close'"></i>
      </template>
      <!-- 批量操作按鈕插槽 -->
      <template v-slot:multiple-operation="{selectionData}">
        <el-button type="primary"
                   size="small"
                   @click="handleClick1(selectionData)">批量操作1</el-button>
        <el-button type="success"
                   size="small"
                   @click="handleClick2(selectionData)">批量操作2</el-button>
      </template>
      <template v-slot:searchBtn="{searchData}">
        <el-button size="medium" type="success" @click="handleClickExport(searchData)">導(dǎo)出</el-button>
      </template>
    </yxt-table>
    <yxt-table :apiUrl="yxtTableList"
               :tableColumn="tableColumn"
               :otherConfig="otherConfig"
               :dict="dict"
               selection="single"
               :selectable="isSelectable"
               :setupConfig="setupConfig2"
               :pagination="false"
               :expand="true"
               :emptyText="'沒有數(shù)據(jù)的展示文字'">
      <!-- 圖標插槽 -->
      <template v-slot:icon="{row, index}">
        <i :class="row.status ? 'el-icon-circle-check' : 'el-icon-circle-close'"></i>
      </template>
      <!-- 批量操作按鈕插槽 -->
      <template v-slot:multiple-operation="{selectionData}">
        <el-button type="primary"
                   size="small"
                   @click="handleClick1(selectionData)">單選操作</el-button>
      </template>
      <template v-slot:expand="{row, index}">
        <div>
          <p>序號:{{index}}</p>
          <p>內(nèi)容:{{row}}</p>
        </div>
      </template>
    </yxt-table>
  </div>
</template>
 
<!-- index.vue -->
<script>
import yxtTable from './yxt-table.vue'
import { yxtTableList } from 'https/yxtDemo.js'
export default {
    name: 'yxtDemoTable',
    components: {
        yxtTable
    },
    data () {
        return {
            yxtTableList,
            tableColumn: [
                { prop: 'name', label: '名稱' },
                { prop: 'code', label: '編碼' },
                { prop: 'status', label: '狀態(tài)', dictCode: 'status' },
                { prop: 'icon', label: '圖標', slot: true },
                { prop: 'phone',
                    label: '電話號碼',
                    format: (row) => {
                        return `${row.name}-${row.code}(${row.phone})`
                    } }
            ],
            tableConfig: {
                stripe: 'stripe',
                border: 'border',
                height: '200',
                maxHeight: '200',
                showHeader: true
            },
            otherConfig: {
                list: 'tasks'
            },
            setupConfig: {
                width: 100,
                view: true,
                log: true
            },
            setupConfig2: {
                edit: true,
                del: true,
                log: true
            },
            dict: {
                status: [
                    { code: 0, name: '打卡失敗' },
                    { code: 1, name: '打卡成功' }
                ]
            },
            searchConfig: [
                { type: 'input', key: 'name' },
                { type: 'input', key: 'code' },
                { type: 'select',
                    key: 'status',
                    selectList: [
                        { code: 0, name: '打卡失敗' },
                        { code: 1, name: '打卡成功' }
                    ],
                    listLabel: 'name',
                    listValue: 'code' }
            ],
            searchReset: {
                name: '張三',
                code: '',
                status: 1
            }
        }
    },
    methods: {
        handleClick1 (selectionData) {
            console.log('1', selectionData)
        },
        handleClick2 (selectionData) {
            console.log('2', selectionData)
        },
        handleClickExport (data) {
            console.log(data)
        },
        isSelectable (row) {
            return row.selectable !== 0
        },
        view (row) {
            console.log('view', row)
        },
        log (row) {
            console.log('log', row)
        }
    }
}
</script>
<style scoped lang="scss">
.el-icon-circle-check {
  font-size: 28px;
  color: #67C23A;
}
.el-icon-circle-close {
  font-size: 28px;
  color: #F00;
}
</style>
yxt-table.vue
<!-- yxt-table.vue -->
<template>
  <div class="yxt-table">
    <yxt-search :searchConfig="searchConfig"
                :searchModel="searchModel"
                :searchReset="searchReset"
                @search="getData(1)">
      <template v-slot:searchBtn="{searchData}">
        <!-- 其他的按鈕需求通過插槽傳入 -->
        <slot name="searchBtn" :searchData="searchData"></slot>
      </template>
    </yxt-search>
    <!-- 批量操作按鈕,因為每個需求不同,批量操作的功能也不同,所以這里只放一個插槽,不設(shè)置默認內(nèi)容,所有按鈕均在父級設(shè)置 -->
    <div class="multiple-operation">
      <slot name="multiple-operation"
            :selectionData="selectionData"></slot>
    </div>
    <!-- 頁面主表格 -->
    <el-table :data="tableData"
              :row-key="rowKey"
              v-loading="loading"
              @selection-change="selectionChange">
      <!-- 可選框(多選) -->
      <el-table-column v-if="selection === 'multiple'"
                       type="selection"
                       align="center"
                       width="55"
                       :reserve-selection="rowKey ? true : false"
                       :selectable="selectable"/>
      <!-- 可選框(單選) -->
      <el-table-column v-else-if="selection === 'single'"
                       align="center"
                       width="30">
        <template v-slot:default="scope">
          <el-radio v-model="selectionRadio"
                    :label="scope.$index"
                    :disabled="selectable ? !selectable(scope.row) : false"
                    @change="selectionChangeSingle(scope.row)">
            {{ '' }}
          </el-radio>
        </template>
      </el-table-column>
      <!-- 展開行 -->
      <el-table-column v-if="expand"
                       type="expand">
        <template v-slot:default="scope">
          <slot name="expand"
                :row="scope.row"
                :index="scope.$index"></slot>
        </template>
      </el-table-column>
      <el-table-column v-for="(item, index) in tableColumn"
                       :key="index"
                       :prop="item.prop"
                       :label="item.label">
        <template v-if="item.slot"
                  v-slot:default="scope">
          <slot :name="item.prop"
                :row="scope.row"
                :index="scope.$index"></slot>
        </template>
        <template v-else v-slot:default="scope">
          <div v-if="item.dictCode">
            {{ scope.row[item.prop] | filterStatus(dict[item.dictCode]) }}
          </div>
          <div v-else-if="item.format">
            {{ item.format(scope.row) }}
          </div>
          <div v-else>
            {{ scope.row[item.prop] }}
          </div>
        </template>
      </el-table-column>
      <!-- 操作列 -->
      <el-table-column v-if="setupConfig.width !== 0"
                       :fixed="setupConfig.fixed"
                       :width="setupConfig.width"
                       label="操作">
        <template v-slot:default="scope">
          <slot name="setup"
                :row="scope.row"
                :index="scope.$index"></slot>
          <!-- 查看 -->
          <el-button v-if="setupConfig.view"
                     type="text"
                     @click="setupEvents('view', scope.row)">查看</el-button>
          <!-- 編輯 -->
          <el-button v-if="setupConfig.edit"
                     type="text"
                     @click="setupEvents('edit', scope.row)">編輯</el-button>
          <!-- 刪除 -->
          <el-button v-if="setupConfig.del"
                     type="text"
                     @click="setupEvents('del', scope.row)">刪除</el-button>
          <!-- 操作日志 -->
          <el-button v-if="setupConfig.log"
                     type="text"
                     @click="setupEvents('log', scope.row)">操作日志</el-button>
        </template>
      </el-table-column>
      <!-- 空狀態(tài) -->
      <template slot="empty">
        <p>{{ emptyText }}</p>
      </template>
    </el-table>
    <!-- 分頁 -->
    <el-pagination v-if="pagination"
                   class="pagination tablePage"
                   :pager-count="5"
                   :page-sizes="pageSizes || [10, 20, 50, 100]"
                   :total="tableTotal || 0"
                   :page-size="pageInfo.pageSize || 10"
                   :current-page="pageInfo.startPage || 1"
                   layout="total, sizes, prev, pager, next, jumper"
                   @size-change="sizeChange"
                   @current-change="pageChange"></el-pagination>
  </div>
</template>
 
<!-- yxt-table.vue -->
<script>
import yxtSearch from './yxt-search'
export default {
    name: 'yxtTable',
    components: {
        yxtSearch
    },
    props: {
        apiUrl: { // 列表接口(必填)
            type: Function,
            required: true
        },
        tableColumn: { // 自定義列配置
            type: Array,
            default: () => []
        },
        otherConfig: { // 其他配置
            type: Object,
            default: () => {
                return {
                    list: 'list' // 接口返回數(shù)據(jù)的列表字段的字段名(因為在組件里面調(diào)接口,可能不同業(yè)務(wù)不同項目組不同一個開發(fā)者返回給前端的參數(shù)名不一致,這里進行兼容)
                }
            }
        },
        dict: { // 全部字典
            type: [Array, Object],
            default: () => []
        },
        selection: { // 是否顯示可選框(多選-multiple 、單選-single )
            type: String
        },
        selectable: { // 當(dāng)前行是否可選擇
            type: Function
        },
        rowKey: { // 表格唯一key(適用于分頁多選表格,保留之前的選擇,不傳則為單頁選擇)
            type: [Number, String, Function],
            default: ''
        },
        setupConfig: {
            type: Object,
            default: () => {
                return {
                    width: 'auto'
                }
            }
        },
        pagination: { // 是否需要分頁,默認需要
            type: Boolean,
            default: true
        },
        pageSizes: { // 分頁的下拉框選項
            type: Array
        },
        expand: { // 是否展開行
            type: Boolean,
            default: false
        },
        searchConfig: { // 搜索條件配置項
            type: Array,
            default () {
                return []
            }
        },
        searchReset: { // 搜索條件默認值重置值
            type: Object
        },
        emptyText: {
            type: String
        }
    },
    filters: {
        filterStatus (value, array, code = 'code', name = 'name') {
            if (!value && value !== 0) { // 要把0摘出來,一般0都是正常的數(shù)據(jù),所以不能只用  !value
                return ''
            }
            const find = array.find(e => (e[code] === value.toString()) || (e[code] === +value)) // 字符型數(shù)值型都得匹配
            if (find) {
                return find[name]
            } else { // 沒有匹配的就原樣返回
                return value
            }
        }
    },
    data () {
        return {
            loading: true,
            tableData: [],
            tableTotal: 0,
            pageInfo: {
                pageSize: 10,
                startPage: 1
            },
            selectionRadio: '',
            selectionData: [],
            searchModel: this.searchReset ? JSON.parse(JSON.stringify(this.searchReset)) : {}
        }
    },
    created () {
        this.getData()
    },
    methods: {
        getData (startPage) {
            if (startPage) { // 如果傳入值,則從改值的頁碼數(shù)開始
                this.pageInfo.startPage = startPage
            }
            this.loading = true
            const fun = this.apiUrl
            const pageInfo = { // 分頁信息
                pageSize: this.pageInfo.pageSize,
                startPage: this.pageInfo.startPage
            }
            let param = { // 其他的搜素條件
                ...this.searchModel
            }
            if (this.pagination) { // 如果需要分頁,則傳分頁信息
                param = { ...param, ...pageInfo }
            }
            fun(param).then(res => {
                setTimeout(() => {
                    this.tableData = res[this.otherConfig.list] || []
                    this.tableTotal = res.pageInfo?.total || 0
                    this.loading = false
                }, 2000)
            })
        },
 
        // 多選,選擇行數(shù)據(jù)change
        selectionChange (selection) {
            this.selectionData = selection
        },
 
        // 單選,選擇行數(shù)據(jù)change
        selectionChangeSingle (selection) {
            this.selectionData = [selection]
        },
 
        // 操作列方法 查看/編輯/刪除/操作日志
        setupEvents (setupType, row) {
            this.$emit(setupType, row)
        },
 
        // 條數(shù)變化
        sizeChange (size) {
            this.pageInfo.startPage = 1
            this.pageInfo.pageSize = size
            this.getData()
        },
 
        // 頁碼變化
        pageChange (page) {
            this.pageInfo.startPage = page
            this.getData()
        }
    }
}
</script>
<style scoped lang="scss">
.yxt-table {
  margin: 30px;
  .multiple-operation {
    margin-bottom: 10px;
  }
}
</style>
yxt-search.vue
<!-- yxt-search.vue -->
<template>
  <div class="yxt-search">
    <div v-for="(item,index) in searchConfig"
         :key="index"
         class="yxt-search-item">
      <el-input v-if="item.type==='input'"
                v-model="searchModel[item.key]"
                size="medium"
                :clearable="item.clearable || true"
                :placeholder="item.placeholder || '請輸入'"
                :maxlength="item.maxlength"></el-input>
      <el-select v-if="item.type==='select'"
                 v-model="searchModel[item.key]"
                 size="medium"
                 style="width: 100%"
                 :clearable="item.clearable || true"
                 :filterable="item.filterable || true"
                 :disabled="item.disabled || false"
                 :multiple="item.multiple || false"
                 :allow-create="item.allowCreate"
                 :placeholder="item.placeholder || '請選擇'">
        <el-option v-for="(selectItem, selectIndex) in item.selectList"
                   :key="selectIndex"
                   :label="selectItem[item.listLabel]"
                   :value="selectItem[item.listValue]"></el-option>
      </el-select>
    </div>
    <div v-if="searchConfig.length" class="yxt-search-button">
      <el-button size="medium" type="primary" @click="search">搜索</el-button>
      <el-button size="medium" type="primary" plain @click="reset">重置</el-button>
      <!-- 其他的按鈕需求通過插槽傳入 -->
      <slot name="searchBtn" :searchData="searchModel"></slot>
    </div>
  </div>
</template>
 
<!-- yxt-search.vue -->
<script>
export default {
    name: 'yxtSearch',
    props: {
        searchConfig: { // 搜索條件配置項
            type: Array,
            required: true,
            default () {
                return []
            }
        },
        searchModel: { // 搜索條件綁定值
            type: Object,
            required: true,
            default () {
                return {}
            }
        },
        searchReset: { // 搜索條件默認值重置值
            type: Object
        }
    },
    data () {
        return {
        }
    },
    methods: {
        search () {
            this.$emit('search', this.searchModel)
        },
        reset () {
            if (this.searchReset) { // 如果傳入有默認值,則重置后為默認值
                Object.keys(this.searchModel).forEach((item) => {
                    this.searchModel[item] = this.searchReset[item]
                })
            } else {
                Object.keys(this.searchModel).forEach((item) => {
                    this.searchModel[item] = ''
                })
            }
        }
    }
}
</script>
<style scoped lang="scss">
.yxt-search {
  display: flex;
  flex-direction: row;
  flex-wrap: wrap;
  justify-content: flex-start;
  .yxt-search-item {
    flex: 1;
    margin: 0 10px 10px 0;
    width: calc((100% - 30px) / 4);  // 這里的30px = (分布個數(shù)4-1)*間隙1px, 可以根據(jù)實際的分布個數(shù)和間隙區(qū)調(diào)整
    min-width: calc((100% - 30px) / 4);
    max-width: calc((100% - 30px) / 4);
    &:nth-child(4n) { // 去除每行最后一個(第4n個)的margin-right
      margin-right: 0;
    }
  }
  .yxt-search-button {
    margin: 0 0 10px 0;
    width: 100%;
    text-align: right;
  }
}
</style>

yxtTable.json

{
  "retCode": "0",
  "retMsg": "success",
  "pageInfo": {
    "total": 300
  },
  "tasks": [
    { "name": "張三",
      "code": "zhangSan",
      "status": 1,
      "icon": true,
      "phone":  "17801010101",
      "selectable": 1
    },
    { "name": "李四",
      "code": "liSi",
      "status": 0,
      "icon": false,
      "phone": "17802020202",
      "selectable": 2
    },
    { "name": "王五",
      "code": "wangWu",
      "status": 2,
      "icon": true,
      "phone": "17803030303",
      "selectable": 0
    },
    { "name": "馬六",
      "code": "maLiu",
      "status": 1,
      "icon": false,
      "phone": "17804040404",
      "selectable": 2
    }
  ]
}

最后效果

總結(jié)

到此這篇關(guān)于elementUI el-table二次封裝的文章就介紹到這了,更多相關(guān)el-table二次封裝內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • vue?事件獲取當(dāng)前組件的屬性方式

    vue?事件獲取當(dāng)前組件的屬性方式

    這篇文章主要介紹了vue?事件獲取當(dāng)前組件的屬性方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-03-03
  • Vue3內(nèi)置組件Teleport使用方法詳解

    Vue3內(nèi)置組件Teleport使用方法詳解

    這篇文章主要介紹了Vue3內(nèi)置組件Teleport使用方法,Teleport是Vue 3.0 新增的一個內(nèi)置組件,主要是為了解決一些特殊場景下模態(tài)對話框組件、組件的渲染,帶著些許的了解一起走進下面文章的詳細內(nèi)容吧
    2021-10-10
  • 前端XSS攻擊場景詳解與Vue.js處理XSS的方法(vue-xss)

    前端XSS攻擊場景詳解與Vue.js處理XSS的方法(vue-xss)

    這篇文章主要給大家介紹了關(guān)于前端XSS攻擊場景與Vue.js使用vue-xss處理XSS的方法,介紹了實際工作中渲染數(shù)據(jù)時遇到XSS攻擊時的防范措施,以及解決方案,需要的朋友可以參考下
    2024-02-02
  • Vue懸浮窗和聚焦登錄組件功能實現(xiàn)

    Vue懸浮窗和聚焦登錄組件功能實現(xiàn)

    這篇文章主要介紹了Vue懸浮窗和聚焦登錄組件經(jīng)驗總結(jié),? 本文整理了實現(xiàn)懸浮窗以及聚焦登錄組件的功能,本文通過實例代碼給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2022-11-11
  • Vue 實現(xiàn)雙向綁定的四種方法

    Vue 實現(xiàn)雙向綁定的四種方法

    這篇文章主要介紹了Vue 實現(xiàn)雙向綁定的四種方法,非常不錯,具有參考借鑒價值,需要的朋友參考下吧
    2018-03-03
  • 解決vue項目打包后提示圖片文件路徑錯誤的問題

    解決vue項目打包后提示圖片文件路徑錯誤的問題

    這篇文章主要介紹了解決vue項目打包后提示圖片文件路徑錯誤的問題,本文給大家介紹的非常詳細,具有一定的參考借鑒價值,需要的朋友可以參考下
    2018-07-07
  • vue源碼解讀子節(jié)點優(yōu)化更新

    vue源碼解讀子節(jié)點優(yōu)化更新

    這篇文章主要為大家介紹了vue源碼解讀子節(jié)點優(yōu)化更新示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-08-08
  • vue使用monaco?editor漢化右鍵菜單示例

    vue使用monaco?editor漢化右鍵菜單示例

    這篇文章主要為大家介紹了vue使用?monaco?editor?漢化右鍵菜單實現(xiàn)漢化示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-08-08
  • 解決Vue3?echarts?v-show無法重新渲染的問題

    解決Vue3?echarts?v-show無法重新渲染的問題

    這篇文章主要介紹了Vue3?echarts?v-show無法重新渲染的問題,本文通過示例代碼給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2023-09-09
  • Vue使用vue-area-linkage實現(xiàn)地址三級聯(lián)動效果的示例

    Vue使用vue-area-linkage實現(xiàn)地址三級聯(lián)動效果的示例

    很多時候我們需要使用地址三級聯(lián)動,即省市區(qū)三級聯(lián)動,這篇文章主要介紹了Vue使用vue-area-linkage實現(xiàn)地址三級聯(lián)動效果的示例,感興趣的小伙伴們可以參考一下
    2018-06-06

最新評論