ElementUI table+dialog实现一个简单的可编辑的表格

news2024/9/22 13:45:39

table组件如何实现可编辑呢?

我的需求是把table组件那样的表格,实现它点击可以弹出一个框,然后在这个框里面输入你的东西,然后将他回显回去,当然,输入的有可能是时间啥的。

为什么要弹出弹层不在框上直接编辑呢?因为框太小了,用户可能看不见输入的是啥。

我们可以利用element组件的插槽,获取数值,然后回显到表格里。

HTML部分

我用了一个弹层来写这个功能,如果测试效果,可以直接在主页面引入 ,将弹层的控制开关改为true。

<template>
	<el-drawer v-model="drawerVisible" size="calc(100% - 210px)" @close="resetForm">
		<el-container>
			<el-form ref="ruleFormRef2" label-position="right" :model="form" label-width="138px">
				<div class="form-left">
					<div class="sepcial_about">
						<div class="tableForm">
							<el-table :data="testDatas" border style="width: 700px">
								<el-table-column v-for="(col, idx) in columnList" :key="col.prop" :index="idx" :width="idx === 1 ? '180px' : ''">
									<template #header>
										<p>
											{{ col.label }}
										</p>
									</template>
									<template #default="{ row }">
										<p :class="col.prop == 'remark' ? 'p_remark' : 'p1111'" @click="e => handleEdit(0, row, col)">
											{{ col.prop == "time" ? changeTime(row[col.prop]) : row[col.prop] }}
										</p>
									</template>
								</el-table-column>
								<el-table-column width="120">
									<template #header>
										<p class="p_specail">操作</p>
									</template>
									<template #default="scope">
										<p class="p1111">
											<el-button link type="primary" size="large" @click.prevent="delRow(scope, 0)">删除</el-button>
										</p>
									</template>
								</el-table-column>
							</el-table>
							<el-button type="primary" class="mt-4" style="width: 100%" @click="addRow(0)">新增</el-button>
						</div>
					</div>
				</div>
			</el-form>
			<el-dialog v-model="dialogVisible" title="添加" width="30%" center align-center>
				<span>{{ sureMsg }}</span>
				<template #footer>
					<span class="dialog-footer">
						<el-button type="primary" @click="toSure">确 认</el-button>
					</span>
				</template>
			</el-dialog>
			<el-dialog v-model="addDialog" :title="addTitle" width="30%" center align-center>
				<el-date-picker v-if="isTime" v-model="addinput" type="daterange" format="YYYY/MM/DD" value-format="YYYY-MM-DD" />
				<el-input
					v-if="isNum"
					resize="none"
					maxlength="15"
					show-word-limit
					v-model="addinput"
					type="textarea"
					size="large"
					placeholder="请输入"
				/>
				<el-input
					v-if="!isNum && !isTime"
					resize="none"
					maxlength="500"
					show-word-limit
					v-model="addinput"
					type="textarea"
					size="large"
					placeholder="请输入"
				/>
				<template #footer>
					<span class="dialog-footer">
						<el-button type="primary" @click="sava">保存</el-button>
					</span>
				</template>
			</el-dialog>
		</el-container>
	</el-drawer>
</template>

JS

1.渲染数据集合

自定义的表头,HTML结构中通过v-for 循环表头列表,进行label的取值来构建最基础的表格

// 表格之中的数据
const testDatas: any = ref([]);

// 表头列表
const columnList: any = ref([
	{ prop: "projectName", label: "测试1" },
	{ prop: "time", label: "时间段" },
	{ prop: "projectContentSummary", label: "测试2" }
]);

2.handleEdit函数

这个函数主要是用来控制弹层的弹出,通过行的标签名字判断需要什么输入的值。根据whatSava的值来判断你点击的是哪个表格,这个参数在HTML结构写死,cellRow和cellCol就是在渲染的时候带入的行的值和列的值。可以获得标签名字或者prop字段用来做判断。当然,这些名字也可以用来设置弹出弹框的弹框名字。

然后判断prop的值来看是不是需要输入 或者是 时间段格式的,让各自的开关变为true或者false

