vue2.x version + element-ui2.15 + version implements the ip input box that can only input numbers. The functional style is based on windows and bound to the parent component in both directions

catalogue

1. Bidirectional binding

2.:oninput dynamic binding and @ input event processing

3. Main functions

4. Custom component code

1. Bidirectional binding

The implementation of bidirectional binding is implemented by v-model in vue2.x. The main codes in this subclass are as follows:

export default {
  name: 'IpInput',
  model: {
    prop: 'ipAddress',
    event: 'change'
  },
  props: {
    ipAddress: {
      type: String,
      required: true
    },
    disabled: {
      type: Boolean,
      default: false
    }
  },
  methods: {
    // When the focus is lost, judge whether the input is completed and pass ip to the parent component
    submitIp() {
      this.$nextTick(() => {
        if (!(this.ip1 === '') && !(this.ip2 === '') && !(this.ip3 === '') && !(this.ip4 === '')) {
          const ipVal = this.ip1 + '.' + this.ip2 + '.' + this.ip3 + '.' + this.ip4
          console.log(ipVal)
          this.$emit('change', ipVal)
        } else {
          return
        }
      })
    }
  }
}

The calls in the parent class are as follows

<ip-input v-model="tab.server" :disabled="tab.format !=='RTMP Push' && tab.format !=='RTMPS Push'" />

The tab.server value here will be passed to the prop named ipAddress. At the same time, when < IP input > triggers a change event with a new value, the tab.server property will be updated. In the submitIp() method, the this.$emit('change', ipVal) method is called to return the new value to the parent component.

2.:oninput dynamic binding and @ input event processing

1) Using oninput binding, this method will lead to the inconsistency between v-model and value in the case of Chinese input method. The reason is that in the case of Chinese input method, the v-model in vue will automatically return, and the value is variable, but the value bound by v-mode remains unchanged.

oninput="value=value.replace(/[^0-9]/g, '')"

2) Use: oninput dynamic binding. This method must be combined with this. $nexttick (() = > {}) in the watch to correctly update the DOM data, because this.$refs.ip1.focus() is used in the watch to operate the dom. The DOM in vue is updated asynchronously. This. $nexttick (() = > {}) is a micro task, which is similar to promise in my opinion. Promise in ES6 is very important, such as this.$store.dispatch(), axios and others are promise, which is mainly used to make asynchronous tasks execute sequentially through. then(). The asynchronous execution of js is to execute synchronous tasks in the execution stack first, and then fetch data from the task queue after the execution stack is empty. I just mention it in general here. I've only studied the front end for a month, and I'm still learning. I only know a little about it.

:oninput="ip1=ip1.replace(/[^0-9]/g, '')"

3) Use @ input event handling

@input="ip1=ip1.replace(/[^0-9]/g, '')"

The main differences between @ input and: oninput are as follows:

: oninput will execute the watch method when inputting Chinese and English. This means that inputting Chinese or English will listen to the change of ip in the input box, and it will be executed twice after my test.

@In the input case, inputting Chinese or English will not execute the watch method, indicating that inputting Chinese or English in this case will directly change the value.

I guess the reason is: oninput binds values through v-bind, while @ binds events through v-on. It will directly execute the statements inside. I hope you can give guidance in the comment area.

3. Main functions

1) Cannot input non numbers. In case of input method, it will be processed after the input is completed

2) After entering three digits, the focus will jump to the right automatically

3) Press "↑" to move the focus to the left and "↓" to move the focus to the right (this is not solved temporarily. Press the left and right keys to jump the cursor inside and between the input boxes at the same time. Friends who understand can give guidance in the comment area)

4) Non 0 automatically removes the previous 0, for example: 036 - > 36000 - > 0

5) If the input box is empty, it will be automatically set to 0

 

4. Custom component code

The custom component code is as follows:

<template>
  <div :class="disabled ? 'disabled' : ''" class="ip-box">
    <el-input
      ref="ip1"
      :disabled="disabled"
      v-model="ip1"
      maxlength="3"
      @input="ip1=ip1.replace(/[^\d]/g,'')"
      @keyup.native="keyupEvent(1,$event)"
      @blur="syncIp1(),submitIp()"/>
    <div class="ip-dot" />
    <el-input
      ref="ip2"
      :disabled="disabled"
      v-model="ip2"
      maxlength="3"
      @input="ip2=ip2.replace(/[^\d]/g,'')"
      @keyup.native="keyupEvent(2,$event)"
      @blur="syncIp2(),submitIp()"/>
    <div class="ip-dot" />
    <el-input
      ref="ip3"
      :disabled="disabled"
      v-model="ip3"
      maxlength="3"
      @input="ip3=ip3.replace(/[^\d]/g,'')"
      @keyup.native="keyupEvent(3,$event)"
      @blur="syncIp3(),submitIp()"/>
    <div class="ip-dot" />
    <el-input
      ref="ip4"
      :disabled="disabled"
      v-model="ip4"
      maxlength="3"
      @input="ip4=ip4.replace(/[^\d]/g,'')"
      @keyup.native="keyupEvent(4,$event)"
      @blur="syncIp4(),submitIp()"/>
  </div>
</template>

