记录一下在对el-tabel进行简单封装并实现行内编辑,单元格合并等功能
<el-table
id="iTable"
v-loading.iTable="options.loading"//是否添加表格loading加载动画
:data="list"//数据列
:stripe="options.stripe"// 是否添加表格loading加载动画
ref="multipleTable"// 是否支持列表项选中功能
border
:default-sort="{order: 'descending'}"
@selection-change="handleSelectionChange"
@filter-change="filterchange"
:header-cell-style="rowClass"//多级表头控制样式
:header-cell-class-name="headerStyle"//表头样式
:row-class-name="tableRowClassName"//行样式
:span-method="objectSpanMethod"//合并单元格
:height="height"//高度
size="small"
:row-style="{height:'30px'}"
:cell-style="{padding:'0px'}"
@row-click="rowclick"//行点击事件
@row-dblclick="dblclick"//双击
@row-contextmenu="contmenuclick"//右键
@cell-click="cellclick"//单元格事件
>
<template v-if="columns.show">//是否为多级,如果为多级,另一个组件循环(代码放下面)
<my-column v-for="(item,index) incolumns.data" :key="index" :col="item">
<template v-else>
<template v-for="(column, index) incolumns">
:prop="column.prop"
:key="column.label"
:label="column.label"
:align="column.align"
:min-width="column.width"
:fixed="column.fixed"
:filters="column.filters"
sortable
>
<template slot-scope="scope">
<template v-if="!column.render">
<template v-if="column.formatter">
<span v-if="scope.row.isEdit&&column.isEdit&&!column.isSelect">
<el-input size="mini" placeholder="请输入内容" @click.stop.native="" v-model="scope.row[column.prop]">
<span v-else-if="scope.row.isEdit&&column.isEdit&&column.isSelect">
<el-select v-model="scope.row[column.prop]" placeholder="請輸入">
v-for="item in column.SelectObj"
:key="item.value"
:label="item.label"
:value="item.value">
<span v-else-if="scope.row.isEdit&&column.isEdit&&column.isDate">
v-model="scope.row[column.prop]"
type="datetime"
placeholder="Select date and time"
default-time="12:00:00">
<span v-else="!scope.row.isEdit" :style="column.style!=null||''?column.style:''" v-html="column.formatter(scope.row, column)">
<template v-else>
<span v-if="scope.row.isEdit&&column.isEdit&&!column.isSelect&&!column.isDate">
<el-input size="mini" placeholder="请输入内容" @click.stop.native="" v-model="scope.row[column.prop]">
<span v-else-if="scope.row.isEdit&&column.isEdit&&column.isSelect">
<el-select v-model="scope.row[column.prop]" placeholder="請輸入">
v-for="item in column.SelectObj"
:key="item.value"
:label="item.label"
:value="item.value">
<span v-else-if="scope.row.isEdit&&column.isEdit&&column.isDate">
v-model="scope.row[column.prop]"
type="date"
placeholder="Pick a day"
>
<span v-else="!scope.row.isEdit" :style="column.style!=null||''?column.style:''">{{scope.row[column.prop]}}
<template v-else>
:column="column"
:row="scope.row"
:render="column.render"
:index="index"
>
ref="fixedColumn"
label="操作"
align="center"
:width="operates.width"
:fixed="operates.fixed"
v-if="operates.list.filter(_x=>_x.show=== true).length > 0"
>
<template slot-scope="scope">
<div class="operate-group">
v-if="!scope.row.isEdit"
type="primary"
size="mini"
icon="el-icon-edit"
plain
round
@click.stop="EditButtonEvent(scope.$index, scope.row)">编辑
v-if="!scope.row.isEdit"
size="mini"
type="danger"
icon="el-icon-delete"
plain
round
@click.stop="DeleteButtonEvent(scope.$index, scope.row)">删除
v-if="scope.row.isEdit"
size="mini"
type="info"
icon="el-icon-refresh-right"
plain
round
@click.stop="CancelButtonEvent(scope.$index, scope.row)">取消
v-if="scope.row.isEdit"
size="mini"
type="success"
icon="el-icon-refresh"
plain
round
@click.stop="SaveButtonEvent(scope.$index, scope.row)">保存
<div class="pagination" v-show="pageShow">
@size-change="handleSizeChange"
@current-change="handleIndexChange"
:page-size="pageSize"
:page-sizes="[5,10,20,30,50,100]"
:current-page="pageIndex"
layout="total,sizes, prev, pager, next,jumper"
:total="total"
>
import MyColumnfrom "./MyColumn";
export default {
props: {
// 数据列表
list: {
type: Array,
default: []
},
//表格高度
height: {
type: Number,
default:400
},
// 需要展示的列 === prop:列数据对应的属性,label:列名,align:对齐方式,width:列宽
columns: {
type: [Array, Object],
default: []
},
// 总数
total: {
type: Number,
default:0
},
// 每页显示的数量
pageSize: {
type: Number,
default:10
},
// 操作按钮组 === label: 文本,type :类型(primary / success / warning / danger / info / text),
// show:是否显示,icon:按钮图标,plain:是否朴素按钮,disabled:是否禁用,method:回调方法
operates: {},
// table 表格的控制参数
options: {
type: Object,
default: {
// 是否为斑马纹 table
stripe:false,
// 是否要高亮当前行
highlightCurrentRow:false
}
},
//需要合并的数据源
mergeData:{
type: [Array,Object],
default: ()=>({
data:[],//要合并的数据源
columnIndex:[],//要合并的列的索引
columnName:[],//要合并的列的名称
}),
},
//需要表示状态行的标识
rowSign:{
type:[Array,Object],
default:()=>({
index:[],//比较字段在对象中的索引
type:'',//判断是什么操作(状态值、正负值、区间值比)
data:[],//需要比较的值、以及返回表格类样式
})
},
//是否需要分页部分
pageShow:{
type:Boolean,
default:true
}
},
//组件
components: {
MyColumn,
expandDom: {
functional:true,
props: {
row: Object,
render: Function,
index: Number,
column: {
type: Object,
default:null
},
},
render:(h, ctx) =>{
const params = {
row: ctx.props.row,
index: ctx.props.index,
size: ctx.props.size,
round: ctx.props.round,
circle: ctx.props.circle,
plain: ctx.props.plain,
show: ctx.props.show
};
if (ctx.props.column) params.column = ctx.props.column;
//实现下拉框
if(ctx.props.row.isEdit&&ctx.props.column.isSelect)
{
return h('el-select',{
props:{
value:ctx.props.row.state
},
on: {
'change':(event) => {
ctx.props.row.state=event;
}
},
},[ctx.props.column.SelectObj.map((val) => {// 下拉框里的内容,optionList下拉框数据
return h('el-option', {
props: {
value: val.value,
label: val.label
}
})
})
]);
}
//实现输入框
if(ctx.props.column.isEdit&&!ctx.props.column.isSelect)
{
debugger;
return h('input',{
style:{
height:'28px !important',
'border-radius':'4px !important',
border:'1px solid #DCDFE6',
},
domProps: {
value:params.row.state
},
props:{
value:params.row.state
},
on: {
click(event){
event.stopPropagation();
},
input(event) {
params.row.state=event.target.value;
}
}
})
}
return ctx.props.render(h, params);
}
}
},
// 数据
data() {
return {
position:0,
rowSpanArr: [],
pageIndex:1,
multipleSelection:[],
rowInfo: [],//选中行数据
};
},
created(){
this.getRowSpan();
},
mounted() {},
computed: {},
methods: {
//切换每页显示的条数
handleSizeChange(size) {
this.pageIndex =1;
this.$emit("handleSizeChange", size);
},
// 切换页码
handleIndexChange(index) {
this.$emit("handleIndexChange", index);
this.pageIndex = index;
},
// 多行选中
handleSelectionChange(val) {
this.multipleSelection = val;
this.$emit("handleSelectionChange", val);
},
//table行样式设置
tableRowClassName({ row, rowIndex }) {
switch (this.rowSign.type) {
case 'state':
for(let i=0;i
{
if(Object.values(row)[this.rowSign.index]===this.rowSign.data[i].Id)
return this.rowSign.data[i].className;
}
break;
case 'bool':
if(Object.values(row)[this.rowSign.index[0]]>0)
return 'success-row';
else if(Object.values(row)[this.rowSign.index[0]]<0)
return 'warning-row';
break;
case 'section':
let num=Object.values(row)[this.rowSign.index[0]];
for(let i=0;i
{
if(num>=this.rowSign.data[i].Number1&&num<=this.rowSign.data[i].Number2)
return this.rowSign.data[i].className;
}
break;
default:
break;
}
return "";
},
//合并单元格
objectSpanMethod({ row, column, rowIndex, columnIndex }) {
if(this.mergeData.columnIndex.length>0)
{
for(let i=0;i
{
if (columnIndex ===this.mergeData.columnIndex[i]) {
const _row =this.rowSpanArr['rowSpanArr'+i][rowIndex];
const _col = _row >0 ?1 :0;
return {
rowspan: _row,
colspan: _col
}
}
}
}
},
// 获取合并的数组
getRowSpan() {
let that=this;
this.rowSpanArr = {};
let data_=that.mergeData.data;
for(let i=0;i
{
let name=that.mergeData.columnName[i];
that.mergeData.data.forEach((item, index) => {
if (index===0) {
that.rowSpanArr['rowSpanArr'+i] =[];
that.rowSpanArr['rowSpanArr'+i].push(1);
that.position =0;
}else {
if (data_[index][name]===data_[index -1][name]) {
that.rowSpanArr['rowSpanArr'+i][that.position] +=1; //项目名称相同,合并到同一个数组中
that.rowSpanArr['rowSpanArr'+i].push(0);
data_[index][name] = data_[index -1][name];
}else {
that.rowSpanArr['rowSpanArr'+i].push(1);
that.position = index;
}
}
});
}
},
//筛选方法
filterchange(value) {
this.$emit("filterchange", value);
return value;
},
//table单击事件
rowclick(row, col, event) {
this.$emit("rowclick", row, col, event);
},
//双击事件
dblclick(val) {
this.$emit("dblclick", val);
},
//右键事件
contmenuclick(val) {
this.$emit("contmenuclick", val);
},
//单元格点击事件
cellclick(row, col, cell, event) {
this.$emit("cellclick", row, col, cell, event);
},
rowClass({ row, rowIndex}){
return "background:rgba(236,240,245,0.4)";
},
headerStyle ({row, column, rowIndex, columnIndex}) {
if(row&&row[0].children)
{
return 'speHeader';
}
},
//编辑按钮事件
EditButtonEvent(index,row)
{
this.$emit("EditButtonEvent", index, row);
},
//删除按钮事件
DeleteButtonEvent(index,row)
{
this.$emit("DeleteButtonEvent", index, row);
},
//取消按钮事件
CancelButtonEvent(index,row)
{
this.$emit("CancelButtonEvent", index, row);
},
//保存按钮事件
SaveButtonEvent(index,row)
{
this.$emit("SaveButtonEvent", index, row);
}
},
watch:{
mergeData:{
handler(newVal,oldVal){
this.getRowSpan();
},
deep:true,
immediate:true
},
}
};
.el-table .warning-row {
background:#fd9165;
}
.el-table .success-row {
background:#94f987;
}
.el-table .danger-row {
background:#f9400b;
}
.el-table .primary-row {
background:#abb7f9;
}
.speHeader{
color:blue
}
.el-input__inner{
height:28px !important;;
}
:prop="col.prop"
:label="col.label"
:min-width="col.width"
:fixed="col.fixed"
align="center"
:filters="col.filters"
>
<template slot-scope="scope">
<template v-if="!col.render">
<template v-if="col.formatter">
<span v-if="scope.row.isEdit&&col.isEdit&&!col.isSelect">
<el-input size="mini" placeholder="请输入内容" @click.stop.native="" v-model="scope.row[col.prop]">
<span v-else-if="scope.row.isEdit&&col.isSelect">
<el-select v-model="scope.row[col.prop]" placeholder="請輸入">
v-for="item incol.SelectObj"
:key="item.value"
:label="item.label"
:value="item.value">
<span v-else="!scope.row.isEdit" :style="col.style!=null||''?col.style:''" v-html="col.formatter(scope.row,col)">
<template v-else>
<span v-if="scope.row.isEdit&&col.isEdit&&!col.isSelect">
<el-input size="mini" placeholder="请输入内容" @click.stop.native="" v-model="scope.row[col.prop]">
<span v-else-if="scope.row.isEdit&&col.isEdit&&col.isSelect">
<el-select v-model="scope.row[col.prop]" placeholder="請輸入">
v-for="item incol.SelectObj"
:key="item.value"
:label="item.label"
:value="item.value">
<span v-else="!scope.row.isEdit" :style="col.style!=null||''?col.style:''">{{scope.row[col.prop]}}
<template v-else>
:column="col"
:row="scope.row"
:render="col.render"
:index="index">
<template v-if="col.children">
v-for="(item, index) incol.children"
:key="index"
:col="item"
>
export default {
name:"MyColumn",
props: {
col: {
type: Object
}
},
methods:{
myclass(){
return 'MyHeader'
},
}
}
<style scoped>
.el-table thead tr:nth-child(1) {
color:blue !important;
}
</style>