根据关键字合并表格
- 1.实现初始化表格
- 2.实现添加班级与学生的功能
- 3.添加的弹窗
- 4.删除班级
- 5.删除学生
首先看最终实现的效果
1.实现初始化表格
<template>
<div class="main-page">
<div class="flex-end">
<div class="public-search">添加班级</div>
</div>
<el-table border :data="tableData" stripe style="width: 100%;" :span-method="objectSpanMethod">
<el-table-column label="班级" align="center" prop="class" />
<el-table-column label="姓名" align="center" prop="name" />
<el-table-column label="课程" align="center" prop="course" />
<el-table-column label="备注" align="center" prop="remark" />
<el-table-column fixed="right" label="删除学生" align="center">
<template #default="scope">
<span class="del-btn">删除</span>
</template>
</el-table-column>
<el-table-column fixed="right" label="操作" align="center">
<template #default="scope">
<span class="add-btn">添加学生</span>
<span class="del-btn">删除班级</span>
</template>
</el-table-column>
</el-table>
</div>
</template>
<script setup>
import { ref } from "vue";
const tableData = ref() //表格数据
// 第一列的的索引
const firstIndex = ref([])
// 相同行数名的索引的值
const mergerRowIndex = ref([])
//合并表格列
const objectSpanMethod = ({ row, column, rowIndex, columnIndex }) => {
if (![1, 2, 3, 4].includes(columnIndex)) { // 从0开始数,第2, 3, 4, 5列是需要合并的
if (rowIndex === 0) {
return {
rowspan: firstIndex.value[0],
colspan: 1
}
}
if (firstIndex.value[0] > rowIndex && rowIndex > 0) {
return {
rowspan: 0,
colspan: 0
}
}
for (let i = 0; i < firstIndex.value.length; i++) {
if (rowIndex === firstIndex.value[i]) {
return {
rowspan: firstIndex.value[i + 1] - firstIndex.value[i],
colspan: 1
}
}
if (firstIndex.value[i + 1] > rowIndex && rowIndex > firstIndex.value[i]) {
return {
rowspan: 0,
colspan: 0
}
}
}
}
}
// 查验有无相同行数名的对象,如果知道不同行数名的位置,则记住其位置并且压入
const getMergerRowIndex = () => {
// 每次调用这个函数,就需要把之前压入到函数内的值给清空
mergerRowIndex.value = []
firstIndex.value = []
for (let i = 1; i < tableData.value.length; i++) {
if (tableData.value[i].class != tableData.value[i - 1].class) {
mergerRowIndex.value.push(i);
firstIndex.value.push(i);
}
}
// 并且还要压入表格的的长度
mergerRowIndex.value.push(tableData.value.length);
firstIndex.value.push(tableData.value.length);
}
//请求接口获取数据
const getData = () => {
let data = [
{ id: '1', class: '一班', name: '张三', course: '数学', remark: '数学年级第二', },
{ id: '2', class: '一班', name: '李四', course: '语文', remark: '语文还行', },
{ id: '3', class: '一班', name: '王五', course: '英语', remark: '英语一般般', },
{ id: '4', class: '二班', name: '向小小', course: '语文', remark: '语文年级第一', },
{ id: '5', class: '二班', name: '杨六六', course: '数学', remark: '数学年级第一', },
]
tableData.value = data
getMergerRowIndex()
}
getData()
</script>
<style lang="scss" scoped>
.main-page {
.flex-end {
display: flex;
justify-content: end;
margin-bottom: 10px;
}
.add-btn {
color: #0077ef;
margin-right: 4px;
cursor: pointer;
}
.del-btn {
color: #f56c6c;
cursor: pointer;
}
.public-search {
background: #0077ef;
border-radius: 4px;
height: 32px;
padding: 0 14px;
text-align: center;
color: #ffffff;
cursor: pointer;
align-items: center;
display: flex;
user-select: none;
}
}
</style>
初始化后的页面
2.实现添加班级与学生的功能
关键代码
//给添加班级与添加学生绑定事件
<div class="public-search" @click="addStudents(null, null)">添加班级</div>
<span class="add-btn" @click="addStudents(scope.$index, scope.row)">添加学生</span>
//为了方便管理数据给新增弹窗重新定义了一个组件AddClass
<AddClass v-model:show="showClass" :row="rowList" :tableData="tableData" @addClass="addClass" />
<script>
import AddClass from "./AddClass.vue"; //引入组件
const showClass = ref(false)
const rowList = ref() //行数据
const rowIndex = ref(0) //点击的多少行
//添加学生和班级
const addStudents = (index, row) => {
rowIndex.value = index || 0
rowList.value = row || {}
showClass.value = true
}
//添加班级或学生
const addClass = (form) => {
//这里全局都是根据class来判断唯一值的,视具体情况而修改
let len = tableData.value.filter(res => res.class === form.class).length;
if (len === 0) {
len = tableData.value.length;
}
//新增学生的随机id
form.id = Math.random()
//使用splice(xx,0,{}) 这个方法在指定位置加数据
tableData.value.splice(len + rowIndex.value, 0, {
...form
})
getMergerRowIndex()
}
</script>
最后实现的效果
3.添加的弹窗
<template>
<div class="add-class">
<el-dialog v-model="dialogVisible" title="新增" width="480px" :before-close="closeDialog">
<el-form ref="ruleFormRef" :model="ruleForm" label-width="120px" label-position="top" class="demo-ruleForm">
<el-form-item label="班级:" prop="class" v-if="!hasClass">
<el-select v-model="ruleForm.class" filterable allow-create default-first-option placeholder="请输入或者选择班级">
<el-option label="一班" value="一班" />
<el-option label="二班" value="二班" />
<el-option label="三班" value="三班" />
<el-option label="四班" value="四班" />
<el-option label="五班" value="五班" />
</el-select>
</el-form-item>
<el-form-item label="姓名:" prop="name">
<el-input v-model="ruleForm.name" />
</el-form-item>
<el-form-item label="课程:" prop="course">
<el-input v-model="ruleForm.course" />
</el-form-item>
<el-form-item label="备注:" prop="remark">
<el-input v-model="ruleForm.remark" :rows="2" type="textarea" />
</el-form-item>
</el-form>
<template #footer>
<span class="dialog-footer">
<el-button type="primary" @click="onSubmit">
确定
</el-button>
<el-button @click="closeDialog">取消</el-button>
</span>
</template>
</el-dialog>
</div>
</template>
<script setup >
import { ref, reactive, defineEmits, defineProps, computed, watch } from "vue"
import { ElMessage } from 'element-plus'
const emits = defineEmits(['update:show']);
const props = defineProps({
show: Boolean,
row: Object || {},
tableData: Array
})
watch(props, () => {
if (props.row && props.row.class) {
ruleForm.class = props.row.class
hasClass.value = true
} else {
ruleForm.class = ''
hasClass.value = false
}
})
const hasClass = ref(false) //是否有class
const dialogVisible = computed({
get: () => { return props.show },
set: newVal => emits('update:show', newVal)
});
const ruleForm = reactive({
class: '',
name: '',
course: '',
remark: '',
})
const ruleFormRef = ref()
const closeDialog = () => {
dialogVisible.value = false
ruleFormRef.value && ruleFormRef.value.resetFields()
}
const onSubmit = async () => {
//如果存在班级则不能继续添加班级
if (!hasClass.value) {
if (props.tableData.some(res => res.class === ruleForm.class)) {
ElMessage.error('已存在该班级');
return;
}
}
emits('addClass', ruleForm)
closeDialog()
}
</script>
<style lang="scss" scoped>
.add-class {
}
</style>
新增班级弹窗效果
新增学生的效果
4.删除班级
关键代码
//绑定事件
<span class="del-btn" @click="delClass(scope.$index, scope.row)">删除班级</span>
import { ElMessage, ElMessageBox } from 'element-plus'
//删除班级
const delClass = (index, row) => {
ElMessageBox.confirm(
`是否删除班级${row.class}?`,
{
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning',
}
).then(() => {
let len = tableData.value.filter(res => res.class === row.class).length
tableData.value.splice(index, len)
getMergerRowIndex()
ElMessage({
type: 'success',
message: '删除成功',
})
}).catch(() => {
ElMessage({
type: 'info',
message: '取消操作',
})
})
}
实现效果
5.删除学生
关键代码
//绑定事件
<span class="del-btn" @click="delStudents(scope.row)">删除</span>
//删除学生
const delStudents = (row) => {
ElMessageBox.confirm(
`是否删除学生${row.name}?`,
{
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning',
}
).then(() => {
tableData.value = tableData.value.filter(item => {
return item.id != row.id
})
getMergerRowIndex()
ElMessage({
type: 'success',
message: '删除成功',
})
}).catch(() => {
ElMessage({
type: 'info',
message: '取消操作',
})
})
}
效果图
end: 关于修改,其实和新增差不多这里就没有写了,合并表格并实现增删改查的功能就是这些。
全部代码可以关注这里哦