Vue+Element-ui实例_可编辑表格和分页

下面是一个可以实现编辑的表格,并且该表格嵌入在form表单内,可以对已修改的内容进行保存提交;而且实现了对表格数据进行关键字搜索和分类筛选的功能,实现了前端分页的效果。

主要难点:

(1)当el-table列数据过多时,我们可以通过设置 type="expand" 和 Scoped slot 可以开启展开行功能,然后在每一行设置一个可编辑按钮,对展开的数据中的某条数据进行再编辑。

(2)当你设置可编辑按钮时,还要对此行展开状态进行判断,判断该行是否为展开,若已展开,则编辑,若未展开,则展开进行编辑。

(3)当对某一行进行编辑时,如该行未确认完成编辑,则不能对其他行再进行编辑,需要对该行确认完成编辑,才可对其他行进行编辑操作。

(4)对数据进行分页展示。

(5)对数据进行关键字搜索和根据分类对每页数据进行筛选。

(6)保存和提交数据的检验。

效果图如下:

效果图(1)
概览

效果图(2)

效果图(3)

效果图(4)

效果视频如下:

可编辑el-table表格演示视频

下面是代码部分:

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title>可编辑表格</title>
		<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0">
		<script src="../vue/vue.min.js" type="text/javascript" charset="utf-8"></script>
		<script src="../elementUI/index.js" type="text/javascript" charset="utf-8"></script>
		<script src="../vue/axios.min.js" type="text/javascript" charset="utf-8"></script>
		<link rel="stylesheet" type="text/css" href="../elementUI/index.css" />
		<style type="text/css">
			.menu {
				width: 100%;
				height: 100%;
			}

			.container_table {
				width: 100%;
			}

			.el-table .cell {
				text-align: center;
			}

			.postForm {
				width: 340px;
				height: 40px;
				float: right;
				margin-top: -40px;
			}

			/* 展开的form样式 */
			.demo-table-expand label {
				width: 90px;
				color: #99a9bf;
			}

			.el-form--label-left .el-form-item__label {
				text-align: right;
			}

			.demo-table-expand .el-form-item {
				margin-right: 0;
				margin-bottom: 0;
				width: 30%;
			}

			.container_table .fy {
				margin-top: 20px;
			}
		</style>
	</head>
	<body>
		<div id="menu" class="menu">
			<el-container>
				<div class="container_table">
					<el-form :model="tableData" @submit.native.prevent>
						<el-table ref="refTable" height="500" :data="tableData.slice((currentPage-1)*pagesize,currentPage*pagesize)"
						 style="width: 100%" @expand-change="expandChange">
							<el-table-column type="expand">
								<template slot-scope="props">
									<el-form label-position="left" inline class="demo-table-expand">
										<el-form-item label="日期">
											<span>{{ props.row.date }}</span>
										</el-form-item>
										<el-form-item label="姓名">
											<span>{{ props.row.name }}</span>
										</el-form-item>
										<el-form-item label="手机号">
											<span v-if="props.row.isSet">{{props.row.phone}}</span>
											<span v-else>
												<el-input clearable v-model="props.row.phone"></el-input>
											</span>
										</el-form-item>
										<el-form-item label="地址">
											<span v-if="props.row.isSet">{{props.row.address}}</span>
											<span v-else>
												<el-input type="textarea" clearable autosize v-model="props.row.address"></el-input>
											</span>
										</el-form-item>
										<el-form-item label="部门">
											<span>{{ props.row.tag }}</span>
										</el-form-item>
									</el-form>
								</template>
							</el-table-column>
							<el-table-column prop="date" label="日期" sortable width="120" column-key="date">
							</el-table-column>
							<el-table-column prop="name" label="姓名">
							</el-table-column>
							<el-table-column prop="phone" label="手机号">
							</el-table-column>
							<el-table-column prop="address" label="地址">
							</el-table-column>
							<el-table-column prop="tag" label="部门" width="140" :filters="sectorData" :filter-method="filterTag">
								<template slot-scope="scope">
									<el-tag size="medium" disable-transitions>{{scope.row.tag}}</el-tag>
								</template>
							</el-table-column>
							<el-table-column prop="searchInfo" width="200">
								<template slot="header" slot-scope="scope">
									<el-input clearable v-model="search" prefix-icon="el-icon-search" size="mini" placeholder="输入姓名关键字搜索" @input="searchName" />
								</template>
								<template slot-scope="scope">
									<el-button :disabled="btnDisabled" plain icon="el-icon-edit" v-if="scope.row.isSet" @click="handleEdit(scope.$index, scope.row)"
									 size="mini">编辑</el-button>
									<el-button plain v-else @click="saveEdit(scope.$index, scope.row)" size="mini">确定</el-button>

								</template>
							</el-table-column>
						</el-table>
					</el-form>
					<el-pagination class="fy" :current-page="currentPage" :page-sizes="[5, 10, 20]" :page-size="pagesize" layout="total, sizes, prev, pager, next, jumper"
					 @size-change="handleSizeChange" @current-change="handleCurrentChange" :total="tableData.length" background>
					</el-pagination>
					<div class="postForm">
						<el-button icon="el-icon-finished" type="primary" @click="postForm">提交</el-button>
						<el-button icon="el-icon-check" type="success" @click="saveForm">保存</el-button>
						<el-button icon="el-icon-back" type="info" @click="backtrack">撤回</el-button>
					</div>
				</div>
			</el-container>
		</div>
	</body>
	<script type="text/javascript">
		var vm = new Vue({
			el: '#menu',
			data() {
				return {
					/* 表格数据 */
					tableData: [],
					/* 原始表格数据 */
					oldtableData: [],
					/* 部门数据 */
					sectorData: [],
					pagesize: 5, //每页的数据条数
					currentPage: 1, //默认开始页面
					search: '', //搜索关键字
					btnDisabled: false,
				};
			},
			methods: {
				/* 部门筛选 */
				filterTag(value, row, column) {
					console.log(value);
					// console.log(row);
					return row.tag === value;
				},
				/* 分页方法 */
				handleSizeChange(val) {
					// console.log(`每页 ${val} 条`);
					this.pagesize = val;
				},
				handleCurrentChange: function(val) {
					// console.log(`当前页: ${val}`);
					this.currentPage = val;
				},
				/* 姓名关键字搜索 */
				searchName(search) {
					var newList = [];
					// console.log(search);
					if (search != '') {
						vm.oldtableData.forEach(item => {
							if (item.name.indexOf(search) != -1) {
								//空字符串包含在所有字符串中,因此控制会返回所有列表
								newList.push(item);
							}
						});
						return this.tableData = newList;
					} else {
						return this.tableData = this.oldtableData;
					}

				},
				/* 更改每一行的张开/关闭状态 */
				expandChange(row, expandedRows) {
					row.isExpand = !row.isExpand;
				},
				/* 开启编辑单元格 */
				handleEdit(index, row, e) {
					for (const i of this.tableData) {
						if (!i.isSet) {
							return this.$message.warning('请先保存当前编辑项');
						}
					}
					if (!row.isExpand) {
						//调用,table的方法,展开/折叠 行
						this.$refs.refTable.toggleRowExpansion(row);
					}
					row.isSet = false;

				},
				/* 保存单元格,进行编辑验证 */
				saveEdit(index, row, column) {
					// console.log(row);
					if ((row.address.replace(/\s+/g, '') == '' || (row.phone.replace(/\s+/g, '') == ''))) {
						row.isSet = false;
						return this.$message.error('数据不能为空');
					} else {
						row.isSet = true;
					}
					//调用,table的方法,展开/折叠 行
					this.$refs.refTable.toggleRowExpansion(row);
				},
				/* 提交表单 */
				postForm() {
					if (!this.btnDisabled) {
						return this.$message.error('请先保存');
					} else {
						this.$confirm('是否提交?', '提示', {
							confirmButtonText: '确定',
							cancelButtonText: '取消',
							type: 'warning'
						}).then((action) => {
							this.$message({
								type: 'success',
								message: '提交成功!',

							});
							if (action === 'confirm') {
								//提交表单
								console.log(this.tableData);
							}
						}).catch(() => {
							this.$message({
								type: 'info',
								message: '已取消提交!'
							});
						});
					}
				},
				/* 保存表单 */
				saveForm() {
					for (var i = 0; i < this.tableData.length; i++) {
						if (!this.tableData[i].isSet) {
							this.$message.warning('请先保存当前编辑项');
							return this.btnDisabled = false;
						} else {
							this.btnDisabled = true;
						}
					}
				},
				/* 撤回保存 */
				backtrack() {
					this.btnDisabled = false;
				},
				/* 获取内容数据 */
				getTableData() {
					axios.get('../data/tableData.json', {})
						.then(function(res) {
							for (var i = 0; i < res.data[0].tableData.length; i++) {
								// 添加单元格是否可以编辑的属性值
								res.data[0].tableData[i].isSet = true;
								// 添加行是否展开的属性值
								res.data[0].tableData[i].isExpand = false;
							}
							console.log(res.data);
							// 赋值
							vm.tableData = res.data[0].tableData;
							vm.oldtableData = res.data[0].tableData;
							vm.sectorData = res.data[1].sectorData;
						}).catch(function(error) {
							console.log(error);
						});
				}
			},
			mounted() {
				// 获取内容数据
				this.getTableData();
			}

		});
	</script>
