提示:請先看第二步中的組件說明,和組件封裝中其他擴展的api,的注釋都在html中對應的代碼結構都有主要依靠JSON數據動態執行和回調
特點:通過JSON數據動態渲染列表標題和數據列表,JSON數據驅動事件監聽和回調以及數據過濾,和滿足更多自定義需求組合
效果圖:

下面這種模式可以點擊圖片,可以是一張圖片,也可以數組中多個圖片,點擊圖片可以預覽切換


1.頁面調用(記得進行引入組件后在調用)
<table-List :tableData="tableData" :tableLabel="tableLabel" :choice="true" pagingPosition="center" :paging="true" :operation="operation" :total="total" headerAlign='center' @handleNumberChange="handleNumberChange" @sortChange="sortChange" @select="select" :headButton="true" @handleCurrentPage="handleCurrentPage"> <template v-slot:second> <el-button type="primary" size="mini" ><i class="el-icon-download"></i> 導出</el-button> </template> </table-List>
import tableList from '@/components/tableList' components:{
tableList,
}, data(){ return{ tableData: [],//數據源 tableLabel:[ { prop: 'nickName', label: '用戶昵稱', align: 'center', }, { prop: 'friendCount', label: '好友數量', align: 'center', }, ], operation:{ width: '220', Button:[ { label: '查看', size: "mini", authority: false, callback(k) { console.log(k) } } ] }, total:10, } } , methods:{ handleNumberChange(val){},// 每一頁展示多少條切換 handleCurrentPage(val){},//切換分頁 sortChange(column){},// 排序 select(valArr){},//列表復選框 }
2.封裝組件核心代碼
<template>
<div style="height: 100%;">
<!-- 這里插槽主要是自定義頭部標簽操作按鈕 -->
<div style="padding: 5px 0;" v-if="headButton">
<slot name="second"></slot>
</div>
<el-table :data="tableData" :row-key="rowKey" border @sort-change='sortChange' @select="select"
:highlight-current-row="true" @select-all="select"
:header-cell-style="{'text-align':headerAlign,'background':'#eef1f6'}" @current-change="handleCurrentChange"
:max-height="fixedHeight>0?fixedHeight:tableHeight-difference" :ref="Math.random()">
<!-- 復選框 -->
<el-table-column type="selection" v-if="choice" width="50" :align="headerAlign" :key="Math.random()">
</el-table-column>
<!-- 序號 -->
<el-table-column label="序號" v-if="serialNumber" width="50" type="index" :align="headerAlign"
:key="Math.random()">
<template slot-scope="scope">
{{searchData.limit * (searchData.page - 1) + (scope.$index + 1)}}
</template>
</el-table-column>
<!-- 動態表頭 -->
<!-- {
prop:'title',// 列表渲染的字段key
label:'菜單名稱',// 字段中文名稱
align:''// 列表內容文字的位置
sort:true, // 是否排序
form:'string', (可選:string/img/Button/filter/select)
key:{label: "label",value: "value"} // 這個配置是下拉框的form = select
filter(row){},// 對數據進行過濾 並返回內容 和vue 過濾器一樣的功能
configure:{ // 配置按鈕的參數對象
type:''// 參考el-button 官網參數
size:''// 參考el-button 官網參數
},
callback(row){} //點擊按鈕的回調函數
} -->
<div v-for="(item, index) in tableLabel" :key="index">
<!-- 普通數據展示/或者字符串文本展示 -->
<el-table-column v-if="!item.form || item.form ==='string'" :prop="item.prop" :width="item.width"
:label="item.label" :sortable="item.sort" :align="item.align?item.align:'left'" :key="index"
show-overflow-tooltip>
</el-table-column>
<!-- 數據過濾:根據filter函數自定義規則進行數據返回 -->
<el-table-column v-else-if="item.form === 'filter'" :width="item.width" :label="item.label"
:sortable="item.sort" :align="item.align?item.align:'left'" :key="index" show-overflow-tooltip>
<template slot-scope="scope">
{{item.filter(scope.row)}}
</template>
</el-table-column>
<!-- 圖片展示 -->
<el-table-column v-else-if="item.form === 'img'" :width="item.width" :label="item.label"
:sortable="item.sort" :align="item.align?item.align:'left'" :key="index">
<template slot-scope="scope">
<!-- 如果是字符串就是一個圖片 -->
<div v-if="typeof scope.row[item.prop] === 'string'">
<el-image style="width: 22px; height: 22px"
:src="scope.row[item.prop]?scope.row[item.prop]:defaultImg"
:preview-src-list="[scope.row[item.prop]?scope.row[item.prop]:defaultImg]">
</el-image>
</div>
<!-- 不是字符串就統一數組來處理 -->
<div v-else-if="scope.row[item.prop]!==null&& scope.row[item.prop].length>0">
<span v-for="(item1,index1) in scope.row[item.prop]" :key="index1">
<el-image style="width: 22px; height: 22px;margin-right: 20px;" :src="scope.row[item.prop][index1]"
:preview-src-list="scope.row[item.prop]" :z-index='2100'>
</el-image>
</span>
</div>
</template>
</el-table-column>
<!-- 按鈕展示 -->
<el-table-column v-else-if="item.form === 'Button'" :width="item.width" :label="item.label"
:sortable="item.sort" :align="item.align?item.align:'left'" :key="index">
<template slot-scope="scope">
<el-button @click="item.callback&&item.callback(scope.row)"
:type="item.configure&&item.configure.type?item.configure.type:''"
:size="item.configure&&item.configure.size?item.configure.size:''">
{{item.configure.text||'缺少按鈕文字'}}</el-button>
</template>
</el-table-column>
<!-- 多個復選框 -->
<el-table-column v-else-if="item.form === 'checkbox'" :width="item.width" :label="item.label"
:sortable="item.sort" :align="item.align?item.align:'left'" :key="index">
<template slot-scope="scope">
<span style="margin-left: 5px;" v-for="(v,i) in scope.row.authority" :key="i">
<el-checkbox :label="v.name" name="type" v-model="v.open"></el-checkbox>
</span>
<span v-if="scope.row.authority&&scope.row.authority.length<1">暫無</span>
</template>
</el-table-column>
<!-- 單選框 -->
<!-- 表頭配置tableLabel -->
<!-- {
prop: 'timeType',最終下拉框每次選中的值都綁定到 這個定義的字段上
label: '時間單位',
align: 'center',
form: "radio",
key: {
label: "label",
value: "value"
},
width: 250,
}, -->
<!-- 列表循環數據 每一項必須要有 radioList屬性為數組 -->
<el-table-column v-else-if="item.form === 'radio'" :width="item.width" :label="item.label"
:sortable="item.sort" :align="item.align?item.align:'left'" :key="index">
<template slot-scope="scope" >
<div v-if="scope.row.radioList && scope.row.radioList.length">
<el-radio-group v-model="scope.row[item.prop]">
<el-radio
v-for="items in scope.row.radioList"
:key="items[item.key.value]"
:label="items[item.key.value]" >{{items[item.key.label]}}</el-radio>
</el-radio-group>
</div>
<div v-else>
<span style="color: #e6a23c;">缺少radioList屬性數組!</span>
</div>
</template>
</el-table-column>
<!-- 下拉框 -->
<!-- 表頭配置tableLabel -->
<!-- {
prop:'xxx' 最終下拉框每次選中的值都綁定到 這個定義的字段上
form:'select',
key:{label: "label",value: "value"}
} -->
<!-- 列表循環數據 每一項必須要有 options屬性為數組 -->
<el-table-column v-else-if="item.form === 'select'" :width="item.width" :label="item.label"
:sortable="item.sort" :align="item.align?item.align:'left'" :key="index">
<template slot-scope="scope">
<el-select v-model="scope.row[item.prop]" placeholder="請選擇" size="mini">
<el-option
v-for="items in scope.row.options"
:key="items[item.key.value]"
:label="items[item.key.label]"
:value="items[item.key.value]">
</el-option>
</el-select>
</template>
</el-table-column>
<!-- 輸入框 -->
<el-table-column v-else-if="item.form === 'input'" :width="item.width" :label="item.label"
:sortable="item.sort" :align="item.align?item.align:'left'" :key="index">
<template slot-scope="scope">
<el-input placeholder="請輸入內容" v-model="scope.row[item.prop]"size="mini" >
</el-input>
</template>
</el-table-column>
</div>
<el-table-column label="操作" :width="operation.width" v-if="JSON.stringify(operation)!== '{}'">
<template slot-scope="scope">
<!-- 操作按鈕 -->
<!-- {
label:'刪除',
type:'danger',// 按鈕類型 參考el-button 官網參數
size:"mini", // 按鈕大小 參考el-button 官網參數
plain:true, // 是否朴素按鈕
callback(row){}, // 點擊按鈕回調函數
disabled(row){ return true/false} //是否禁用 可以條件判斷 讓函數返回布爾值
authority:true// 如果涉及到權限按鈕控制的 就添加這個屬性(false普通按鈕/true權限按鈕)
authorityEvent(row){return true/false}
} -->
<!-- 動態操作按鈕 -->
<div class="flex center">
<div class="flex center" v-for="(item,index) in operation.Button" :key="index">
<el-button style="margin: 0 5px;" v-if="!item.authority"
@click="item.callback(Object.assign({},scope.row))" :type="item.type?item.type:''"
:size="item.size?item.size:''" :disabled="item.disabled&&item.disabled(scope.row)"
:plain="plain">{{item.label}}</el-button>
<el-button style="margin: 0 5px;"
v-else-if="item.authority && item.authorityEvent&& item.authorityEvent(item.label)"
@click="item.callback(Object.assign({},scope.row))" :type="item.type?item.type:''"
:size="item.size?item.size:''" :disabled="item.disabled&&item.disabled(scope.row)"
:plain="plain">{{item.label}}</el-button>
</div>
</div>
</template>
</el-table-column>
</el-table>
<!-- 分頁 -->
<div style="padding: 10px;" v-if="paging" :style="{'text-align':pagingPosition}">
<el-pagination @size-change="handleNumberChange" @current-change="handleCurrentPage"
:current-page="searchData.page" :page-sizes="[10,15, 20, 30, 40,50]" :page-size="searchData.limit"
layout="total, sizes, prev, pager, next, jumper" :total="total">
</el-pagination>
</div>
</div>
</template>
<!-- /**
* 組件說明
* 屬性:
* 參數 說明 類型 默認值
* ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
* tableData 列表 的數據源 Array []
* treeProps 支持樹類型的數據的列表顯示 Object {children: 'children'}
* rowKey 樹類型的數據 列表必須要指定 String '_id'
* serialNumber 是否需要序號 Boolean true
* headerAlign 表頭對齊方式/復選框/序號 String 'left'/'center'/'right'
* tableLabel 動態表頭渲染數組 Array []
* choice 是否開啟多選復選框 Boolean false
* operation 操作列表按鈕 Object {}
* total 分頁總頁數 number 0
* paging 是否開啟分頁 Boolean false
* pagingPosition 分頁底部的位置 String 'left'/'center'/'right'
* fixedHeight 固定table列表高度 number 0
* pagingPage 分頁參數 Object {pageSize: 20,page: 1}
* headButton 列表頭部按鈕是否顯示 Boolean false
* 回調事件:
* select 獲取復選框選中對象 返回數組
* sortChange 獲取當前點擊表頭指定排序結果
* handleCurrentPage 每次切換頁數觸發並且回調頁數
* handleNumberChange 每次切換展示的條數觸發並且回調
*/ -->
<script>
const defaultImg = require('../../assets/image/user.png')
export default {
components: {
},
props: {
plain: {
type: Boolean,
default: true
},
headButton: {
type: Boolean,
default: false
},
tableData: { // 數據
type: Array,
default: () => ([])
},
treeProps: { // 支持樹類型的數據的顯示
type: Object,
default: () => ({
children: 'children'
})
},
rowKey: { //樹類型的數據 列表必須要指定row-key id
type: String,
default: '_id'
},
serialNumber: { // 是否需要序號
type: Boolean,
default: true
},
headerAlign: {
type: String,
default: 'left'
},
tableLabel: {
type: Array,
default: () => ([])
},
choice: {
type: Boolean,
default: false
},
operation: {
type: Object,
default: () => ({})
},
total: {
type: Number,
default: 0
},
paging: {
type: Boolean,
default: false
},
pagingPosition: {
type: String,
default: 'left'
},
fixedHeight: {
type: Number,
default: 0
},
pagingPage: {
type: Object,
default: () => ({
limit: 15,
page: 1
})
},
// 設置偏移高度(到達每個頁面不同內容高度,都可以讓列表高度填充滿整個可視區)
difference:{
type: Number,
default: 0
}
},
data() {
return {
defaultImg: defaultImg,
tableHeight: document.documentElement.clientHeight-(70+80), // 表格自適應高度 默認撐滿
// 分頁固定參數
searchData: {
limit: this.pagingPage.limit,
page: this.pagingPage.page
}
}
},
watch: {
},
created() {
},
methods: {
// 重置分頁參數
pagingReset(limit,page){
if(!limit && !page){
this.searchData.limit = 15;
this.searchData.page = 1
} else if(limit){
this.searchData.limit = limit;
} else {
this.searchData.page = page
}
},
test(){
console.log('添加事件')
},
// 切換頁數
handleCurrentPage(val) {
this.searchData.page = val
this.$emit('handleCurrentPage', val)
},
// 每頁N展示條
handleNumberChange(val) {
this.searchData.limit = val
this.$emit('handleNumberChange', val)
},
// 復選框勾選
select(row) {
this.$emit('select', row)
},
// 排序
sortChange(column, prop, order) {
this.$emit('sortChange', column)
},
// 點擊列表 獲取數據
handleCurrentChange(row) {
// console.log(row)
}
}
}
</script>
<style scoped>
/* 默認el-table 行高過於高,這里設置減少padding之間的間距 */
/deep/ th {
padding: 9px 0;
}
/deep/ .el-table td {
padding: 9px 0;
}
</style>
我是馬丁的車夫,歡迎轉發收藏!
