引言
在工作中遇到一个小问题,整个数据可展示的内容比较多,但可修改的只有一个备注。
想着单独做个备注页面不划算,太麻烦了,在当前页面做个弹框也比较麻烦,还需要控制显示隐藏弹框,做好之后还得刷新页面,太麻烦了。
所以干脆效果做在表格里,双击变成输入框,失去焦点的时候直接调用接口保存,就很舒服了。
效果展示
实现步骤
我这人写教程喜欢按照思维顺序,一步一步来,如果不习惯这种方式的话,可以直接看我在最后给的源码复制。
1. 建立原始模板文件
如果你不是像我这样的demo
的话,可以跳过这步,我主要是不想搭建一个vue
项目那么麻烦了
<!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
我这里给的链接是国内镜像的2.x
版本,有其他需要的可以自己找
我指的是上面代码当中的这些部分:
<!-- 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
包括<template></template>
模板当中的HTML
结构,还有<script></script>
当中的js
部分
我这里就当你不会vue
,直接按照通用教程来讲哈~
拷贝过来整体结构是这样的:
<!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>
这时候,页面就有了基本形状,一个简单的表格输出
3. 补充备注列和主键
然后你需要给其中一列进行处理,比如我需求是备注字段,就需要增加备注部分的代码
<el-table-column
prop="remark"
label="备注">
</el-table-column>
注意,底下的数据也要有对应的内容
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
作为处理的主键标识,在修改数据的时候,一般也是用这个作为这条数据的标识来进行修改的。
我们一并补上
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: "小虎备注",
}]
}
}
})
然后回到页面上来。页面此时应该有数据渲染了。
4. 输入框制作,确定显示逻辑
然后我们开始做输入框,在上面的html
结构里先动手
把备注栏的DOM
结构变换一下
<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
元素,这里有两个判断的表达式:
scope.row.id != editRowId
当前行的id
字段值不等于全局变量editRowId
的值时展示scope.row.id == editRowId
当前行的id
字段值等于全局变量editRowId
的值时展示
这两个表达式和全局变量editRowId
控制了这个页面具体显示输入框还是span
标签。
下面的data
部分也得把这个全局变量给声明了:
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
都有提供给我们。
另一个是在el-input
组件的文档里的。
https://element.eleme.cn/#/zh-CN/component/input
大家可以自己去看一下。
实际用法是:
在顶部的DOM
结构里,加入这个cell-dblclick
的事件监听
<el-table
@cell-dblclick="openRemarkEdit"
:data="tableData"
style="width: 100%">
<!-- 我这里省略掉很多内容 -->
</el-table>
就是这里的第2行
代码
然后输入框部分也得补充这个事件监听
<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
属性同级)
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
标识,如果你的写法跟我不同,也可以省略掉
现在的功能就基本实现了,大家也可以点点看看,我这就不放演示视频了
源码展示
最后,把整个文件的源码放出来,写的不好,可以参考一下。
<!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>