并且根据cellRow[cellCol.prop]这个值来对弹出来的框进行赋值,也就是回显。

const addinput = ref("");
const addTitle = ref("");
const addCode = ref();
const addProp = ref();
const isTime = ref(false);
const savaWhat = ref();
const isNum = ref(false);
const handleEdit = (whatSava: any, cellRow: any, cellCol: any) => {
	if (whatSava == "0") {
		savaWhat.value = 0;
	}
	if (cellCol.prop == "ceshi1" || cellCol.prop == "ceshi2") {
		isTime.value = false;
		if (cellCol.prop == "ceshi2") {
			isNum.value = true;
		} else {
			isNum.value = false;
		}
		addTitle.value = cellCol.label;
		addProp.value = cellCol.prop;
		addCode.value = cellRow.index;
		addinput.value = cellRow[cellCol.prop];
		addDialog.value = true;
	} else {
		isTime.value = true;
		addTitle.value = cellCol.label;
		addProp.value = cellCol.prop;
		addCode.value = cellRow.index;
		addinput.value = cellRow[cellCol.prop];
		addDialog.value = true;
	}
};

3.保存弹框函数

这个函数就是弹出层的保存函数,先找到你点击的是哪个框,然后把弹框里面输入的东西赋值给他,如果是数字的话,就用正则限制一下,不让他输入数字以外的东西。最后要清空一下,防止下次回显。

const sava = () => {
	let idx = testDatas.value.findIndex((p: any) => p.index == addCode.value);
	if (addProp.value == "ceshi2") {
		if (!/^[0-9]*$/.test(addinput.value)) {
			ElMessage.warning("请输入数字");
			return;
		}
		testDatas.value[idx][addProp.value] = addinput.value;
	} else {
		testDatas.value[idx][addProp.value] = addinput.value;
	}
	addinput.value = "";
	addDialog.value = false;
};

4.清洗时间格式函数

因为我们日期时间选择器,得到的是一个数组,所以我们回显的时候,应该拿数组的第一项和第二项,然后拼接起来,得到我们回显的正确格式。

//时间格式清洗
const changeTime = (data: any) => {
	if (!data) {
		return "";
	} else {
		let data1 = data[0] + "~" + data[1];
		return data1;
	}
};

5.添加函数

只需要我们知道添加的是哪个表格的,单表格就可以忽略whatAdd这个参数。

逻辑就是先判断他是不是为空,为空的话给他单纯的加一行,不为空的话,得到数组的长度,给他加一个index,我在写的过程中,发现我们没有办法获得一个标识,所以我写了一个index来当作唯一标识,当然,这个在获取后端接口的时候,需要你获取后端给你数组的长度,然后再依次相加就不会导致错误的出现。

// 添加一行
const addRow = (whatAdd: number) => {
	if (whatAdd == 0) {
		let obj: any = {};
		if (testDatas.value.length == 0) {
			obj.index = "0";
			columnList.value.forEach((p: any) => {
				obj[p.prop] = "";
			});
			testDatas.value[0] = obj;
		} else {
			const weiyi = testDatas.value[testDatas.value.length - 1].index;
			columnList.value.forEach((p: any) => {
				obj[p.prop] = "";
			});
			obj.index = String(Number(weiyi) + 1);
			testDatas.value[testDatas.value.length] = obj;
		}
	}
};

6.删除函数

因为删除标签在table表格之中,所以我们可以用scope准确的获得是哪一行,然后用whatDel判断你删除的是哪个表格。

//删除
const delRow = (scope: any, whatDel: number) => {
	const arrIndex = scope.$index; //唯一标识
	//将testDatas中的第arrIndex项数据删除
	if (whatDel == 0) {
		testDatas.value.splice(arrIndex, 1);
	}
};

CSS

<style scoped lang="scss">
:deep(.el-textarea__inner) {
	height: 200px;
}
:deep(.cell) {
	text-align: center !important;
	height: 45px;
	padding: 0;
}
.p1111 {
	height: 50px;
	line-height: 50px !important;
	overflow: hidden;
	white-space: nowrap;
	text-overflow: ellipsis;
	padding: 0;
	margin: 0;
	text-align: center !important;
}

