实现一个可编辑的表格,让用户可以修改表格中的数据,并且能够清楚地看到哪些单元格被修改过。这样的功能可以提高用户体验,也方便后端处理数据的变化。
本文将介绍如何使用Vue.js和Element UI的el-table组件来实现一个可编辑表格,并且修改的单元格会有不同的背景色。
代码实现
首先创建一个el-table组件,给它绑定一个data属性,用来存储表格的数据。给每个el-table-column设置一个prop属性,用来指定每一列对应的数据字段。使用v-for指令来动态生成表格的列,根据一个tableColumn数组,里面存储了每一列的信息,比如label,prop,fixed等。可以给el-table添加一些事件监听,比如cell-mouse-enter,cell-mouse-leave,cell-click等,用来实现鼠标移入移出和点击单元格的效果。代码如下:
<el-table ref="multipleTable" stripe :border=true :data="tableData"
@cell-mouse-enter="handleCellEnter" @cell-mouse-leave="handleCellLeave" @cell-click="handleCellClick"
:cell-style="cellstyle">
<el-table-column width=120 v-for="column in tableColumn" :key="column.aliasColName"
:prop="column.aliasColName" :label="column.text" :fixed="column.fixed">
<div class="item" v-if="column.editStyle == 5"
slot-scope="scope">
<el-input class="item__input" v-model="scope.row[scope.column.property]" placeholder="请输入内容">
<i slot="suffix" class="el-icon-edit" @click="showPwd(scope.row, scope.$index, scope.column)"></i>
</el-input>
<div class="item__txt">{{ scope.row[scope.column.property] }}</div>
</div>
<div class="item" v-else-if="column.editStyle == 22" slot-scope="scope">
<el-select v-model="scope.row[scope.column.property]" placeholder="请选择">
<el-option v-for="item in listArray" :key="item.value" :label="item.display" :value="item.value">
</el-option>
</el-select>
</div>
</el-table-column>
<el-table-column fixed="right" label="操作" width="120" v-if="!visremove">
<div class="item" slot-scope="scope">
<el-popconfirm confirm-button-text='好的' cancel-button-text='取消' icon="el-icon-info" icon-color="red"
title="确定删除吗?" @confirm="removerow(scope.row)">
<el-button slot="reference" type="text" size="small">删除</el-button>
</el-popconfirm>
</div>
</el-table-column>
</el-table>
接下来需要在data中定义一些变量,用来存储表格的数据,列的信息,下拉框的选项,以及一些控制变量,比如clickSwitch,用来记录当前点击的单元格,clickCellMap,用来存储当前点击的单元格的DOM元素,tableDataCopy,用来存储表格数据的副本,用于和修改后的数据进行对比。代码如下:
data() {
return {
tableData: [], //表格数据
tableColumn: [], //表格列信息
listArray: [], //下拉框选项
clickSwitch: { //当前点击的单元格
row: "",
col: ""
},
clickCellMap: [], //当前点击的单元格的DOM元素
tableDataCopy: [], //表格数据的副本
};
},
然后,需要在mounted中调用一个loadtabledata方法,用来加载表格的数据和列的信息。这里使用了一个模拟的数据文件loadData.json,里面存储了表格的数据和列的信息。根据实际的需求,从后端获取数据或者自定义数据。还需要使用JSON.parse和JSON.stringify方法,来创建一个表格数据的副本,用于后续的对比。代码如下:
mounted() {
this.loadtabledata();
},
methods: {
//表格
loadtabledata() {
let resloadtabledata = require("@/artificialdata/loadData.json")
this.tableData = resloadtabledata.data.data
this.tableDataCopy = JSON.parse(JSON.stringify(resloadtabledata.data.data))
},
}
接下来实现一些事件处理的方法,用来实现鼠标移入移出和点击单元格的效果。handleCellEnter方法用来处理鼠标移入单元格的事件。获取当前单元格的column和cell,然后判断是否有prop属性,如果有,说明是可编辑的单元格,就给它的item__txt类添加一个item__txt–hover类,用来显示一个编辑图标,提示用户可以点击编辑。代码如下:
/** 鼠标移入cell */
handleCellEnter(row, column, cell, event) {
const property = column.property
if (property) {
cell.querySelector('.item__txt').classList.add('item__txt--hover')
}
},
然后,需要实现一个handleCellLeave方法,用来处理鼠标移出单元格的事件。需要获取当前单元格的column和cell,然后判断是否有prop属性,如果有,说明是可编辑的单元格,就给它的item__txt类移除一个item__txt–hover类,用来隐藏编辑图标。代码如下:
/** 鼠标移出cell */
handleCellLeave(row, column, cell, event) {
const property = column.property
if (property) {
cell.querySelector('.item__txt').classList.remove('item__txt--hover')
}
},
接下来,实现一个handleCellClick方法,用来处理点击单元格的事件。获取当前单元格的row,column,cell,然后判断是否是同一个单元格,如果是,就不做任何操作,如果不是,就记录当前点击的单元格的信息,存储到clickSwitch变量中。然后,需要判断是否有之前点击的单元格,如果有,就触发它的失焦事件,让它保存数据,并且切换它的显示状态,让它显示文本,隐藏输入框。最后,切换当前点击的单元格的显示状态,让它显示输入框,隐藏文本,并且让输入框获取焦点。代码如下:
/** 点击cell */
handleCellClick(row, column, cell, event) {
if (this.clickSwitch.row == row.id && this.clickSwitch.col == column.property) {
return
}
this.clickSwitch.row = row.id
this.clickSwitch.col = column.property
const property = column.property
// 保存cell
if (this.clickCellMap.length > 0 ) {
this.clickCellMap[0].querySelector('input').blur()
}
if (this.clickCellMap.length > 0) {
this.clickCellMap[0].querySelector('.item__txt').style.display = 'block'
this.clickCellMap[0].querySelector('.item__input').style.display = 'none'
}
this.clickCellMap[0]=cell
cell.querySelector('.item__txt').style.display = 'none'
cell.querySelector('.item__input').style.display = 'block'
cell.querySelector('input').focus()
},
最后实现一个cellstyle方法,用来设置单元格的样式。需要获取当前单元格的row,column,rowIndex,columnIndex,然后判断当前单元格的值是否和表格数据副本中的值相同,如果不同,就说明该单元格被修改过,就给它返回一个背景色的样式,比如"background-color: rgb(144 199 255);",让它显示为蓝色。这样,用户就可以一眼看出哪些单元格被修改过,哪些没有。代码如下:
cellstyle({ row, column, rowIndex, columnIndex }) {
if (this.tableDataCopy[rowIndex][column.property] != row[column.property]) {
return "background-color: rgb(144 199 255);"
}
},
效果展示
表格中有两种类型的可编辑单元格,一种是输入框,一种是下拉框。当鼠标移入一个可编辑的单元格时,它会显示一个编辑图标,提示可以点击编辑。当点击一个可编辑的单元格时,它会显示一个输入框或者下拉框修改数据。当修改完数据后,按下回车键或者点击其他地方,它会保存数据,并且切换回文本显示。同时可以看到,修改过的单元格会有一个蓝色的背景色,清楚地看到数据的变化。还可以点击右侧的删除按钮,删除一行数据。代码如下:
cellstyle({ row, column, rowIndex, columnIndex }) {
if (this.tableDataCopy[rowIndex][column.property] != row[column.property]) {
return "background-color: rgb(144 199 255);"
}
},
.el-input__icon {
line-height: 24px !important;
}
.el-button--text {
height: 24px;
}
.item {
.el-input--suffix .el-input__inner {
padding-right: 20px;
padding-left: 10px;
}
.el-input__inner {
height: 24px !important;
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;
}
.item__input {
display: none;
}
.item__txt {
box-sizing: border-box;
border: 1px solid transparent;
width: 100px;
line-height: 24px;
padding: 0 8px;
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;
}
.item__txt--hover {
border: 1px solid #dddddd;
border-radius: 4px;
cursor: text;
}
}
.el-table {
.el-table__cell {
padding: 6px 0 !important;
}
}