</html>

data数据如下:

[{
		"tableData": [{
				"date": "2016-05-01",
				"name": "张晓明",
				"phone": "18852067999",
				"address": "上海市普陀区金沙江路 11 弄",
				"tag": "设计三所"

			}, {
				"date": "2016-05-02",
				"name": "李米中",
				"phone": "18852067999",
				"address": "上海市普陀区金沙江路 12 弄",
				"tag": "设计二所"

			}, {
				"date": "2016-05-03",
				"name": "张晓明",
				"phone": "18852067999",
				"address": "上海市普陀区金沙江路 13 弄",
				"tag": "南京小组"

			}, {
				"date": "2016-05-04",
				"name": "李米中",
				"phone": "18852067999",
				"address": "上海市普陀区金沙江路 14 弄",
				"tag": "设计一所"

			}, {
				"date": "2016-05-05",
				"name": "向飒飒",
				"phone": "18852067999",
				"address": "上海市普陀区金沙江路 15 弄",
				"tag": "南京小组"

			}, {
				"date": "2016-05-06",
				"name": "王小虎",
				"phone": "18852067999",
				"address": "上海市普陀区金沙江路 16 弄",
				"tag": "设计三所"

			},
			{
				"date": "2016-05-07",
				"name": "张晓明",
				"phone": "18852067999",
				"address": "上海市普陀区金沙江路 17 弄",
				"tag": "设计二所"

			}, {
				"date": "2016-05-08",
				"name": "李米中",
				"phone": "18852067999",
				"address": "上海市普陀区金沙江路 18 弄",
				"tag": "南京小组"

			}, {
				"date": "2016-05-09",
				"name": "向飒飒",
				"phone": "18852067999",
				"address": "上海市普陀区金沙江路 19 弄",
				"tag": "设计一所"

			}, {
				"date": "2016-05-10",
				"name": "王小虎",
				"phone": "18852067999",
				"address": "上海市普陀区金沙江路 20 弄",
				"tag": "设计三所"

			},
			{
				"date": "2016-05-11",
				"name": "张晓明",
				"phone": "18852067999",
				"address": "上海市普陀区金沙江路 21 弄",
				"tag": "设计三所"

			}, {
				"date": "2016-05-12",
				"name": "李米中",
				"phone": "18852067999",
				"address": "上海市普陀区金沙江路 22 弄",
				"tag": "设计二所"

			}, {
				"date": "2016-05-13",
				"name": "向飒飒",
				"phone": "18852067999",
				"address": "上海市普陀区金沙江路 23 弄",
				"tag": "南京小组"

			}, {
				"date": "2016-05-14",
				"name": "王小虎",
				"phone": "18852067999",
				"address": "上海市普陀区金沙江路 24 弄",
				"tag": "设计一所"

			}, {
				"date": "2016-05-15",
				"name": "王小虎",
				"phone": "18852067999",
				"address": "上海市普陀区金沙江路 25 弄",
				"tag": "设计二所"

			}
		]
	},
	{
		"sectorData": [{
				"itemid": 10001,
				"text": "设计一所",
				"value": "设计一所"
			}, {
				"itemid": 10002,
				"text": "设计二所",
				"value": "设计二所"
			},
			{
				"itemid": 10003,
				"text": "设计三所",
				"value": "设计三所"
			},
			{
				"itemid": 10004,
				"text": "南京小组",
				"value": "南京小组"
			}
		]
	}
]

