前言
最近做的一个功能发现,其中还挺多坑的,就写个小记录吧,也为后人少踩点坑,下面就按我的开发过程来讲述这其中的问题吧。
一、失焦不修改内容回车才保存
如图是一个表格,我们需要表格的单元格内容,双击或者haver到会出现编辑按键点击可以变为 input 输入框,对内容进行修改。
第一版
当时想的是需要获取到每一个单元格的位置,这就麻烦了,一个表格,可以说是一个二维的,得通过行和列来定位到每一个格子。
具体实现就不记得了,这里大概说下一开始咋想的
首先DOM的层面:我们可以通过一个v-show来进行切换,如果触发双击的行为,就把赋给 v-show 的值变为 true 就可以实现展示和编辑的切换了。这一步并不难,但难点在于我们如何定位到这个单元格里。
<el-table-column
:show-overflow-tooltip="true"
align="center"
label="英文"
>
<template slot-scope="scope">
<div
:class="b('contentStyle')"
@dblclick="changeEnddate(scope.$index,'en', scope.row)"
>
<span v-if="!scope.row.is_show_en">{{ scope.row.en }}</span>
<el-input
v-else
:ref='scope.$index'
v-model="scope.row.en"
clearable
size="mini"
@blur="switchShow(scope.$index,'en')"
@keyup.enter.native="$event.target.blur"
/>
</div>
</template>
</el-table-column>
这里就是先获取到列和再来获取到行来定位的。
methods: {
// 双击编辑
// 切换input框的显示状态
switchShow(index, tag, tmp_this=this){
console.log('------->tmp_this.tableData[index]', tmp_this.tableData);
tmp_this.tableData[index][`is_show_${tag}`] = !tmp_this.tableData[index][`is_show_${tag}`];
tmp_this.tableData = [...tmp_this.tableData];
},
// 显示input框, 使光标焦点当前input框
changeEnddate(index, tag){
console.log('------->index', index);
this.switchShow(index, tag, this);
this.$nextTick(() => {
this.$refs[index].focus();
console.log('------->ref', this.$refs[index]);
});
// setTimeout( ()=> {
// this.$refs['enddateinput' + tag + '&' + index].focus();
// }, 1);
}
可以发现这种方式是可以的,但是很麻烦,而且不好维护,打个比方,要是我们后面还得给表格在添加多一列呢?我们写代码,要考虑他的,可维护行,扩展性等。
另外上卖的思路来源于该篇博客,如有冒犯,请联系我处理。
第二版
针对上面的问题,我想是不是可以单独把一列提取出来?把那一列提取出来为一个组件的话,那么一列里面我们就只需要考虑该列中第几行的单元格的行为。我们就不需要去考虑它是第几列的。是不是瞬间从之前的二维降到一维了,难度下降了不是一点点的事了。
组件:
<template>
<div
:class="b()"
@dblclick="changeEnddate()"
>
<span
v-if="show"
style="display: flex"
>
<div :class="b('word')">{{ showData }}</div>
<el-button
type="primary"
icon="el-icon-edit"
:class="b('icon')"
size="mini"
@click="changeEnddate()"
/>
</span>
<el-input
v-else
ref="cxk"
v-model="showData"
size="mini"
type="textarea"
clearable
maxlength="500"
show-word-limit
@blur="blurDate($event)"
@keydown.enter.native="submit($event)"
@keyup.enter.native="keyData($event)"
/>
</div>
</template>
组件里的方法:思想上
methods: {
changeEnddate() {
this.show = false;
this.$nextTick(() => {
this.$refs.cxk.focus();
});
},
submit(event) {
event.preventDefault();
},
async keyData(event) {
event.preventDefault();
this.showData=event.target.value.trim();
this.show=true;
this.is = true;
this.$emit('update', this.showData, this.rowData);
},
blurDate(event){
this.showData=event.target.value.trim();
//奥义:标签大法好,解决回车触发失焦事件
if(this.is === false) {
if(this.showData!==this.temData) {
this.showData = this.data;
}
}
this.show=true;
this.is = false;
}
}
父组件的使用:传入该列单元格的数据
<el-table-column
:show-overflow-tooltip="true"
align="center"
label="英文"
>
<template slot-scope="scope">
<Column
:row-data="scope"
:data="scope.row.locale2text['en-US']"
@update="upDataEn"
/>
</template>
</el-table-column>
这么改写之后,爽太多了,根部不用考虑那么多了。同时如果需要多加一列也更加好处理了。
大体思想就是如上,那么下面我细细说说上面实现中会遇到的几个坑的地方:
注意点一:回车触发失焦事件(失焦事件触发两次)
首先是,我们需要点击后是输入框,我们修改内容(初始为1),修改完后(变为2),回车的话,就触发接口方法保存(保存2)。如果不是回车,点击其他地方的失焦的话,数据不发生改变,修改后的数据复原(2变回1)。
好的,这不难,我们用 @blur=“blurDate($event)” 这个属性来监听失焦事件。失焦的话就复原数据。
问题就来了,我们回车的话也会触发失焦。也就会复原数据,就会导致我们接口传递的数据是被复原的原本的数据,而不是我们修改过得
这里我们是通过添加一个标识(上面中是 is),在失焦触发的方法中做判断,如果为 false 就复原修改过数据,反之就不对数据复原。OK,完美解决,失焦事件触发两次的问题。
注意点二:使用.native
注意!!!如果用了封装组件的话,比如element等,这个时候使用按键修饰符需要加上 .native
对于 .native ,官方的介绍是: 你可能想在某个组件的根元素上监听一个原生事件。可以使用 v-on 的修饰符 .native
举个例子:
这里本来开始是用input实现的,但是后面需要添加一个清空内容的功能,所以我就改为 el-input 就能使用该组件的的 clearable 属性了。加了后没留意测试,直到后面测试说不行了。回头才发现,没有对下面的回车触发的方法添加 .native
加上了就没有问题了~~
注意点三:回车和换行事件冲突(回车和清空回车默认事件)
这次是因为,input输入框是单行的,当内容多了的时候,不便于展示,所以我们添加多一个 teatext 的属性,使得 el-input输入框变为文本域的格式,那么,问题又来了,文本域中会有回车换行的默认行为,会和回车保存的行为冲突。
这里我们的解决方法是,去除输入框的默认方法就好了
event.preventDefault();
本以为这里就好了的,结果发现还是不行呀。研究了很久,突然,在查看的过程中想到了不记得哪里的一条评论说,回车按下去是按下去触发还是弹起来触发。
这就不对劲了,回去一看,我之前的事件是回车弹起来的时候触发的,那么按下去的时候,就触发了换行的默认行为了。
这时无语死了,然后再控件上再添加多一个方法,让他按下去的时候也清除默认行为。
@keydown.enter.native="submit($event)"
@keyup.enter.native="keyData($event)"
到此就解决啦!
后面又啥需求又会遇到啥相关的再来补充吧~
第三版
其实公司有自己实现的组件的,我晕,自己捣鼓半天,不过学到不少,下面学习看看自己和公司组件的区别,如何实现的。
总结
一生二,二生三,三生万物。用来形容Bug也是不错的~
突然发现要是用事件委托来做不是会简单很多吗,我的猪脑子~