在前端开发时,可能会需要用到可编辑的表格控件。一些原生的UI框架并不支持Table控件的可编辑功能,所以只能自己实现。
以下用Vue3+Element-Plus进行示例开发。
一、实现可编辑的单元格
我想要实现的效果是,鼠标移动到el-table的某行时,该行呈现可编辑效果。所以需要用到Table事件中的cell-mouse-enter和cell-mouse-leave。当鼠标移入时,将该行数据源编辑状态字段置为true,相应的单元格模板借助v-if绑定呈现出可编辑状态;鼠标移出时,再将状态字段置为false,隐藏编辑状态模板。
完整代码如下:
<template>
<div>
<el-table :data="dataList" @cell-mouse-enter="handleCellEnter" @cell-mouse-leave="handleCellLeave">
<el-table-column type="index" width="50" />
<el-table-column label="名称" prop="name" width="120">
<template #default="scope">
<el-input v-if="scope.row.isEdit" class="cell-input" v-model="scope.row.name" />
</template>
</el-table-column>
<el-table-column label="类型" prop="type" width="150">
<template #default="scope">
<el-select v-if="scope.row.isEdit" class="cell-select" v-model="scope.row.type" placeholder="请选择">
<el-option v-for="item in TypeOptions" :key="item.value" :label="item.label" :value="item.value" />
</el-select>
</template>
</el-table-column>
<el-table-column label="值" prop="value" width="150" />
</el-table>
</div>
</template>
<script setup lang="ts">
import { reactive } from 'vue';
interface TempData {
name: string,
type: string,
value: string,
isEdit: boolean
}
const TypeOptions = [
{
value: 'Option1',
label: 'Option1',
},
{
value: 'Option2',
label: 'Option2',
},
{
value: 'Option3',
label: 'Option3',
}
]
const dataList = reactive<TempData[]>([
{
name: '张三',
type: 'Option1',
value: 'value',
isEdit: false
},
{
name: '李四',
type: 'Option2',
value: 'value',
isEdit: false
},
{
name: '王五',
type: 'Option3',
value: 'value',
isEdit: false
}
])
const handleCellEnter = (row: any, column: any, cell: any, event: any) => {
row.isEdit = true
}
const handleCellLeave = (row: any, column: any, cell: any, event: any) => {
row.isEdit = false
}
</script>
<style scoped>
.cell-input {
height: 26px;
margin-left: -10px;
}
:deep(.cell-select .el-select__wrapper) {
height: 26px;
min-height: 26px;
margin-left: -11px;
}
:deep(.el-table .el-table__row) {
height: 50px;
}
</style>
(说明:以上代码示例中,对编辑状态下的el-input和el-select样式进行了处理,使鼠标移入移出时不会出现明显的错位现象)
二、解决el-select下拉内容无法选择问题
通常el-select的下拉框会超出所在行的范围,因此当鼠标准备选择下拉框内容时,会因超出行的范围而触发取消编辑状态,el-select就会消失,这样一来永远无法选中下拉选项。
解决的方法便是记录el-select的状态,如果是下拉状态,则el-table的鼠标事件不要触发行状态更改。变更部分代码如下:
let canUpdateEditingState = false
const handleOptionVisibleChange = (isVisible: boolean, row: any) => {
canUpdateEditingState = isVisible
if (!isVisible) {
row.isEdit = false
}
}
const handleCellEnter = (row: any, column: any, cell: any, event: any) => {
if (canUpdateEditingState) return
row.isEdit = true
}
const handleCellLeave = (row: any, column: any, cell: any, event: any) => {
if (canUpdateEditingState) return
row.isEdit = false
}
然后给el-select绑定事件方法如下:
@visible-change="(arg: any) => handleOptionVisibleChange(arg, scope.row)"
三、解决el-input无法使用中文输入法的问题
由于输入中文时,输入法弹框也会触发el-table的cell-mouse-leave事件,导致刚打出字符,单元格的编辑状态便取消了。这就需要借助compositionstart和compositionend事件来屏蔽中文输入过程。原理和第二点类似,补充代码如下:
const handleCompositionStart = () => {
canUpdateEditingState = true
}
const handleCompositionEnd = () => {
canUpdateEditingState = false
}
给el-table增加事件绑定:
@compositionstart="handleCompositionStart" @compositionend="handleCompositionEnd"