代码中使用的框架有:

vue链接:vue

elementUI链接:elementUI

axios.js链接:axios.min.js

主要的难点的简单讲解:

(1)在el-table中通过设置 type="expand" 和 Scoped slot 可以开启展开行功能,el-table-column 的模板会被渲染成为展开行的内容,展开行可访问的属性与使用自定义列模板时的 Scoped slot 相同。然后在表格的最后一列设置两个按钮,但是两个按钮要根据 v-if="scope.row.isSet"来进行“编辑和确定”的切换。

(2)在每条数据中设置一个isExpand="false"的属性,默认该行为未展开状态,当展开或关闭该行时,记录下该状态,如下:

/* 更改每一行的张开/关闭状态 */
            expandChange(row, expandedRows) {
                    row.isExpand = !row.isExpand;
            },

(3)在点击编辑按钮时,对其他行进行验证,如其他行存在编辑状态,则先保存对其他行的编辑,然后才能对该行进行编辑;点击改变某条数据变为可编辑状态,确认时,对数据进行非空校验。如下:

/* 开启编辑单元格 */
                handleEdit(index, row, e) {
                    for (const i of this.tableData) {
                        if (!i.isSet) {
                            return this.$message.warning('请先保存当前编辑项');
                        }
                    }
                    if (!row.isExpand) {
                        //调用,table的方法,展开/折叠 行
                        this.$refs.refTable.toggleRowExpansion(row);
                    }
                    row.isSet = false;

         },
        /* 保存单元格,进行编辑验证 */
                saveEdit(index, row, column) {
                    // console.log(row);
                    if ((row.address.replace(/\s+/g, '') == '' || (row.phone.replace(/\s+/g, '') == ''))) {
                        row.isSet = false;
                        return this.$message.error('数据不能为空');
                    } else {
                        row.isSet = true;
                    }
                    //调用,table的方法,展开/折叠 行
                    this.$refs.refTable.toggleRowExpansion(row);
                },

 (4)分页展示的核心代码是在获取的数据后,写入到el-table中,如下红色部分:

<el-table ref="refTable" height="500" :data="tableData.slice((currentPage-1)*pagesize,currentPage*pagesize)"
                         style="width: 100%" @expand-change="expandChange">

/* 分页方法 */
                handleSizeChange(val) {
                    // console.log(`每页 ${val} 条`);
                    this.pagesize = val;
                },
                handleCurrentChange: function(val) {
                    // console.log(`当前页: ${val}`);
                    this.currentPage = val;
                },

(5) 此案例中是对姓名中的关键字进行搜索,对字符串使用indexOf属性,对搜索到的数据添加到一个新的数组中,并返回给el-table;在筛选中,是element中的,可去案例中参考。如下:

<el-table-column prop="tag" label="部门" width="140" :filters="sectorData" :filter-method="filterTag">
                       <template slot-scope="scope">
                                    <el-tag size="medium" disable-transitions>{{scope.row.tag}}</el-tag>
                        </template>
        </el-table-column>

<template slot="header" slot-scope="scope">
               <el-input clearable v-model="search" prefix-icon="el-icon-search" size="mini" placeholder="输入姓名关键字搜索" @input="searchName" />
         </template>

/* 部门筛选 */
                filterTag(value, row, column) {
                    console.log(value);
                    // console.log(row);
                    return row.tag === value;
                },

/* 姓名关键字搜索 */
                searchName(search) {
                    var newList = [];
                    // console.log(search);
                    if (search != '') {
                        vm.oldtableData.forEach(item => {
                            if (item.name.indexOf(search) != -1) {
                                //空字符串包含在所有字符串中,因此控制会返回所有列表
                                newList.push(item);
                            }
                        });
                        return this.tableData = newList;
                    } else {
                        return this.tableData = this.oldtableData;
                    }
                },

(6)下面就是对保存和提交的简单校验,在提交时要确认数据已经保存,保存的数据不可再编辑

/* 提交表单 */
                postForm() {
                    if (!this.btnDisabled) {
                        return this.$message.error('请先保存');
                    } else {
                        this.$confirm('是否提交?', '提示', {
                            confirmButtonText: '确定',
                            cancelButtonText: '取消',
                            type: 'warning'
                        }).then((action) => {
                            this.$message({
                                type: 'success',
                                message: '提交成功!',

                            });
                            if (action === 'confirm') {
                                //提交表单
                                console.log(this.tableData);
                            }
                        }).catch(() => {
                            this.$message({
                                type: 'info',
                                message: '已取消提交!'
                            });
                        });
                    }
                },
                /* 保存表单 */
                saveForm() {
                    for (var i = 0; i < this.tableData.length; i++) {
                        if (!this.tableData[i].isSet) {
                            this.$message.warning('请先保存当前编辑项');
                            return this.btnDisabled = false;
                        } else {
                            this.btnDisabled = true;
                        }
                    }
                },
                /* 撤回保存 */
                backtrack() {
                    this.btnDisabled = false;
                },

 这次vue小实例就写到这,如果内容、代码有不妥的地方,望斧正,谢谢。

  • 2
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值