.tableForm {
	width: 700px;
	margin-left: 35px;
	margin-top: 20px;
}
.sepcial_about {
	width: 500px;
	padding-left: 40px;
	box-sizing: border-box;
	margin-bottom: 60px;
	position: relative;

	> :first-child {
		width: 1000px;
		margin-bottom: 10px;
	}
}
.sepcial_about .mt-4 {
	position: absolute;
	width: 40px !important;
	height: 30px !important;
	bottom: 10px;
	left: 800px;
	z-index: 999;
}
.sepcial_about :deep(.el-table) {
	display: block;
	height: 100%;
}
:deep(.el-date-editor) {
	width: 100% !important;
	height: 50px;
	text-align: center;
}




.form-left {
	padding-top: 20px;
}


:deep(.el-form-item__content) {
	/* margin-top: 20px; */
	margin-left: 40px !important;
}



:deep(.el-form-item__label) {
	font-size: 16px;
	color: black;
}
</style>

 全部代码

<template>
	<el-drawer v-model="drawerVisible" size="calc(100% - 210px)" @close="resetForm">
		<el-container>
			<el-form ref="ruleFormRef2" label-position="right" :model="form" label-width="138px">
				<div class="form-left">
					<div class="sepcial_about">
						<div class="tableForm">
							<el-table :data="testDatas" border style="width: 700px">
								<el-table-column v-for="(col, idx) in columnList" :key="col.prop" :index="idx" :width="idx === 1 ? '180px' : ''">
									<template #header>
										<p>
											{{ col.label }}
										</p>
									</template>
									<template #default="{ row }">
										<p :class="col.prop == 'remark' ? 'p_remark' : 'p1111'" @click="e => handleEdit(0, row, col)">
											{{ col.prop == "time" ? changeTime(row[col.prop]) : row[col.prop] }}
										</p>
									</template>
								</el-table-column>
								<el-table-column width="120">
									<template #header>
										<p class="p_specail">操作</p>
									</template>
									<template #default="scope">
										<p class="p1111">
											<el-button link type="primary" size="large" @click.prevent="delRow(scope, 0)">删除</el-button>
										</p>
									</template>
								</el-table-column>
							</el-table>
							<el-button type="primary" class="mt-4" style="width: 100%" @click="addRow(0)">新增</el-button>
						</div>
					</div>
				</div>
			</el-form>
			<el-dialog v-model="addDialog" :title="addTitle" width="30%" center align-center>
				<el-date-picker v-if="isTime" v-model="addinput" type="daterange" format="YYYY/MM/DD" value-format="YYYY-MM-DD" />
				<el-input
					v-if="isNum"
					resize="none"
					maxlength="15"
					show-word-limit
					v-model="addinput"
					type="textarea"
					size="large"
					placeholder="请输入"
				/>
				<el-input
					v-if="!isNum && !isTime"
					resize="none"
					maxlength="500"
					show-word-limit
					v-model="addinput"
					type="textarea"
					size="large"
					placeholder="请输入"
				/>
				<template #footer>
					<span class="dialog-footer">
						<el-button type="primary" @click="sava">保存</el-button>
					</span>
				</template>
			</el-dialog>
		</el-container>
	</el-drawer>
</template>

