<template> <div style="margin: 20px 20px 100px 20px"> <el-table border class="customer-no-border-table" element-loading-text="数据正在加载中..." :row-class-name="tableRowClassName" :header-cell-style="{ background: '#E7F2FD', color: '#252525' }" style="width: 100%; border-top: 1px solid #409eff" v-loading="loading" :ref="tableName" :data="tableData" :highlight-current-row="light" @row-click="getrow" @sort-change="sortChange" @selection-change="handleSelectionChange" :row-key="rowKey" :reserve-selection="reserve" :max-height="fixedHeight > 0 ? fixedHeight : tableHeight - difference" > <!-- 复选框 --> <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()" > </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 : 'center'" :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 : 'center'" :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 : 'center'" :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 : 'center'" :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 : 'center'" :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 : 'center'" :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> <!-- 自定义 --> <el-table-column v-else-if="item.form === 'my'" :width="item.width" :label="item.label" :sortable="item.sort" :align="item.align ? item.align : 'center'" :key="index" show-overflow-tooltip > <template slot-scope="scope"> <span style="text-decoration: underline; color: blue" @click="item.callback(Object.assign({}, scope.row))" >{{ item.filter(scope.row) }}</span > </template> </el-table-column> <!-- 固定列 --> <el-table-column v-else-if="item.form === 'fixed'" :width="item.width" :label="item.label" :sortable="item.sort" :align="item.align ? item.align : 'center'" :key="index" > </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/nodata.png"); export default { props: { // ref的名字 tableName: { type: String, default: "", }, // 是否记忆分页选中行 reserve: { type: Boolean, default: false, }, // 是否高亮当前行 ligth: { type: Boolean, default: false, }, // 是否朴素按钮 plain: { type: Boolean, default: true, }, // 数据 tableData: { type: Array, default: () => [], }, // 支持树类型的数据的显示 treeProps: { type: Object, default: () => ({ children: "children", }), }, //树类型的数据 列表必须要指定row-key id rowKey: { type: String, default: "_id", }, // 是否需要序号 serialNumber: { type: Boolean, default: true, }, // 表头对齐方式 headerAlign: { type: String, default: "center", }, // 表头 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: 10, 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, }, }; }, methods: { tableRowClassName({ rowIndex }) { if (rowIndex % 2 === 1) { return "success-row"; } return ""; }, // 重置分页参数 pagingReset(limit, page) { if (!limit && !page) { this.searchData.limit = 10; this.searchData.page = 1; } else if (limit) { this.searchData.limit = limit; } else { this.searchData.page = page; } }, // 切换页数 handleCurrentPage(val) { this.searchData.page = val; this.$emit("handleCurrentPage", val); }, // 每页N展示条 handleNumberChange(val) { this.searchData.limit = val; this.$emit("handleNumberChange", val); }, //选中当前行 getrow(row) { this.$emit("getrow", row); }, // 复选框勾选 handleSelectionChange(array) { console.log(array, "array"); this.$emit("handleSelectionChange", array); }, // 排序 sortChange(column, prop, order) { console.log(column, "column"); console.log(prop, "prop"); console.log(order, "order"); this.$emit("sortChange", column); } }, }; </script> <style scoped lang='less'> /* 默认el-table 行高过于高,这里设置减少padding之间的间距 */ /deep/ th { padding: 9px 0; } /deep/ .el-table td { padding: 9px 0; } </style>
<template> <div> <table-List :tableData="tableData" :tableLabel="tableLabel" :choice="choice" :light="light" :reserve="reserve" :paging="paging" :operation="operation" :total="total" pagingPosition="center" headerAlign="center" @sortChange="sortChange" @getrow="getrow" @handleSelectionChange="handleSelectionChange" @handleNumberChange="handleNumberChange" @handleCurrentPage="handleCurrentPage" > </table-List> </div> </template> <script> import tableList from "./table.vue"; export default { components: { tableList, }, data() { return { light: true, //高亮当前行 paging: true, //是否分页 pagingPage: { limit: 10, page: 1, }, tableData: [ { nickName: "111", friendCount: 123 }, { nickName: "222", friendCount: 456 }, ], //数据源 tableLabel: [ { prop: "nickName", label: "用户昵称", align: "center", form: "filter", filter(row) { if ((row.nickName = "111")) { return `丫丫`; } else { return "哈哈"; } }, }, { prop: "friendCount", label: "好友数量", align: "center", form: "my", filter(row) { if (row.friendCount == "123") { return `百度`; } else { return "billbill"; } }, callback: (row) => { if (row.friendCount == "123") { window.open("https://www.baidu.com/?tn=02003390_19_hao_pg"); } else { window.open("https://blog.csdn.net/jlsdzhj/article/details/80647682"); } }, }, ], operation: { width: "220", Button: [ { label: "查看", size: "mini", authority: false, callback(k) { console.log(k); }, }, ], }, total: 0, }; }, methods: { // 分页 handleNumberChange(val) { console.log(val, "当前页码"); }, // 每一页展示多少条切换 handleCurrentPage(val) { console.log(val, "当前展示条数"); }, // 排序 sortChange(column) { console.log(column, "column"); }, //多选 handleSelectionChange(array) { console.log(array, "array"); this.selectList = array; }, // 单选 getrow(row) { console.log(row, "选中行"); this.trData = row; }, }, }; </script> <style lang="scss" scoped> </style> components:{tableList, }, data(){ return{ tableData: [ {nickName:"111",friendCount:123,},{nickName:"222",friendCount:456},{}],//数据源 tableLabel:[ { prop: 'nickName', label: '用户昵称', align: 'center', form:'filter', filter(row){ if(row.nickName='111'){ return '丫丫' }else{ return '哈哈' } } }, { 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){},//列表复选框 }