1

首先,我不是原创

原创是https://segmentfault.com/a/1190000023041401
原创是https://segmentfault.com/a/1190000023041401
原创是https://segmentfault.com/a/1190000023041401

重要的原创说三遍

我是在他的基础上,整理出一个vue3可用的简单版本,供大家参考

喏,图都是直接用原创作者的图,因为我不是原创。

MobileCode.vue:

<template>
  <div class="input-box">
    <div
      class="input-content"
      @keydown="keydown"
      @keyup="keyup"
      @paste="paste"
      @mousewheel="mousewheel"
      @input="inputEvent"
    >
      <input
        max="9"
        min="0"
        maxlength="1"
        data-index="0"
        v-model.trim.number="input[0]"
        type="number"
        ref="firstinput"
      />
      <input
        max="9"
        min="0"
        maxlength="1"
        data-index="1"
        v-model.trim.number="input[1]"
        type="number"
      />
      <input
        max="9"
        min="0"
        maxlength="1"
        data-index="2"
        v-model.trim.number="input[2]"
        type="number"
      />
      <input
        max="9"
        min="0"
        maxlength="1"
        data-index="3"
        v-model.trim.number="input[3]"
        type="number"
      />
      <input
        max="9"
        min="0"
        maxlength="1"
        data-index="4"
        v-model.trim.number="input[4]"
        type="number"
      />
      <input
        max="9"
        min="0"
        maxlength="1"
        data-index="5"
        v-model.trim.number="input[5]"
        type="number"
      />
    </div>
  </div>
</template>

<script>
import { ref } from 'vue'; // vue3需要,vue2不需要可以删掉

export default {
  setup() {
    // vue3的写法,vue2的话,把这个setup方法删除
    // 然后在data()里面定义input就可以
    const input = ref(new Array(6).fill(''));
    return {
      input,
    }
  },
  methods: {
    // 解决一个输入框输入多个字符
    inputEvent(e) {
      var index = e.target.dataset.index * 1
      var el = e.target
      el.value = el.value
        .replace(/Digit|Numpad/i, '')
        .replace(/1/g, '')
        .slice(0, 1)
      this.input[index] = el.value
    },
    keydown(e) {
      var index = e.target.dataset.index * 1
      var el = e.target
      if (e.key === 'Backspace') {
        if (this.input[index] && this.input[index].length > 0) {
          this.input[index] = ''
        } else {
          if (el.previousElementSibling) {
            el.previousElementSibling.focus()
            this.input[index - 1] = ''
          }
        }
      } else if (e.key === 'Delete') {
        if (this.input[index].length > 0) {
          this.input[index] = ''
        } else {
          if (el.nextElementSibling) {
            this.input[(index = 1)] = ''
          }
        }
        if (el.nextElementSibling) {
          el.nextElementSibling.focus()
        }
      } else if (e.key === 'Home') {
        el.parentElement.children[0] && el.parentElement.children[0].focus()
      } else if (e.key === 'End') {
        el.parentElement.children[this.input.length - 1] &&
          el.parentElement.children[this.input.length - 1].focus()
      } else if (e.key === 'ArrowLeft') {
        if (el.previousElementSibling) {
          el.previousElementSibling.focus()
        }
      } else if (e.key === 'ArrowRight') {
        if (el.nextElementSibling) {
          el.nextElementSibling.focus()
        }
      } else if (e.key === 'ArrowUp') {
        if (this.input[index] * 1 < 9) {
          this.input[index] = (this.input[index] * 1 + 1).toString()
        }
      } else if (e.key === 'ArrowDown') {
        if (this.input[index] * 1 > 0) {
          this.input[index] = (this.input[index] * 1 - 1).toString()
        }
      }
    },
    keyup(e) {
      var index = e.target.dataset.index * 1
      var el = e.target
      // 解决输入e的问题
      el.value = el.value
        .replace(/Digit|Numpad/i, '')
        .replace(/1/g, '')
        .slice(0, 1)
      if (/Digit|Numpad/i.test(e.code)) {
        // 必须在这里符直,否则输入框会是空值
        this.input[index] = e.code.replace(/Digit|Numpad/i, '')
        el.nextElementSibling && el.nextElementSibling.focus()
        if (index === 5) {
          if (this.input.join('').length === 6) {
            document.activeElement.blur()
          }
        }
      } else {
        if (this.input[index] === '') {
          this.input[index] = ''
        }
      }
      this.$emit( 'complete', this.input.slice());
    },
    mousewheel(e) {
      var index = e.target.dataset.index
      if (e.wheelDelta > 0) {
        if (this.input[index] * 1 < 9) {
          this.input[index] = (this.input[index] * 1 + 1).toString()
        }
      } else if (e.wheelDelta < 0) {
        if (this.input[index] * 1 > 0) {
          this.input[index] = (this.input[index] * 1 - 1).toString()
        }
      } else if (e.key === 'Enter') {
        if (this.input.join('').length === 6) {
          document.activeElement.blur()
          this.$emit('complete', this.input.slice())
        }
      }
    },
    paste(e) {
      // 当进行粘贴时
      e.clipboardData.items[0].getAsString((str) => {
        if (str.toString().length === 6) {
          document.activeElement.blur();
          this.input = str.split('');
          this.$emit( 'complete', this.input.slice())
        } else {
          // 如果粘贴内容不合规,清除所有内容
          this.input[0] = new Array(6)
        }
      })
    },
  },
  mounted() {
    // 等待dom渲染完成,在执行focus,否则无法获取到焦点
    this.$nextTick(() => {
      this.$refs.firstinput.focus()
    })
  },
  emits: ['complete'],
}
</script>

<style lang="scss" scoped>
.input-box {
  .input-content {
    width: 512px;
    height: 60px;
    display: flex;
    align-items: center;
    justify-content: space-between;

    input {
      color: inherit;
      font-family: inherit;
      border: 0;
      outline: 0;
      border-bottom: 1px solid #919191;
      height: 60px;
      width: 60px;
      font-size: 44px;
      text-align: center;
    }
  }

  input::-webkit-outer-spin-button,
  input::-webkit-inner-spin-button {
    appearance: none;
    margin: 0;
  }
}
</style>

父组件调用:

<MobileCode @complete="onComplete" />
<script setup>
// vue3写法,vue2在methods里定义
const onComplete = (val) => {
  console.log('complete', val);
}
</script>

隐约雷鸣
631 声望4 粉丝

人声控,吉他控,喵星控。