VUE3封装el-table可编辑且键盘控制动态聚焦

321 阅读3分钟

实现:

  1. 表格可编辑
  2. 可通过上下左右的键盘实现跳转,就是动态聚焦
  3. 表格只能输入数字

大家可能会想,只能输入数字我用el-input-number不就行了,但是我还需要实现上下左右的像excel一样,可用上下左右键跳转,方便我输入,el-input-number有自带的自增自减事件,你可以说那加一个el.preventDefault()不就好了,好不了一点,没有用,没有阻止就算了,按上箭头自增和跳转同时发生,我直接给自己气笑了!!!

     <el-table :data="tableData" :span-method="arraySpanMethod" :cell-class-name="tableRowClassName" border :show-header="false">
          <el-table-column type="index" label="序号"  />
          <el-table-column :prop="'amount'+index" v-for="(item,index) in activeNum" :key="index" >
            <template #default="scope">
              <div v-if="scope.row.isInput&&postData[index]&&postData[index].header">
                <el-input v-numberOnly :controls="false" ref="autoFocus"
                  v-model="postData[index].enTraffic" placeholder="请输入"
                  @keyup="nextFocu($event,index, scope.row.index,1)"
                  @input="bindChangeForm($event,index,'enTraffic',1)"
 class="inputDeep" />
              </div>
            </template>
          </el-table-column>
        </el-table>

@keyup事件放下面了,也有人会说拿ref做啊,直接就可以拿到上一个或者下一个,对不起,我做的表格并不规整,是两个table表格看似合并在一起的,上面可能有5个,下面有3个,并不是对齐的,并且都是动态生成表格,也就是说,id为‘el-id-2940-49’输入框的左边,可能是‘el-id-2940-149’,且整个页面有很多不规则表格,所以只能拿到他页面上的祖父元素们来做。

const nextFocu = (el, index, row, type) => {
  let td = document.getElementById(el.srcElement.id).parentElement.parentElement.parentElement.parentElement.parentElement
  if (el.keyCode == 39) {
    if (td && td.nextElementSibling) {
      let nextDom = td.nextElementSibling.querySelectorAll('input')[0]
      nextDom ? nextDom.focus() : '';
    }
  } else if (el.keyCode == 37) {
    if (td && td.previousElementSibling) {
      let lastDom = td.previousElementSibling.querySelectorAll('input')[0];
      lastDom ? lastDom.focus() : '';
    }
  } else if (el.keyCode == 38) {
    let upDom = '';
    let lastChilderDom = ''
    if (type == 1 && row == 1) {
      upDom = getParentElement(td, 'el-table__row').previousElementSibling;
      upDom.childNodes[index + 2].querySelectorAll('input')[0].focus();
    } else if (type == 2) {
      upDom = getParentElement(td, 'el-table__inner-wrapper').parentElement.previousElementSibling;
      lastChilderDom = upDom.querySelectorAll('.el-table__row')[upDom.querySelectorAll('.el-table__row').length - 1]
      lastChilderDom.querySelectorAll('input')[index].focus();
    } else if (type == 3) {
      upDom = getParentElement(td, 'el-table__row').previousElementSibling;
      if (upDom && upDom.querySelectorAll('.el-table__cell')) {
        lastChilderDom = upDom.querySelectorAll('.el-table__cell')[index + 1];
        lastChilderDom.querySelectorAll('input')[0].focus();
      }
    }
  } else if (el.keyCode == 40) {
    let downDom = ""
    let lastChilderDom2 = ''
    if (type == 1 && row == 0) {
      downDom = getParentElement(td, 'el-table__row').nextElementSibling;
      downDom.childNodes[index + 2].querySelectorAll('input')[0].focus();
    } else if (type == 1 && row == 1) {
      downDom = getParentElement(td, 'el-table__inner-wrapper').parentElement.nextElementSibling;
      lastChilderDom2 = downDom.querySelectorAll('.el-table__row')[downDom.querySelectorAll('.el-table__row').length - 1];
      let getDom = lastChilderDom2.querySelectorAll('input')[index];
      getDom ? getDom.focus() : "";
    } else if (type == 3) {
      downDom = getParentElement(td, 'el-table__row').nextElementSibling;
      if (downDom && downDom.querySelectorAll('.el-table__cell')) {
        lastChilderDom2 = downDom.querySelectorAll('.el-table__cell')[index + 1];
        lastChilderDom2.querySelectorAll('input')[0].focus();
      }
    }
  }
}

至于只能输入数字,我做了一个自定义指令v-numberOnly,代码也贴下边。

export default {
  beforeMount(el, binding) {
    el.clickOutsideEvent = (event) => {
      // 判断点击是否发生在el之外
      if (!(el === event.target || el.contains(event.target))) {
        // 如果是,执行绑定的方法
        el.handler = function (event) {
          let  input = event.target;
          input.value = input.value
          .replace(/[^-|0-9.]/g, "")
          .replace(/(\..*)\./g, "$1");
        };
        el.addEventListener("input", el.handler);
      }
    };
    // 添加事件监听
    document.addEventListener("click", el.clickOutsideEvent);
  },
  unmounted(el) {
    // 移除事件监听
    document.removeEventListener("click", el.clickOutsideEvent);
  },
};

最后,可输入表格的css我也贴下边,请夸我贴心!

.el-collapse {
  border-top: none;
  border-bottom: none;
}
.el-collapse-item {
  border-top: 1px solid #f5f5f5;
  border-left: 1px solid #f5f5f5;
  border-right: 1px solid #f5f5f5;
  margin-bottom: 12px;
}
/deep/ .el-collapse-item__wrap {
  background: #fafafa !important;
  border-radius: 0px 0px 0px 0px;
  border: 1px solid #e4e4e4;
  padding: 17px;
  box-sizing: border-box;
}

/deep/ .el-table .warning-row {
  background: #e0eafb !important;
  text-align: center;
}
/deep/ .el-table .success-row {
  background: #ffeed9 !important;
  text-align: center;
}
/deep/ .el-table .info-row {
  background: #eaeaea !important;
  text-align: center;
}
/deep/ .el-table--default .el-table__cell {
  padding: 0;
}
/deep/ .el-table--default .cell {
  height: 50px;
  line-height: 50px;
  padding: 0;
}
/deep/ .el-collapse-item__content {
  padding-bottom: 0;
}
.inputDeep >>> .el-input.is-disabled .el-input__wrapper {
  background: #fff;
}
.inputDeep {
  width: 100%;
}
.inputDeep >>> .el-input__inner {
  -webkit-appearance: none;
  background-color: #fff;
  background-image: none;
  border-radius: 4px;
  border: none !important;
  width: 100%;
  box-shadow: none !important;
}

.inputDeep >>> .el-input__inner:focus {
  outline: none;
}
.inputDeep >>> .el-input__wrapper {
  height: 50px;
  line-height: 50px;
  box-shadow: none !important;
}
.inputDeep >>> .el-input__wrapper:hover {
  box-shadow: none !important;
}
.inputDeep >>> .el-textarea__inner {
  height: 80px !important;
  line-height: 40px !important;
  min-height: 50px !important;
  box-shadow: none !important;
  border: none;
}

.inputDeep >>> .el-descriptions__table.is-bordered .el-descriptions__cell {
  width: 100px;
  text-align: center;
}