<script>
export default {
  name: 'IpInput',
  model: {
    prop: 'ipAddress',
    event: 'change'
  },
  props: {
    ipAddress: {
      type: String,
      required: true
    },
    disabled: {
      type: Boolean,
      default: false
    }
  },
  data() {
    return {
      ip1: '',
      ip2: '',
      ip3: '',
      ip4: ''
    }
  },
  watch: {
    'ip1': {
      handler: function() {
        this.$nextTick(() => {
          console.log(this.ip1)
          if (this.ip1.length === 3) {
            this.$refs.ip2.focus()
          }
        })
      }
    },
    'ip2': {
      handler: function() {
        this.$nextTick(() => {
          if (this.ip2.length === 3) {
            this.$refs.ip3.focus()
          }
        })
      }
    },
    'ip3': {
      handler: function() {
        this.$nextTick(() => {
          if (this.ip3.length === 3) {
            this.$refs.ip4.focus()
          }
        })
      }
    }
  },
  created() {
    if (this.ipAddress !== '') {
      // split() splits a string into an array of substrings
      const ipList = this.ipAddress.split('.')
      this.ip1 = ipList[0]
      this.ip2 = ipList[1]
      this.ip3 = ipList[2]
      this.ip4 = ipList[3]
    }
  },
  methods: {
    // Three digit automatic jump. If the ip exceeds 255, set it to 255 and remove the previous 0
    syncIp1() {
      if (this.ip1 === '') {
        this.ip1 = '0'
      } else if (parseInt(this.ip1) > 255) {
        this.ip1 = '255'
        this.$message({
          message: 'This is not a valid value, please specify a 0-255 Values between',
          type: 'error'
        })
      } else if (this.ip1 === '0' || this.ip1 === '00' || this.ip1 === '000') {
        this.ip1 = '0'
      } else {
        this.ip1 = this.ip1.replace(/\b(0+)/g, '')
      }
    },
    syncIp2() {
      if (this.ip2 === '') {
        this.ip2 = '0'
      } else if (parseInt(this.ip2) > 255) {
        this.ip2 = '255'
        this.$message({
          message: 'This is not a valid value, please specify a 0-255 Values between',
          type: 'error'
        })
      } else if (this.ip2 === '0' || this.ip2 === '00' || this.ip2 === '000') {
        this.ip2 = '0'
      } else {
        this.ip2 = this.ip2.replace(/\b(0+)/g, '')
      }
    },
    syncIp3() {
      if (this.ip3 === '') {
        this.ip3 = '0'
      } else if (parseInt(this.ip3) > 255) {
        this.ip3 = '255'
        this.$message({
          message: 'This is not a valid value, please specify a 0-255 Values between',
          type: 'error'
        })
      } else if (this.ip3 === '0' || this.ip3 === '00' || this.ip3 === '000') {
        this.ip3 = '0'
      } else {
        this.ip3 = this.ip3.replace(/\b(0+)/g, '')
      }
    },
    syncIp4() {
      if (this.ip4 === '') {
        this.ip4 = '0'
      } else if (parseInt(this.ip4) > 255) {
        this.ip4 = '255'
        this.$message({
          message: 'This is not a valid value, please specify a 0-255 Values between',
          type: 'error'
        })
      } else if (this.ip4 === '0' || this.ip4 === '00' || this.ip4 === '000') {
        this.ip4 = '0'
      } else {
        this.ip4 = this.ip4.replace(/\b(0+)/g, '')
      }
    },
    // When the focus is lost, judge whether the input is completed and pass ip to the parent component
    submitIp() {
      if (!(this.ip1 === '') && !(this.ip2 === '') && !(this.ip3 === '') && !(this.ip4 === '')) {
        const ipVal = this.ip1 + '.' + this.ip2 + '.' + this.ip3 + '.' + this.ip4
        console.log(ipVal)
        this.$emit('change', ipVal)
      } else {
        return
      }
    },
    // Press the left and right keys to move the focus left and right
    keyupEvent(index, e) {
      this.$nextTick(() => {
        // Press the '↑' key to shift the focus to the left
        if (e.keyCode === 38) {
          if (index === 2) {
            this.$refs.ip1.focus()
          } else if (index === 3) {
            this.$refs.ip2.focus()
          } else if (index === 4) {
            this.$refs.ip3.focus()
          }
        } else if (e.keyCode === 40) {
          // Press the '↓' key to shift the focus to the right
          if (index === 1) {
            this.$refs.ip2.focus()
          } else if (index === 2) {
            this.$refs.ip3.focus()
          } else if (index === 3) {
            this.$refs.ip4.focus()
          }
        }
      })
    }
  }
}
</script>

<style lang='scss' scoped>
.ip-box {
  width: 202px;
  border:1px solid #dcdfe6;
  border-radius: 5px;
  height: 38px; 
  display: flex;
  align-items: center;
  justify-content: center;
  position: relative;
  >>> .el-input__inner {
	border: 0 !important;
    padding: 0;
    text-align: center;
  }
  >>> .el-input {
    width: 48px;
  }
  &.disabled {
    background-color: #f5f7fa;
    color: #c0c4cc;
    cursor: not-allowed;
  }
}
.ip-dot {
  margin-top: 7px;
	display: inline-block;
	width: 3px;
	height: 3px;
	border-radius: 50%;
	background-color: #606266;
}
.disabled {
  .ip-dot {
    background-color: #c0c4cc;
  }
}
</style>

scss is used. You need to use sass loader to select the appropriate version of the project

npm install sass-loader@Version number --save-dev

To change the style in element UI, you need to use the > > > depth selector or / deep / depth selector

The parent component is invoked as follows:

<ip-input v-model="tab.server" :disabled="tab.format !=='RTMP Push' && tab.format !=='RTMPS Push'" />

The v-model is bound with ip address, String type, disabled, whether to disable input (read-only), and the default is false

Bloggers have only taught themselves about the front-end for one month. There must be something to optimize this code, which can be written more concise. What problems can be commented and discussed

Code subject reference Yidamuyanol Articles

Keywords: Javascript Front-end Vue.js elementUI TCP/IP

Added by pinxue on Tue, 23 Nov 2021 01:41:01 +0200