element-ui实现激活码输入框

 

 这个输入框分为8个框,前面的框满了4个字符后自动跳到后面的框,并且支持复制如'aaaa-aaaa-aaaa-aaaa-aaaa-aaaa-aaaa-aaaa'这样的激活码。

代码如下:(这个功能是由ip输入框修改而来,个别注释和变量名还是ip请勿见怪)

<!--
 * @Author: 
 * @Date: 2021-12-16 16:43:32
 * @Description: 激活码输入框
-->
<template>
  <el-popover
    ref="popoverInput"
    :content="tips"
    :max-width="tipsMaxWidth"
    :placement="tipsPlacement"
    :show-html="true"
    :offset-placement="tipsOffset"
    :value="tipsVisible"
    effect="effect"
    trigger="manual"
    popper-class="
      el-popover__for-input el-popover__for-input-form
    "
  >
    <div
      slot="reference"
      :style="styleObj"
      :class="{
        'is-focus': focused,
        'is-disabled': disabled
      }"
      class="code-input"
    >
      <!-- 给ip-input添加提示功能 -->
      <el-input
        v-for="i in 8"
        :key="i"
        :ref="'input_' + i"
        v-model="ipArr[i - 1]"
        :maxlength="4"
        :disabled="disabled"
        :style="{ width: itemWidth }"
        class="code-input__verse"
        @change="updateValue($event, i)"
        @focus="handleFocus"
        @blur="handleBlur"
        @keyup.native="onInputKeyup($event, i)"
        @paste.native.prevent="onPaste($event, i)"
      />
    </div>
  </el-popover>
</template>