<script setup lang="tsx" name="addConfig">
import { ref, reactive } from "vue";
import { ElMessage } from "element-plus";
const drawerVisible = ref(false);
const addDialog = ref(false);
const addinput = ref("");
const testDatas: any = ref([]);
const columnList: any = ref([
	{ prop: "ceshi1", label: "测试1" },
	{ prop: "time", label: "时间段" },
	{ prop: "ceshi2", label: "测试2" }
]);
const addTitle = ref("");
const addCode = ref();
const addProp = ref();
const isTime = ref(false);
const savaWhat = ref();
const isNum = ref(false);
const handleEdit = (whatSava: any, cellRow: any, cellCol: any) => {
	if (whatSava == "0") {
		savaWhat.value = 0;
	}
	if (cellCol.prop == "ceshi1" || cellCol.prop == "ceshi2") {
		isTime.value = false;
		if (cellCol.prop == "ceshi2") {
			isNum.value = true;
		} else {
			isNum.value = false;
		}
		addTitle.value = cellCol.label;
		addProp.value = cellCol.prop;
		addCode.value = cellRow.index;
		addinput.value = cellRow[cellCol.prop];
		addDialog.value = true;
	} else {
		isTime.value = true;
		addTitle.value = cellCol.label;
		addProp.value = cellCol.prop;
		addCode.value = cellRow.index;
		addinput.value = cellRow[cellCol.prop];
		addDialog.value = true;
	}
};
const sava = () => {
	let idx = testDatas.value.findIndex((p: any) => p.index == addCode.value);
	if (addProp.value == "ceshi2") {
		if (!/^[0-9]*$/.test(addinput.value)) {
			ElMessage.warning("请输入数字");
			return;
		}
		testDatas.value[idx][addProp.value] = addinput.value;
	} else {
		testDatas.value[idx][addProp.value] = addinput.value;
	}
	addinput.value = "";
	addDialog.value = false;
};
let form: any = reactive({});
//时间格式清洗
const changeTime = (data: any) => {
	if (!data) {
		return "";
	} else {
		let data1 = data[0] + "~" + data[1];
		return data1;
	}
};
//清空数据
const resetForm = () => {
	form.companyName = "";
	form.linkman = "";
	form.companyType = "";
	form.contactTitle = "";
	form.contactPhone = "";
	form.id1 = [];
	form.id2 = [];
	form.idCardPhoto = [];
	form.publicCreditInformationReportOfEnterpriseInstitutions = [];
	form.businessLicenseOrLegalRepresentativeCertificate = [];
	form.lastYearBankCertificationDocuments = [];
	form.taxPaymentMaterialsForThePastYear = [];
	form.employeePaymentCertificateForThePastYear = [];
	form.declarationOfMajorIllegalRecords = [];
	form.representativeProjects = [];
	form.actualImplementationSituation = [];
	form.other = [];
	testDatas.value = [];
};
// 添加一行
const addRow = (whatAdd: number) => {
	if (whatAdd == 0) {
		let obj: any = {};
		if (testDatas.value.length == 0) {
			obj.index = "0";
			columnList.value.forEach((p: any) => {
				obj[p.prop] = "";
			});
			testDatas.value[0] = obj;
		} else {
			const weiyi = testDatas.value[testDatas.value.length - 1].index;
			columnList.value.forEach((p: any) => {
				obj[p.prop] = "";
			});
			obj.index = String(Number(weiyi) + 1);
			testDatas.value[testDatas.value.length] = obj;
		}
	}
};
//删除
const delRow = (scope: any, whatDel: number) => {
	const arrIndex = scope.$index; //唯一标识
	//将testDatas中的第arrIndex项数据删除
	if (whatDel == 0) {
		testDatas.value.splice(arrIndex, 1);
	}
};
const acceptParams = () => {
	drawerVisible.value = true;
};
defineExpose({
	acceptParams
});
</script>

<style scoped lang="scss">
:deep(.el-textarea__inner) {
	height: 200px;
}
:deep(.cell) {
	text-align: center !important;
	height: 45px;
	padding: 0;
}
.p1111 {
	height: 50px;
	line-height: 50px !important;
	overflow: hidden;
	white-space: nowrap;
	text-overflow: ellipsis;
	padding: 0;
	margin: 0;
	text-align: center !important;
}
.tableForm {
	width: 700px;
	margin-left: 35px;
	margin-top: 20px;
}
.sepcial_about {
	width: 500px;
	padding-left: 40px;
	box-sizing: border-box;
	margin-bottom: 60px;
	position: relative;

	> :first-child {
		width: 1000px;
		margin-bottom: 10px;
	}
}
.sepcial_about .mt-4 {
	position: absolute;
	width: 40px !important;
	height: 30px !important;
	bottom: 10px;
	left: 800px;
	z-index: 999;
}
.sepcial_about :deep(.el-table) {
	display: block;
	height: 100%;
}
:deep(.el-date-editor) {
	width: 100% !important;
	height: 50px;
	text-align: center;
}
.form-left {
	padding-top: 20px;
}
:deep(.el-form-item__content) {
	/* margin-top: 20px; */
	margin-left: 40px !important;
}
:deep(.el-form-item__label) {
	font-size: 16px;
	color: black;
}
</style>

 

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

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

