VUE-实现一个可编辑修改的表格/清空回车默认事件/回车和换行事件冲突/失焦不修改回车保存


前言

最近做的一个功能发现,其中还挺多坑的,就写个小记录吧,也为后人少踩点坑,下面就按我的开发过程来讲述这其中的问题吧。


一、失焦不修改内容回车才保存

在这里插入图片描述
如图是一个表格,我们需要表格的单元格内容,双击或者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也是不错的~

突然发现要是用事件委托来做不是会简单很多吗,我的猪脑子~

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

文默

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值