Loading... ### 引言 在工作中遇到一个小问题,整个数据可展示的内容比较多,但可修改的只有一个备注。 想着单独做个备注页面不划算,太麻烦了,在当前页面做个弹框也比较麻烦,还需要控制显示隐藏弹框,做好之后还得刷新页面,太麻烦了。 所以干脆效果做在表格里,双击变成输入框,失去焦点的时候直接调用接口保存,就很舒服了。 ### 效果展示 ![效果展示](https://aliyun-yuesha-public-oss.oss-cn-zhangjiakou.aliyuncs.com/usr/uploads/2023/12/2101285612.png) ### 实现步骤 我这人写教程喜欢按照思维顺序,一步一步来,如果不习惯这种方式的话,可以直接看我在最后给的源码复制。 #### 1. 建立原始模板文件 如果你不是像我这样的`demo`的话,可以跳过这步,我主要是不想搭建一个`vue`项目那么麻烦了 ```html <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>ElementUI的示例页面</title> <!-- import CSS --> <link rel="stylesheet" href="https://unpkg.com/element-ui/lib/theme-chalk/index.css"> </head> <body> <div id="app"> <el-button @click="visible = true">Button</el-button> <el-dialog :visible.sync="visible" title="Hello world"> <p>Try Element</p> </el-dialog> </div> </body> <!-- import Vue before Element --> <script src="https://unpkg.com/vue@2/dist/vue.js"></script> <!-- import JavaScript --> <script src="https://unpkg.com/element-ui/lib/index.js"></script> <script> new Vue({ el: '#app', data: function() { return { visible: false } } }) </script> </html> ``` 首先从`ElementUI`的官网把示例代码拷贝下来,资源用`CDN`的就可以了。 官网链接:[https://element.eleme.cn/#/zh-CN](https://element.eleme.cn/#/zh-CN) 我这里给的链接是国内镜像的`2.x`版本,有其他需要的可以自己找 我指的是上面代码当中的这些部分: ```html <!-- import CSS --> <link rel="stylesheet" href="https://unpkg.com/element-ui/lib/theme-chalk/index.css"> <!-- import Vue before Element --> <script src="https://unpkg.com/vue@2/dist/vue.js"></script> <!-- import JavaScript --> <script src="https://unpkg.com/element-ui/lib/index.js"></script> ``` #### 2. 建立表格结构 然后把表格部分的代码复制过来,链接在这里 [https://element.eleme.cn/#/zh-CN/component/table](https://element.eleme.cn/#/zh-CN/component/table) 包括`<template></template>`模板当中的`HTML`结构,还有`<script></script>`当中的`js`部分 **我这里就当你不会`vue`,直接按照通用教程来讲哈~** 拷贝过来整体结构是这样的: ```html <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>ElementUI的示例页面</title> <link rel="stylesheet" href="https://unpkg.com/element-ui/lib/theme-chalk/index.css"> </head> <body> <div id="app"> <el-table :data="tableData" style="width: 100%"> <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> </body> <script src="https://unpkg.com/vue@2/dist/vue.js"></script> <script src="https://unpkg.com/element-ui/lib/index.js"></script> <script> new Vue({ el: '#app', data: function() { return { tableData: [{ date: '2016-05-02', name: '王小虎', address: '上海市普陀区金沙江路 1518 弄' }, { date: '2016-05-04', name: '王小虎', address: '上海市普陀区金沙江路 1517 弄' }, { date: '2016-05-01', name: '王小虎', address: '上海市普陀区金沙江路 1519 弄' }, { date: '2016-05-03', name: '王小虎', address: '上海市普陀区金沙江路 1516 弄' }] } } }) </script> </html> ``` 这时候,页面就有了基本形状,一个简单的表格输出 ![表格输出](https://aliyun-yuesha-public-oss.oss-cn-zhangjiakou.aliyuncs.com/usr/uploads/2023/12/2666831396.png) #### 3. 补充备注列和主键 然后你需要给其中一列进行处理,比如我需求是备注字段,就需要增加备注部分的代码 ```html <el-table-column prop="remark" label="备注"> </el-table-column> ``` 注意,底下的数据也要有对应的内容 ```js new Vue({ el: '#app', data: function() { return { tableData: [{ date: '2016-05-02', name: '王小虎', address: '上海市普陀区金沙江路 1518 弄', remark: "", }, { date: '2016-05-04', name: '王小虎', address: '上海市普陀区金沙江路 1517 弄', remark: "", }, { date: '2016-05-01', name: '王小虎', address: '上海市普陀区金沙江路 1519 弄', remark: "", }, { date: '2016-05-03', name: '王小虎', address: '上海市普陀区金沙江路 1516 弄', remark: "小虎备注", }] } } }) ``` 每一条记录都得有个`remark`字段,作为接口对接的话,后端会给你返回的。 实际项目当中,我们一般使用`id`或者`uid`作为处理的主键标识,在修改数据的时候,一般也是用这个作为这条数据的标识来进行修改的。 我们一并补上 ```js new Vue({ el: '#app', data: function() { return { tableData: [{ id: 1, date: '2016-05-02', name: '王小虎', address: '上海市普陀区金沙江路 1518 弄', remark: "", }, { id: 2, date: '2016-05-04', name: '王小虎', address: '上海市普陀区金沙江路 1517 弄', remark: "", }, { id: 3, date: '2016-05-01', name: '王小虎', address: '上海市普陀区金沙江路 1519 弄', remark: "", }, { id: 4, date: '2016-05-03', name: '王小虎', address: '上海市普陀区金沙江路 1516 弄', remark: "小虎备注", }] } } }) ``` 然后回到页面上来。页面此时应该有数据渲染了。 ![备注字段](https://aliyun-yuesha-public-oss.oss-cn-zhangjiakou.aliyuncs.com/usr/uploads/2023/12/4015497233.png) #### 4. 输入框制作,确定显示逻辑 然后我们开始做输入框,在上面的`html`结构里先动手 把备注栏的`DOM`结构变换一下 ```html <el-table-column prop="remark" label="备注"> <template slot-scope="scope"> <span v-show="scope.row.id != editRowId">{{ scope.row.remark }}</span> <el-input v-model="scope.row.remark" v-show="scope.row.id == editRowId" /> </template> </el-table-column> ``` 这里的`<el-table-column></el-table-column>`标签内,我们加了个`<template></template>`标签,用来替换掉原先的输出,用了个`slot-scope="scope"`占位符,表示要替换的位置。 里面包含一个`<span></span>`标签和一个`<el-input />`标签,分别用来输出数据的`remark`字段,和用来编辑这个字段。 核心在于这个`v-show`指令,代表可以显示隐藏这个`DOM`元素,这里有两个判断的表达式: 1. `scope.row.id != editRowId` 当前行的`id`字段值不等于全局变量`editRowId`的值时展示 2. `scope.row.id == editRowId` 当前行的`id`字段值等于全局变量`editRowId`的值时展示 这两个表达式和全局变量`editRowId`控制了这个页面具体显示输入框还是`span`标签。 下面的`data`部分也得把这个全局变量给声明了: ```js data: function() { return { // 编辑标识的id editRowId: 0, // 表格数据 tableData: [{ id: 1, date: '2016-05-02', name: '王小虎', address: '上海市普陀区金沙江路 1518 弄', remark: "", }, { id: 2, date: '2016-05-04', name: '王小虎', address: '上海市普陀区金沙江路 1517 弄', remark: "", }] } } ``` 现在你可以尝试把我这里`第4行`的`0`分别改成`1、2、3`是什么效果了。 #### 5. 自动修改变量值 接下来我们让程序“自己”去修改这个变量值 回到最前面,我们整个业务的需求是——“双击这一栏,输出文本变成输入框,失焦时保存并显示新文本” 那么我们就需要有两个事件,`onBlur`和`onDblClick` 这两个事件`ElementUI`都有提供给我们。 ![table组件底部方法](https://aliyun-yuesha-public-oss.oss-cn-zhangjiakou.aliyuncs.com/usr/uploads/2023/12/3232775001.png) 另一个是在`el-input`组件的文档里的。 [https://element.eleme.cn/#/zh-CN/component/input](https://element.eleme.cn/#/zh-CN/component/input) 大家可以自己去看一下。 ![input组件文档的Events部分](https://aliyun-yuesha-public-oss.oss-cn-zhangjiakou.aliyuncs.com/usr/uploads/2023/12/1895596496.png) 实际用法是: 在顶部的`DOM`结构里,加入这个`cell-dblclick`的事件监听 ```html <el-table @cell-dblclick="openRemarkEdit" :data="tableData" style="width: 100%"> <!-- 我这里省略掉很多内容 --> </el-table> ``` 就是这里的`第2行`代码 然后输入框部分也得补充这个事件监听 ```html <el-table-column prop="remark" label="备注"> <template slot-scope="scope"> <span v-show="scope.row.id != editRowId">{{ scope.row.remark }}</span> <el-input v-model="scope.row.remark" v-show="scope.row.id == editRowId" @blur="saveRemark(scope.row.remark)" /> </template> </el-table-column> ``` 重点部分在`第6行`,`@blur="saveRemark(scope.row.remark)"` 这两处补充涉及到`2个方法`,需要在下面`methods`当中定义(`methods`属性需要定义在跟`data`属性同级) ```js methods: { openRemarkEdit(row, column, cell, event) { if (column.property != 'remark') return ; this.editRowId = row.id }, async saveRemark(remark) { if (!remark) return this.editRowId = 0; /* // 请求接口 const resp = await this.$api.xxx(带的参数); if (resp.code == 200) this.$message.success('保存成功'); else this.$message.error(resp.msg); */ this.editRowId = 0; }, } ``` 我这里的请求接口保存方法就省略了,看大家具体的接口方法名,为了方便,我这里的`saveRemark`还加了`async`标识,如果你的写法跟我不同,也可以省略掉 现在的功能就基本实现了,大家也可以点点看看,我这就不放演示视频了 ### 源码展示 最后,把整个文件的源码放出来,写的不好,可以参考一下。 ```html <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>测试表格</title> <!-- import CSS --> <link rel="stylesheet" href="https://unpkg.com/element-ui/lib/theme-chalk/index.css"> </head> <body> <div id="app"> <el-table @cell-dblclick="openRemarkEdit" :data="tableData" style="width: 100%"> <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-column prop="remark" label="备注"> <template slot-scope="scope"> <span v-show="scope.row.id != editRowId">{{ scope.row.remark }}</span> <el-input v-model="scope.row.remark" v-show="scope.row.id == editRowId" @blur="saveRemark(scope.row.remark)" /> </template> </el-table-column> <el-table-column prop="remark" label="备注"> <template slot-scope="scope"> <span v-show="scope.row.id != editRowId">{{ scope.row.remark }}</span> <el-input v-model="scope.row.remark" v-show="scope.row.id == editRowId" @blur="saveRemark(scope.row.remark)" /> </template> </el-table-column> </el-table> </div> </body> <!-- import Vue before Element --> <script src="https://unpkg.com/vue@2/dist/vue.js"></script> <!-- import JavaScript --> <script src="https://unpkg.com/element-ui/lib/index.js"></script> <script> new Vue({ el: '#app', data: function() { return { // 编辑标识的id editRowId: 0, // 表格数据 tableData: [{ id: 1, date: '2016-05-02', name: '王小虎', address: '上海市普陀区金沙江路 1518 弄', remark: "", }, { id: 2, date: '2016-05-04', name: '王小虎', address: '上海市普陀区金沙江路 1517 弄', remark: "", }] } }, methods: { openRemarkEdit(row, column, cell, event) { if (column.property != 'remark') return ; this.editRowId = row.id }, async saveRemark(remark) { if (!remark) return this.editRowId = 0; /* // 请求接口 const resp = await this.$api.xxx(带的参数); if (resp.code == 200) this.$message.success('保存成功'); else this.$message.error(resp.msg); */ this.editRowId = 0; }, } }) </script> </html> ``` 欢迎关注拓行公众号,分享各种技术博客文章拓行——奋勇进取,开拓未来,砥砺前行 最后修改:2023 年 12 月 15 日 © 允许规范转载 打赏 赞赏作者 支付宝微信 赞 如果您对各种技术博客文章感兴趣,欢迎关注拓行公众号,分享各种专业技术知识~