相关文章

文件名称管理文件:抓关键字归类文件,让文件管理变得简单明了

在当今数字时代&#xff0c;每天都要处理大量的文件&#xff0c;无论是文本、图片、视频还是其他类型的文件。如何有效地管理这些文件&#xff0c;能够迅速找到所需的信息&#xff0c;已经成为了一个重要的问题。文件名称是文件内容的第一反映&#xff0c;也是识别和检索文件的…

在arm 64 环境下使用halcon算法

背景&#xff1a; halcon&#xff0c;机器视觉领域神一样得存在&#xff0c;在windows上&#xff0c;应用得特别多&#xff0c; 但是arm环境下使用得很少。那如何在arm下使用halcon呢。按照官方说明&#xff0c;arm下只提供了运行时环境&#xff0c;并且需要使用价值一万多人民…

element中el-switch的v-model自定义值

一、问题 element中的el-switch的值默认都是true或false&#xff0c;但是有些时候后端接口该字段可能是0或者1&#xff0c;如果说再转换一次值&#xff0c;那就有点太费力了。如下所示&#xff1a; <template><el-switchinactive-text"否"active-text&quo…

【miniQMT实盘量化5】获取财务报表数据

前言 上面文章&#xff0c;我们介绍了如何获取实时数据&#xff0c;这篇文章&#xff0c;我们继续往下探讨&#xff0c;介绍关于财务报表数据的获取。 财务报表数据 财务报表数据&#xff0c;也就是常说的基本面数据&#xff0c;是除了行情数据之外&#xff0c;辅助我们投资…

PMP 考试的含金量怎么样?

这里可以三个思考题和三个价值点帮你认识PMP考试。 三个思维题 1.工作环境 PMP证书含金量的一个很大因素&#xff0c;就是考证的人是否对PMP证书有比较强的实际需求。相反&#xff0c;如果只是听别人说&#xff0c;PMP证书很好&#xff0c;不管工作中是否有需要&#xff0c;…

〖大前端 - 基础入门三大核心之JS篇㊷〗- DOM事件对象及它的属性

说明&#xff1a;该文属于 大前端全栈架构白宝书专栏&#xff0c;目前阶段免费&#xff0c;如需要项目实战或者是体系化资源&#xff0c;文末名片加V&#xff01;作者&#xff1a;不渴望力量的哈士奇(哈哥)&#xff0c;十余年工作经验, 从事过全栈研发、产品经理等工作&#xf…

黑马点评12-实现好友关注/取关功能,查看好友共同关注列表

