vue3 + element Plus实现表格根据关键字合并行,并实现行的增删改操作

首先看最终实现的效果

请添加图片描述

1.实现初始化表格

这里主要用到的是表格的span-method这个方法

<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开始数,第1,2, 3, 4列是需要合并的
        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: 关于修改,其实和新增差不多这里就没有写了,合并表格并实现增删改查的功能就是这些。

全部代码可以关注这里哦

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
好的,以下是一个使用Vue 3和Element UI实现关键字搜索的示例代码: ```vue <template> <div> <el-input v-model="searchText" placeholder="请输入关键字"></el-input> <el-button type="primary" @click="search">搜索</el-button> <el-table :data="tableData" border> <el-table-column prop="date" label="日期" width="180"></el-table-column> <el-table-column prop="name" label="姓名" width="180"></el-table-column> <el-table-column prop="address" label="地址"></el-table-column> </el-table> </div> </template> <script> import { ref } from 'vue'; import { ElTable, ElTableColumn, ElInput, ElButton } from 'element-plus'; export default { components: { ElTable, ElTableColumn, ElInput, ElButton, }, setup() { const searchText = ref(''); const tableData = ref([ { date: '2021-08-01', name: '张三', address: '北京市海淀区', }, { date: '2021-08-02', name: '李四', address: '上海市浦东区', }, { date: '2021-08-03', name: '王五', address: '广州市天河区', }, ]); const search = () => { const keyword = searchText.value; if (keyword) { const filteredData = tableData.value.filter( (item) => item.name.includes(keyword) || item.address.includes(keyword) ); tableData.value = filteredData; } else { // 如果没有关键字,重置表格数据 tableData.value = [ { date: '2021-08-01', name: '张三', address: '北京市海淀区', }, { date: '2021-08-02', name: '李四', address: '上海市浦东区', }, { date: '2021-08-03', name: '王五', address: '广州市天河区', }, ]; } }; return { searchText, tableData, search, }; }, }; </script> ``` 在这个示例中,我们使用了`ElInput`组件来接收用户输入的关键字,使用`ElButton`组件来触发搜索操作。我们还使用了`ElTable`和`ElTableColumn`组件来展示搜索结果。 当用户点击搜索按钮时,我们会获取用户输入的关键字,然后使用`filter`方法来过滤表格数据,只保留包含关键字的数据项。如果没有输入关键字,我们就重置表格数据,展示所有数据项。 请注意,这只是一个简单的示例,您需要根据自己的实际需求进适当的修

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Jet_closer

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值