vue自定义封装组件 ip输入组件

690 阅读1分钟

由于在使用ui框架中没有合适的ip地址类型输入框,所以自己封装了一个

功能:

  • 可增、删、改
  • 可在每个input间进行切换
  • 回车跳转
<template>
    <ul>
        <li v-for="(item,index) in ipAddress" :key="index">
            <input ref="ipInput"  v-model="item.value" type="text" 
            @input="checkIpVal(item)" 
            @keyup="turnIpPosition(item,index,$event)" />
            <div></div>
        </li>
    </ul>
</template>

<script>
export default {
    props: {
        value: {
            type: String,
            default: ''
        }
    },
    data() {
        return {
            ipAddress: [
                {
                    value: ''
                },{
                    value: ''
                },{
                    value: ''
                },{
                    value: ''
                }
            ]
        }
    },
    watch: {
        ipAddress: { // 双向数据绑定的value
            handler: function (newVal, oldVal) {
                console.log(newVal, oldVal);
                let str = ''
                for (const i in this.ipAddress) {
                    str += this.formatter(this.ipAddress[i].value)
                }
                if (str === '000000000000') {
                    str = ''
                }
                this.$emit('input', str);
            },
            deep: true
        }

    },
    methods: {
        // 格式化补零方法
        formatter(val) {
            let value = val.toString()
            if (value.length === 2) {
                value = '0' + value
            } else if (value.length === 1) {
                value = '00' + value
            } else if (value.length === 0) {
                value = '000'
            }
            return value
        },
        // 检查ip输入为0-255
        checkIpVal(item) {
            //确保每个值都处于0-255
            let val = item.value;
            // 处理非数字
            val = val.toString().replace(/[^0-9]/g,'');
            val = parseInt(val, 10);
            if(isNaN(val)) {
                val = '';
            } else {
                val = val < 0 ? 0 : val;
                val = val > 255 ? 255 : val;
            }
            item.value = val;
        },
        // 光标位置判断
        turnIpPosition(item, index, event) {
            let self = this;
            let e = event || window.event;
            if (e.keyCode === 37) { // 左箭头向左跳转,左一不做任何措施
                // 事件监听器对象的起点位置
                if(index !== 0 && e.currentTarget.selectionStart === 0) {
                    self.$refs.ipInput[index - 1].focus();
                }
            } else if (e.keyCode == 39) { // 右箭头向右跳转,右一不做任何措施
                if(index !== 3 && e.currentTarget.selectionStart === item.value.toString().length) {
                    self.$refs.ipInput[index + 1].focus();
                }
            } else if (e.keyCode === 8) { // 删除键把当前数据删除完毕后会跳转到前一个input,左一不做任何处理
                if(index !== 0 && item.value === '') {
                    self.$refs.ipInput[index - 1].focus();
                }
            } else if (e.keyCode === 13 || e.keyCode === 32 || e.keyCode === 190) {// 回车键、空格键、冒号均向右跳转,右一不做任何措施
                if(index !== 3) {
                    self.$refs.ipInput[index + 1].focus();
                }
            } else if (item.value.toString().length === 3) { // 满3位,光标自动向下一个文本框
                if(index !== 3) {
                    self.$refs.ipInput[index + 1].focus();
                }
            }
        },
        setIPInit(ipVal){
            const ipVals = ipVal.split(".");
            for (const i in this.ipAddress) {
                this.ipAddress[i].value = ipVals[i] ?? "";
            }
        },
    }
}
</script>

调用组件
由于v-model的本质是 v-bind:value="value" @input="val=> value = val",但它会默认以prop中的value和input事件绑定,所以子组件传递的 str ipaddress 进行了绑定

<ip-address-input
  ref="ip"
  v-model="ipaddress"
  :value="ipaddress"
>
</ip-address-input>