<script>
// 获取当前输入框的焦点位置 by liumeng6
function getRange (el) {
  const ret = {}
  if (el.setSelectionRange) {
    ret.begin = el.selectionStart
    ret.end = el.selectionEnd
    ret.result = el.value.substring(ret.begin, ret.end)
  }
  el.focus()
  return ret
}
export default {
  name: 'classInInput',
  props: {
    value: {
      type: String,
      default: ''
    },
    width: {
      type: String,
      default: '100%'
    },
    itemWidth: {
      type: String,
      default: null
    },
    disabled: {
      type: Boolean,
      default: false
    },
    // 提示信息,设置了tips才能显示popover
    tips: {
      type: String,
      default: null
    },
    // popover的最大宽度
    tipsMaxWidth: {
      type: [String, Number],
      default: null
    },
    // popover出现的位置
    tipsPlacement: {
      type: String,
      default: 'top'
    },
    // 出现位置的偏移量
    tipsOffset: {
      type: Number,
      default: 0
    },
    // 粘贴格式有误时提示
    pasteFail: {
      type: String,
      default: null
    }
  },
  data () {
    return {
      ipArr: (this.value || '').split('-'),
      tipsVisible: false,
      focused: false
    }
  },
  computed: {
    styleObj () {
      return {
        width: this.width
      }
    }
  },
  watch: {
    value (val) {
      this.ipArr = val.split('-')
    }
  },
  methods: {
    updateValue (val, index) {
      this.$nextTick(() => {
        let str = val.toLowerCase()
        const reg = new RegExp(/[^a-f0-9]+/, 'gi')
        if (/[^a-f0-9]+/.test(str)) {
          // 输入的内容不是0-9或a-f时,输入框置空
          str = str.replace(reg, '')
        } else {
          // 当不处于第八个输入框,且当前输入框满四位时,自动获取下一个焦点
          if (index < 8 && `${str}`.length >= 4) {
            const inputEl = this.$el.getElementsByTagName('input')[index]
            this._setCursorPosition(inputEl, 0)
          }
        }
        this.ipArr.splice(index - 1, 1, str)

        // 如果ip都为空,则返回空字符串,如果ip不为空,则返回ip字符串
        const emitStr = this.ipArr.every(ip => ip === '') ? '' : this.ipArr.join('-')
        // 如果格式符合才会被emit
        if (/^[a-f0-9]{1,4}-[a-f0-9]{1,4}-[a-f0-9]{1,4}-[a-f0-9]{1,4}-[a-f0-9]{1,4}-[a-f0-9]{1,4}-[a-f0-9]{1,4}-[a-f0-9]{1,4}$/.test(emitStr)) {
          this.$emit(
            'input', emitStr
          )
        }
      })
    },
    /**
     * @author 
     * @date 
     * @desc input按键监听
     */
    onInputKeyup (event, index) {
      const keyCode = event.keyCode || event.which
      const value = event.target.value
      const arrIndex = index - 1 // 值在数组中的顺序 即从0开始
      const ip = this.ipArr[arrIndex]
      // 处理键盘监听,8 为退格键,37 为left箭头,39 为right箭头,110 为数字键盘上的小数点,190为控制键上的小数点,229为中文数字键盘上小数点
      if (keyCode === 8 || keyCode === 37) {
        if (
          (value.length === 0 || getRange(event.target).end === 0) &&
          arrIndex > 0
        ) {
          const inputEl = this.$el.getElementsByTagName('input')[arrIndex - 1]
          this._setCursorPosition(inputEl, inputEl.value.length, event)
        }
      } else if (keyCode === 39) {
        // 按下右箭头,要光标在最后的时候才聚焦下一个
        if (getRange(event.target).end !== value.length) return
        if (arrIndex < 3 && ip !== undefined) {
          const inputEl = this.$el.getElementsByTagName('input')[arrIndex + 1]
          this._setCursorPosition(inputEl, 0, event)
        }
      } else if (
        keyCode === 110 ||
        keyCode === 190 ||
        (keyCode === 229 &&
          (event.code === 'NumpadDecimal' || event.code === 'Period'))
      ) {
        if (!value.length) return
        // 输入小数点或数字键盘上的句号能跳转
        if (arrIndex < 3 && ip !== undefined) {
          const inputEl = this.$el.getElementsByTagName('input')[arrIndex + 1]
          this._setCursorPosition(inputEl, 0, event)
        }
      }
    },

    /**
     * @desc 
     * @author chenguanbin
     * @param {Document} inputEl 设置光标的IP框
     * @param {Number} index 光标位置
     */
    _setCursorPosition (inputEl, index, event) {
      if (inputEl.setSelectionRange) inputEl.setSelectionRange(index, index)
      inputEl.select()
      // 解决缺陷:IE浏览器下一定概率出现,IP输入框按退格键,当前一位是3位数时,无法退回到上一个输入框的问题
      // 原因:IE下先执行了键盘的退格事件,再执行前一个输入框的focus,这样会触发前一个输入框的change事件,导致焦点重新回到原输入框。(正确事件顺序:focus - 退格 - change)
      // 解决:focus事件后阻止后续事件的执行,这样就不会执行键盘的退格事件和输入框的change事件
      event && event.preventDefault()
    },

    /**
     * @author 
     * @date 
     * @desc ip粘贴事件
     */
    onPaste (event, index) {
      const arrayIndex = index - 1
      // `ie`和`chrome`兼容
      const pasteText = event.clipboardData
        ? event.clipboardData.getData('text/plain').trim()
        : window.clipboardData.getData('text').trim()
      if (/^[a-f0-9]{1,4}-[a-f0-9]{1,4}-[a-f0-9]{1,4}-[a-f0-9]{1,4}-[a-f0-9]{1,4}-[a-f0-9]{1,4}-[a-f0-9]{1,4}-[a-f0-9]{1,4}$/.test(pasteText)) {
        const segments = pasteText.split('-')
        segments.forEach((segment, i) => {
          const value = segment
          if (
            arrayIndex + i < 8
          ) {
            this.ipArr.splice(arrayIndex + i, 1, value)
            this.$emit('input', this.ipArr.join('-'))
          }
        })
        this.$emit(
          'input',
          this.ipArr.every(ip => ip === '') ? '' : this.ipArr.join('-')
        )
      } else {
        this.$message.error(this.pasteFail)
      }
    },

    /**
     * @author 
     * @date 
     * @desc 处理焦点事件
     */
    handleFocus () {
      this.focused = true
      if (this.tips) {
        this.tipsVisible = true
      }
    },

    /**
     * @author 
     * @date 
     * @desc 处理失焦事件
     */
    handleBlur () {
      this.focused = false
      if (this.tips) {
        this.tipsVisible = false
      }
    }
  }
}
</script>

<style lang="less" scoped>
.code-input{
  display: inline-block;
  min-width: 162px;
  background-color: #fff;
  border-radius: 2px;
  line-height: 29px;
}
.code-input__verse.el-input{
  position:relative;
  width:12%;
  border-radius:0;
  padding-right: 10px;
  padding-left: 5px;
}
.code-input__verse:not(:last-child):after{
  position:absolute;z-index:10;top:0;right:0;color:#999;content:"-"}
.code-input__verse input{height:30px;border:none;text-align:center}
</style>

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值