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

news2024/11/17 3:05:00

根据关键字合并表格

    • 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: 关于修改,其实和新增差不多这里就没有写了,合并表格并实现增删改查的功能就是这些。

全部代码可以关注这里哦

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1082742.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Service Weaver:以单体形式编码,以微服务形式部署

分布式应用的主流架构模式演化为微服务架构已经有些年头了。微服务、DevOps、持续交付和容器技术(k8s)是构成最初云原生概念[1]的核心要素。它们相生相拌&#xff0c;共同演进&#xff0c;并推动了云计算全面进入云原生时代。 云原生应用普遍采用微服务架构&#xff0c;遗留的单…

阿里云r7服务器内存型CPU采用

阿里云服务器ECS内存型r7实例是第七代内存型实例规格族&#xff0c;CPU采用第三代Intel Xeon可扩展处理器&#xff08;Ice Lake&#xff09;&#xff0c;基频2.7 GHz&#xff0c;全核睿频3.5 GHz&#xff0c;计算性能稳定&#xff0c;CPU内存比1:8&#xff0c;2核16G起步&#…

HBase 表如何按照某表字段排序后顺序存储的方法?

首先需要明白HBase表的排序规则&#xff1a; &#xff08;1&#xff09;rowkey排序&#xff08;字典排序&#xff09;——升序 &#xff08;2&#xff09;Column排序&#xff08;字典排序&#xff09;——升序 &#xff08;3&#xff09;时间戳排序——降序 rowkey 字典序排序…

DeskHIL桌面级仿真测试平台

硬件在环测试系统&#xff0c;一直是汽车电子功能测试的重要工具。随着测试工程师对硬件在环系统的要求越来越高&#xff0c;对其高集成性、便携性的需求也愈发强烈。由于硬件在环系统设计复杂、定制化程度高等因素&#xff0c;成本一直居高不下&#xff0c;因此&#xff0c;市…

C++基础入门学习笔记

问题1&#xff1a;什么是 C 中的多态&#xff1f;如何实现多态&#xff1f; 回答1&#xff1a;C 中的多态是指同一种类型的实体&#xff0c;可以在不同的情况下表现出不同的行为。实现多态的方式有两种&#xff1a;虚函数和模板函数。虚函数是在基类中声明为虚函数的函数&…

c++视觉处理---仿射变换和二维旋转变换矩阵的函数

仿射变换cv::warpAffine cv::warpAffine 是OpenCV中用于执行仿射变换的函数。仿射变换是一种线性变换&#xff0c;可用于执行平移、旋转、缩放和剪切等操作。下面是 cv::warpAffine 函数的基本用法&#xff1a; cv::warpAffine(src, dst, M, dsize, flags, borderMode, borde…

嵌入式Linux裸机开发(七)UART串口、IIC、SPI通信

系列文章目录 文章目录 系列文章目录前言UART串口通信介绍UART配置 IIC介绍I.MX6U 的 I2C SPI介绍I.MX6U ECSPI 结语 前言 大概学完这三种通信后&#xff0c;之后就先去学系统移植&#xff0c;其他的先暂时放下 UART串口通信 介绍 串口全称叫做串行接口&#xff0c;通常也叫…

Maven创建父子工程详解

引言 在微服务盛行的当下&#xff0c;我们创建的工程基本都是父子工程&#xff0c;我们通过父工程来引入jar&#xff0c;定义统一的版本号等&#xff0c;这样我们在子工程中就可以直接引用后使用了&#xff0c;而不需要去重复的声明版本号等&#xff0c;这样会更方便对整个项目…

Linux中Locate命令查找不全

Locate locate(locate) 命令用来查找文件或目录。 locate命令要比find -name快得多&#xff0c;原因在于它不搜索具体目录&#xff0c;而是搜索一个数据库/var/lib/mlocate/mlocate.db 。这个数据库中含有本地所有文件信息。Linux系统会自动创建这个数据库&#xff0c;并且每天…

【ElasticSearch】深入探索 DSL 查询语法,实现对文档不同程度的检索,以及对搜索结果的排序、分页和高亮操作

文章目录 前言一、Elasticsearch DSL Query 的分类二、全文检索查询2.1 match 查询2.2 multi_match 查询 三、精确查询3.1 term 查询3.2 range 查询 四、地理坐标查询4.1 geo_bounding_box 查询4.2 geo_distance 查询 五、复合查询5.1 function score 查询5.2 boolean 查询 六、…