好友关注 数据模型 数据库中的tb_follow记录博主与粉丝的关系 tb_follow表对应的实体类 Data EqualsAndHashCode(callSuper false) Accessors(chain true) TableName("tb_follow") public class Follow implements Serializable {private static final long ser…

【RtpRtcp】1: webrtc m79:audio的ChannelReceive 创建并使用

m79中,RtpRtcp::Create 的调用很少 不知道谁负责创建ChannelReceiveclass ChannelReceive : public ChannelReceiveInterface,public MediaTransportAudioSinkInterface {接收编码后的音频帧:接收rtcp包:

nodejs微信小程序+python+PHP -留学信息查询系统的设计与实现-安卓-计算机毕业设计

目 录 摘 要 I ABSTRACT II 目 录 II 第1章 绪论 1 1.1背景及意义 1 1.2 国内外研究概况 1 1.3 研究的内容 1 第2章 相关技术 3 2.1 nodejs简介 4 2.2 express框架介绍 6 2.4 MySQL数据库 4 第3章 系统分析 5 3.1 需求分析 5 3.2 系统可行性分析 5 3.2.1技术可行性&#xff1a;…

如何提高希音、亚马逊、国际站店铺流量转化,自养号优势及测评底层环境逻辑

随着全球贸易数字化程度加快&#xff0c;尤其是跨境电商的发展日新月异&#xff0c;在外贸出口占比越来越高&#xff0c;在这其中&#xff0c;亚马逊作为全球实力强劲的在线零售平台之一&#xff0c;吸引了大量的优秀卖家。 而这也加剧了亚马逊平台的竞争程度&#xff0c;尤其…

Java核心知识点整理大全9-笔记

目录 null文章浏览阅读9w次&#xff0c;点赞7次&#xff0c;收藏7次。Java核心知识点整理大全https://blog.csdn.net/lzy302810/article/details/132202699?spm1001.2014.3001.5501 Java核心知识点整理大全2-笔记_希斯奎的博客-CSDN博客 Java核心知识点整理大全3-笔记_希斯…

二十四、RestClient操作文档

目录 一、新增文档 1、编写测试代码 二、查询文档 1、编写测试代码 三、删除文档 1、编写测试代码 四、修改文档 1、编写测试代码 五、批量导入文档 批量查询 一、新增文档 1、编写测试代码 SpringBootTest public class HotelDocumentTest {private RestHighLevelC…

PCIE链路训练-状态机描述2

Configuration.Lanenum.Accept 如果use_modified_TS1_TS2_Ordered_Set为1&#xff0c;需要注意&#xff1a; &#xff08;1&#xff09;tx需要发送Modified TS1而不是正常的TS1&#xff1b; &#xff08;2&#xff09;rx端必须检查是否收到Modified TS1&#xff08;注意一开…

node版本管理工具-nvm

1、 下载地址 https://github.com/coreybutler/nvm-windows/releases/tag/1.1.11 2、 选择安装地址不能有空格&#xff0c;中文 3、 使用命令

【图论】关键路径求法c++

代码结构如下图&#xff1a; 其中topologicalSort(float**, int, int*, bool*, int, int)用来递归求解拓扑排序&#xff0c;topologicalSort(float**, int*&, int, int, int)传参图的邻接矩阵mat与结点个数n&#xff0c;与一个引用变量数组topo&#xff0c;返回一个布尔值…

【网络奇缘】- 计算机网络|分层结构|ISO模型

&#x1f308;个人主页: Aileen_0v0&#x1f525;系列专栏: 一见倾心,再见倾城 --- 计算机网络~&#x1f4ab;个人格言:"没有罗马,那就自己创造罗马~" 目录 计算机网络分层结构 OSI参考模型 OSI模型起源 失败原因: OSI模型组成 协议的作用 &#x1f4dd;全文…

C语言——求分段函数 y=f(x)的值

求分段函数 yf(x)的值,f(x)的表达式如下: #define _CRT_SECURE_NO_WARNINGS 1#include<stdio.h> int main() {int x,y;printf("请输入x的值&#xff1a;");scanf("%d",&x);if(x>5){yx3;}else if(x>0 && x<5){y0;}elsey2*x30;pr…

使用vcpkg安装库失败的解决方法

1、前言 vcpk是是一款开源的c/c库管理工具&#xff0c;尤其是在windows平台&#xff0c;可以帮助我们很好的管理各种依赖包。 在windows环境做c/c开发的人应该都深有体会&#xff0c;有时候编译需要下载一堆依赖库&#xff0c;导致搭建编译环境特别麻烦。但是&#xff0c;通过v…

深入理解Spring AOP的工作流程

文章目录 引言什么是AOP&#xff1f;Spring AOP的工作原理1. JDK动态代理2. CGLIB代理 Spring AOP的注解方式Aspect注解EnableAspectJAutoProxy注解 Spring AOP的工作流程拓展应用1. 自定义注解2. 异常处理3. 切面优先级 结论 &#x1f389;深入理解Spring AOP的工作流程 ☆* o…

vue - - - - - vue-qr插件生成二维码

vue-qr插件生成二维码 1. 安装插件2. 组件使用示例图&#xff1a;扫码结果 1. 安装插件 【vue-qr 官网地址】 npm install vue-qr --save // or yarn add vue-qr --save2. 组件使用 <template><vue-qr :logo-src"logoSrc":size"237":margin&qu…