需求实现目标:点击table的任意cell就可以编辑里面的内容
思路:
- 表格里的cell有两种标签展示一个是普通的文本展示标签(div,span 等),一种是input标签
- 双击事件发生时切换两种标签的展示
- input失去焦点时再次切换标签展示
- 记录当前编辑的cell信息
关系图如下:
1.使用elementUi实现一个普通的表格组件数据纯展示
<template>
<div>
<el-table :data="tableData.list" >
<template v-for="col of tableColumns" :key="col.prop || col.label">
<el-table-column
v-slot="{ row, column }"
:prop="col.prop"
:label="col.label"
>
<span>{{ row[col.prop] }}</span>
</el-table-column>
</template>
</el-table>
</div>
</template>
<script setup>
import { ref ,watchEffect } from 'vue'
const props = defineProps({
tableData: {
type: Object,
default: ()=>[]
},
tableColumns: {
type: Array,
default: () => []
},
})
</script>
2.判断是都处于编辑状态
<template>
<div>
<el-table :data="tableData.list" @cell-click="handleTableCellClick">
<template v-for="col of tableColumns" :key="col.prop || col.label">
<el-table-column
v-slot="{ row, column }"
:prop="col.prop"
:label="col.label"
>
+++ 新增判断 根据是否处于编辑状态切换展示内容
<template v-if="checkCellIsEditing(row,column)">
<span>{{ row[col.prop] }}</span>
</template>
<template v-else>
// 处于编辑状态所展示的内容
</template>
</el-table-column>
</template>
</el-table>
</div>
</template>
<script setup>
import { ref ,watchEffect } from 'vue'
const props = defineProps({
tableData: {
type: Object,
default: ()=>[]
},
tableColumns: {
type: Array,
default: () => []
},
})
+++ 新增部分
// 当前编辑cell数据
const inEditingCell = ref(null)
// 判断是否在编辑状态
function checkCellIsEditing (row, col) {
return !!inEditingCell.value && inEditingCell.value.row.followId === row.followId && inEditingCell.value.col.property === col.property
}
// 把当前点击的单元格保存到inEditingCell中
const handleTableCellClick = (row, col) => {
if(checkCellIsEditing(row, col)) {
return
}
inEditingCell.value = {row,col}
}
</script>
3.定制一个处于可编辑状态的组件(该组件的表现形式并不唯一,所以我们可以由外部提供)
思路
//编辑组件的完整代码如下
<script setup lang='jsx'>
const createQuickEditComponent = ({ submit, initialValue }) => ({
setup() {
const inputComponent = ref(null);
const localValue = ref(initialValue);
watchEffect(
() => {
if (inputComponent.value) {
inputComponent.value.focus();
}
},
{
flush: "post",
}
);
return { localValue, inputComponent };
},
render() {
return (
<el-input
ref="inputComponent"
v-model={this.localValue}
onBlur={() => submit(this.localValue)}
></el-input>
);
},
});
</script>
QuickEditTable.vue与编辑组件交互
<template>
<div>
<el-table :data="tableData.list" @cell-click="handleTableCellClick">
<template v-for="col of tableColumns" :key="col.prop || col.label">
<el-table-column
v-slot="{ row, column }"
:prop="col.prop"
:label="col.label"
>
// 根据是否处于编辑状态切换展示内容
<template v-if="checkCellIsEditing(row,column)">
<span>{{ row[col.prop] }}</span>
</template>
<template v-else>
// 处于编辑状态所展示的内容
<component :is="editCellComponent" />
</template>
</el-table-column>
</template>
</el-table>
</div>
</template>
<script setup>
import { ref ,watchEffect ,shallowRef} from 'vue'
const props = defineProps({
tableData: {
type: Object,
default: ()=>[]
},
tableColumns: {
type: Array,
default: () => []
},
+++ 新增 外部传进的编辑组件
createQuickEditComponent:{
type:Function,
default:()=>()=>{}
}
})
// 当前编辑cell数据
const inEditingCell = ref(null)
// 编辑组件
const editCellComponent = shallowRef(null)
// 判断是否在编辑状态
function checkCellIsEditing (row, col) {
return !!inEditingCell.value && inEditingCell.value.row.followId === row.followId && inEditingCell.value.col.property === col.property
}
+++ 新赠 click事件触发与编辑组件的一系列交互
const handleTableCellClick = (row, col) => {
if(checkCellIsEditing(row, col)) {
return
}
// 提交后清空数据
const exit = () => { inEditingCell.value = null }
const component = requestQuickEdit({ row, col, exit })
if (!component) {
return
}
inEditingCell.value = { row, col }
editCellComponent.value = component
}
+++ 新增 调用外部传的编辑组件
function requestQuickEdit({ row, col, exit }) {
const initialValue = row[col.property]; // 初始值
return props.createQuickEditComponent({
submit(val) {
exit();
row[col.property] = val;
},
initialValue,
});
}
</script>
4.组件使用
<template>
<QuickEditTable :table-columns="columns" :table-data="tableData"
:create-quick-edit-component="createQuickEditComponent" />
</template>
<script setup lang="jsx">
import { ref, reactive,watchEffect } from "vue";
import QuickEditTable from "./components/QuickEditTable.vue";
const columns = [
{ label: "日期", prop: "dateDesc" },
{ label: "存在问题", prop: "problem" },
{ label: "问题诊断", prop: "diagnosis" },
{ label: "解决办法/下次沟通关注点", prop: "solution" },
{ label: "备注", prop: "remark" },
];
const tableData = reactive({
list: [
{
dateDesc: "入职第一周",
problem: "problem",
diagnosis: "diagnosis",
solution: "solution",
remark: "remark",
},
],
});
// 创建编辑组件
const createQuickEditComponent = ({ submit, initialValue }) => ({
setup() {
const inputComponent = ref(null);
const localValue = ref(initialValue);
watchEffect(
() => {
if (inputComponent.value) {
inputComponent.value.focus();
}
},
{
flush: "post",
}
);
return { localValue, inputComponent };
},
render() {
return (
<el-input
ref="inputComponent"
v-model={this.localValue}
onBlur={() => submit(this.localValue)}
></el-input>
);
},
});
</script>