输入框内容格式化后 从中间删除光标移至最后一位的问题

转自博文:格式化输入框内容后定位光标位置
具体计算规则
监听 keydown 事件,获取当前光标的位置。
根据输入框的内容和光标位置,计算出当前光标位置的前一个字符的下标(不计算空格)。
判断用户按了哪个键,是退格还是[0-9a-f]。如果是退格,光标应该定位在前一个字符,否则定位到后一个字符,从而计算出期望光标定位在哪个字符后面(不计算空格)。
格式化数据,根据字符位置计算出光标位置(计算空格)。
这里需要注意几点:
当进行选中删除操作时,光标应该不需要前移。
其他输入框不支持的字符需要处理,例如:ctrl等功能键。
html:

<div class="container">
  <input type="text" id="input">
</div>
sass:
.container {
  text-align: center;
  padding-top: 46px;
}

#input {
  font-variant: tabular-nums;
  box-sizing: border-box;
  margin: 0;
  display: inline-block;
  padding: 4px 11px;
  width: 300px;
  height: 32px;
  font-size: 14px;
  line-height: 1.5;
  color: rgba(0, 0, 0, 0.65);
  background-color: #fff;
  border: 1px solid #d9d9d9;
  border-radius: 4px;
  transition: all .3s;
  
  &:focus {
    border-color: #40a9ff;
    outline: 0;
    box-shadow: 0 0 0 2px rgba(24, 144, 255, 0.2);
    border-right-width: 1px !important;
  }
}

babel:

const input = document.querySelector('#input');
  let expectCharIndex; // 期望光标所处位置前一个字符的下标(不包括空格)

  input.onkeydown = function(e) {
    const curValue = input.value; // 当前值
    console.log('keydown 阶段,此时 value 为:', curValue || '空');
    const selectionStart = input.selectionStart; // 当前选中的区域起始位置
    const selectionEnd = input.selectionEnd; // 当前选中区域结束位置
    console.log('当前光标位置:', selectionStart);

    const code = e.keyCode || e.which || e.charCode;
    const preCharIndex = getPreviousCharIndex(curValue, selectionStart);
    console.log('当前光标前一个字符的下标:', preCharIndex);

    // 计算编辑之后光标前一个字符
    if (code === 8) {
      if (selectionStart !== selectionEnd) { // 选中区间删除,此时光标应该不前移动
        expectCharIndex = preCharIndex;
      } else {
        expectCharIndex = preCharIndex - 1;
      }
    } else {
      expectCharIndex = preCharIndex + 1;
    }

    console.log('格式化后,期望光标前一个字符的下标:', expectCharIndex);
  };

  input.onkeyup = function() {
    const value = formatValue(input.value);
    console.log('keyup 阶段,此时 value 为:', value);
    input.value = value;

    const cursorIndex = getCursorIndex(value, expectCharIndex);
    console.log('期望光标的位置:', cursorIndex);
    console.log('=============================');

    // TODO 增加判断,如果是功能键等则不设置
    setTimeout(() => {
      input.setSelectionRange(cursorIndex, cursorIndex);
    }, 10);
  };

  /**
   * 格式化输入框内容,每两个字节中间插入一个空格。
   *
   * @param {string} value - 输入框内容
   * @return {string}
   */
  function formatValue(value) {
    if (!value) {
      return value;
    }
    value = value.replace(/\s*/g, '');
    if (value.length <= 2) {
      return value;
    }
    const arr = [];
    for (let i = 0; i < value.length - 1; i += 2) {
      arr.push(value.charAt(i) + value.charAt(i + 1));
    }
    if (value.length & 1) {
      // 如果是奇数,还需要添加末尾的数
      arr.push(value.charAt(value.length - 1));
    }
    return arr.join(' ');
  }

  /**
   * 根据输入的内容和光标位置计算前一个字符的下标(不计算空格)
   *
   * @param {string} value - 格式化后的输入框内容
   * @param {number} cursorIndex - 当前光标的位置
   * @return {number} 光标前一个字符的下标,如果前面没有字符,则返回 -1。
   */
  function getPreviousCharIndex(value, cursorIndex) {
    let subStr = value.substring(0, cursorIndex);
    subStr = subStr.replace(/\s*/g, '');
    return subStr.length - 1;
  }

  /**
   * 根据格式化之后的值和期望光标位置的前一个字符下标,计算出光标的位置
   *
   * @param {string} value - 格式化之后的值
   * @param {number} charIndex - 光标前一个字符的下标
   * @return {number} 光标的位置
   */
  function getCursorIndex(value, charIndex) {
    if (charIndex < 0) {
      // 如果期望光标前面没有字符,则光标位置为 0
      return 0;
    }
    // 计算格式化之后,字符所在的位置
    let curCharIndex;
    let count = -1;
    for (let i = 0; i < value.length; i++) {
      if (value.charAt(i) !== ' ') {
        count += 1;
      }
      if (count === charIndex) {
        curCharIndex = i;
        break;
      }
    }/**
     * 格式化手机号,133 3333 3333格式
     *
     * @param {string} value - 输入框内容
     * @return {string}
     */
    function format(obj){
      let value = valid(obj.value);
      if (!value) {
        return value;
      }
      value = value.replace(/\s*/g, '');
      if (value.length > 3 && value.length < 8) {
        return value.substr(0, 3) + " " + value.substr(3);
      } else if (value.length >= 8) {
        return value.substr(0, 3) + " " + value.substr(3, 4) + " " + value.substr(7);
      }
      console.log(value);
      obj.value = arr.join(' ');
      return obj.value;
    }
  }

猜你喜欢

转载自blog.csdn.net/jbguo/article/details/86689270
今日推荐