在Element UI的el-table中实现行内编辑,主要有两种主流方法:一种是通过条件渲染 在单元格内切换文本和表单组件,另一种是封装可复用的编辑组件。
条件渲染方法
这种方法的核心是使用 v-if
和 v-else
根据当前行是否处于编辑状态,来切换显示普通文本或输入框。
核心步骤:
-
数据准备 :为表格数据源的每个对象添加一个状态字段(如
isSet
或edit
),用于控制当前行(或单元格)的编辑模式。 -
模板定义 :在
el-table-column
的插槽模板中,根据状态字段条件渲染文本或表单组件。 -
操作按钮:在操作列提供"编辑/保存"、"取消/删除"等按钮,并绑定对应的方法来切换状态和执行业务逻辑。
示例代码:
下面的例子展示了如何实现一个包含编辑和保存功能的行内编辑表格。
html
<template>
<el-table :data="tableData" border style="width: 100%">
<!-- 姓名列 -->
<el-table-column prop="name" label="姓名">
<template slot-scope="scope">
<span v-if="!scope.row.isEdit">{{ scope.row.name }}</span>
<el-input v-else v-model="scope.row.editName" size="mini"></el-input>
</template>
</el-table-column>
<!-- 操作列 -->
<el-table-column label="操作" width="180">
<template slot-scope="scope">
<!-- 非编辑状态下的按钮 -->
<el-button
v-if="!scope.row.isEdit"
size="mini"
@click="enterEdit(scope.row)">
编辑
</el-button>
<el-button
v-if="!scope.row.isEdit"
size="mini"
type="danger">
删除
</el-button>
<!-- 编辑状态下的按钮 -->
<el-button
v-else
size="mini"
type="success"
@click="saveEdit(scope.row)">
保存
</el-button>
<el-button
v-else
size="mini"
@click="cancelEdit(scope.row)">
取消
</el-button>
</template>
</el-table-column>
</el-table>
</template>
<script>
export default {
data() {
return {
tableData: [
{ id: 1, name: '张三', isEdit: false, editName: '' },
{ id: 2, name: '李四', isEdit: false, editName: '' },
// ... 更多数据
]
};
},
methods: {
enterEdit(row) {
// 进入编辑状态,备份当前数据
row.isEdit = true;
row.editName = row.name;
},
saveEdit(row) {
// 保存编辑,可以在这里发送AJAX请求
row.name = row.editName;
row.isEdit = false;
// 调用API提交更改
},
cancelEdit(row) {
// 取消编辑,恢复备份的数据
row.isEdit = false;
row.editName = '';
}
}
};
</script>
自定义编辑组件方法
对于更复杂或需要高度复用的场景,可以封装一个自定义的编辑单元格组件,使编辑逻辑更加清晰和内聚。
核心思路:
创建一个名为 EditableCell
的组件,它根据外部传入的 canEdit
属性来决定是显示普通的文本内容,还是一个可交互的表单组件。
示例组件 (EditableCell.vue
):
html
<template>
<div @click="onCellClick" class="edit-cell">
<!-- 非编辑模式下显示内容,鼠标悬停有提示 -->
<el-tooltip
v-if="!isEditing"
content="点击编辑"
placement="top">
<div class="cell-content">
<slot name="content">{{ value }}</slot>
</div>
</el-tooltip>
<!-- 编辑模式下显示输入组件 -->
<component
v-else
:is="editableComponent"
ref="inputRef"
v-bind="$attrs"
v-model="currentValue"
@blur="onInputExit"
@change="onInputExit">
<slot name="edit-component-slot"></slot>
</component>
</div>
</template>
<script>
export default {
name: 'EditableCell',
props: {
value: [String, Number, Date], // 单元格的值
canEdit: Boolean, // 是否可编辑
editableComponent: { // 使用的编辑组件类型
type: String,
default: 'el-input'
}
},
data() {
return {
isEditing: false,
currentValue: this.value
};
},
watch: {
value(newVal) {
this.currentValue = newVal;
}
},
methods: {
onCellClick() {
if (this.canEdit && !this.isEditing) {
this.isEditing = true;
// 下一个tick聚焦输入框
this.$nextTick(() => {
const input = this.$refs.inputRef;
if (input && input.focus) input.focus();
});
}
},
onInputExit() {
if (this.isEditing) {
this.isEditing = false;
// 将值传递回父组件
this.$emit('input', this.currentValue);
this.$emit('change', this.currentValue);
}
}
}
};
</script>
<style scoped>
.edit-cell {
min-height: 25px;
cursor: pointer;
}
.cell-content {
padding: 8px 0;
}
</style>
在表格中使用自定义组件:
html
<template>
<div id="app">
<el-table :data="gridData">
<el-table-column label="姓名" min-width="150">
<template slot-scope="{row}">
<editable-cell
:can-edit="true"
v-model="row.name">
<span slot="content">{{ row.name }}</span>
</editable-cell>
</template>
</el-table-column>
<el-table-column label="性别" min-width="120">
<template slot-scope="{row}">
<editable-cell
:can-edit="true"
editable-component="el-select"
v-model="row.gender">
<!-- 非编辑状态下显示的内容 -->
<el-tag
slot="content"
:type="row.gender === 'M' ? 'primary' : 'danger'">
{{ row.gender === 'M' ? '男' : '女' }}
</el-tag>
<!-- 编辑状态下,下拉框的选项 -->
<template slot="edit-component-slot">
<el-option value="M" label="男"></el-option>
<el-option value="F" label="女"></el-option>
</template>
</editable-cell>
</template>
</el-table-column>
</el-table>
</div>
</template>
<script>
import EditableCell from './components/EditableCell.vue';
export default {
components: { EditableCell },
data() {
return {
gridData: [
{ date: '2016-05-03', name: '汤姆', gender: 'M' },
{ date: '2016-05-02', name: '丽莎', gender: 'F' }
]
};
}
};
</script>