2023年中国溶瘤病毒药物上市产品、研发现状及行业市场规模前景[图]

溶瘤病毒&#xff08;Oncolyticvirus&#xff09;&#xff0c;是一类具有复制能力的肿瘤杀伤型病毒&#xff0c;溶瘤病毒根据所采用的毒株类型可以被分为天然病毒株&#xff08;野生型病毒株&#xff09;和基因改造病毒株两类&#xff0c;溶瘤病毒的种类也从最初的疱疹病毒发展…

使用c++视觉处理----canny 边缘检测、sobel边缘检测、scharr 滤波边缘检测

使用c视觉处理canny 边缘检测、sobel边缘检测、scharr 滤波边缘检测 #include <opencv2/opencv.hpp>int main() {// 读取图像cv::Mat image cv::imread("1.jpg", cv::IMREAD_GRAYSCALE); // 转为灰度图像if (image.empty()) {std::cerr << "无法加…

网络-网络状态网络速度

文章目录 前言一、网络状态二、网络速度 前言 本文主要记录如何监听网络状态和网络速度。 一、网络状态 获取当前网络状态: navigator.onLine // true:在线 false:离线监听事件&#xff1a;online&#xff08;联网&#xff09; 和 offline&#xff08;断网&#xff09; windo…

全国A级旅游景区清单数据(2023年更新)

全国A级旅游景区清单数据&#xff08;2023年更新&#xff09; 1.样本量&#xff1a;14847条 2.来源&#xff1a;政府公布资料 3.指标&#xff1a;景区名称、等级、所属省份、所属城市、所属区县、地址、当前等级评定时间、相关文件发布时间、坐标(GCJ02)Lng、坐标(GCJ02)Lat…

【Redis实战】分布式锁

分布式锁 synchronized只能保证单个JVM内部的线程互斥&#xff0c;不能保证集群模式下的多个JVM的线程互斥。 分布式锁原理 每个JVM内部都有自己的锁监视器&#xff0c;但是跨JVM&#xff0c;就会有多个锁监视器&#xff0c;就会有多个线程获取到锁&#xff0c;不能实现多JV…

分享一份关于 Rust 编程的学习指南

Rust是一种现代的系统级编程语言&#xff0c;以其注重内存安全、性能和并发性而闻名。学习Rust可以是一段有回报的旅程&#xff0c;为您打开构建强大高效应用的机会。无论您是经验丰富的开发者还是完全的初学者&#xff0c;本指南将通过精选的资源和技巧帮助您踏上Rust编程之旅…

【angular】实现简单的angular国际化(i18n)

文章目录 目标过程运行参考 目标 实现简单的angular国际化。本博客实现中文版和法语版。 将Hello i18n!变为中文版&#xff1a;你好 i18n!或法语版:Bonjour l’i18n !。 过程 创建一个项目&#xff1a; ng new i18nDemo在集成终端中打开。 添加本地化包&#xff1a; ng a…

景联文科技:3D点云标注应用场景和专业平台

3D点云技术之所以得到广泛发展和应用&#xff0c;主要是因为它能够以一种直观、真实和全面的方式来表示和获取现实世界中的三维信息。 3D点云的优势&#xff1a; 真实感和立体感&#xff1a;3D点云数据能够呈现物体的真实感和立体感&#xff0c;使观察者能够更直观地理解物体的…

Springboot整合阿里云OSS进行上传单个图片,多个图片,删除图片功能

1. 导入OSS依赖 <!-- 阿里云oss依赖 --><dependency><groupId>com.aliyun.oss</groupId><artifactId>aliyun-sdk-oss</artifactId><version>3.10.2</version></dependency> 2. 进行OSS配置 package com.example.sushe…

[GAMES101]透视投影变换矩阵中为什么需要改变z值

透视投影需要保证&#xff0c;1.变换矩阵内的元素是常数&#xff0c;2.相对深度值不变&#xff08;绝对值不重要&#xff09;&#xff1b;若再加上变换后zNear和zFar平面上的点依旧在zNear和zFar平面上这两个条件&#xff08;实际上并不一定需要满足这两个条件&#xff09;&…