VUE3 实现IP输入框

537 阅读1分钟

子组件



<template>
    <div class="jc-ip-model jc-flex-row">
        <div class="ip-ground jc-flex-row" :class="{ isDisabled: props.isDisabled, active: active }">
            <div v-for="(item, index) in ipAddress" class="ip-item">
                <input
                    class="input"
                    :disabled="props.isDisabled"
                    v-model="item.num"
                    :ref="(el) => getCarou(el, index)"
                    @input="handleInput(index)"
                    @keydown="handleKeyDown($event, index, item)"
                    @blur="setDefaultVal(item, index)"
                    @focus="focusInput(index)"
                    maxlength="3"
                    :key="index"
                />
                <span v-if="index !== ipAddress.length - 1">.</span>
            </div>
        </div>
        <div class="port">
            <el-input-number
                :disabled="props.isDisabled"
                @keyup.enter="enterIp(3)"
                @input="changePort"
                :controls="false"
                v-model="portBase"
                :min="1"
                :max="65535"
            ></el-input-number>
        </div>
    </div>
</template>

<script setup lang="ts">
/**
 * @author : yy 2023/09/07 13:35:29
 * @description:
 * @params : {{catchIp}} ip 地址
 * @params : {{port}} 端口号
 * @example: <jc-ip-model :port="port" :catchIp="ip" @ipModelSend="ipModelSend" @enter="ensureConfig(2)"></jc-ip-model>
 */
import { nextTick, onMounted, ref } from 'vue'
const props = defineProps({
    catchIp: {
        type: String
    },
    port: {
        type: String,
        default: null
    },
    isDisabled: {
        type: Boolean,
        default: false
    }
})

const ipAddress = ref([
    { id: 1, num: '' },
    { id: 2, num: '' },
    { id: 3, num: '' },
    { id: 4, num: '' }
])

const divDomList = ref(new Map())
const getCarou = (el, id) => {
    if (el) {
        divDomList.value.set(id, el)
    }
}
const realIp = ref()

// 验证ip是否合格
let pattern = /^([1-9]?\d|1\d{2}|2[0-4]\d|25[0-5])(.([1-9]?\d|1\d{2}|2[0-4]\d|25[0-5])){3}$/

const handleInput = (index) => {
    // TODO
    ipAddress.value[index].num = ipAddress.value[index].num.replace(/[^0-9]/g, '')
    let ip = ipAddress.value[index].num
    if (ip.length > 1 && ip[0] === '0') {
        ipAddress.value[index].num = ip.slice(1)
    }
    if (ip > 255) {
        ipAddress.value[index].num = '255'
    }
    if (ip.length === 3) {
        let nextIndex = index + 1
        if (nextIndex <= 3) {
            divDomList.value.get(nextIndex).focus()
        }
    }
    realIp.value = ipAddress.value[0].num + '.' + ipAddress.value[1].num + '.' + ipAddress.value[2].num + '.' + ipAddress.value[3].num
  
// 验证ip是否符合请求 不符合不添加
if (pattern.test(realIp.value)) {
     emits('ipModelSend', { ip: realIp.value, port: String(portBase.value) })
}

  
}
const changePort = () => {
    realIp.value = ipAddress.value[0].num + '.' + ipAddress.value[1].num + '.' + ipAddress.value[2].num + '.' + ipAddress.value[3].num
    console.log('realIp.value', realIp.value, portBase.value)
    nextTick(() => {
        console.log('realIp.value', realIp.value, portBase.value)
        if (portBase.value == null) {
            portBase.value = ''
        }
      // 验证ip是否符合请求 不符合不添加
if (pattern.test(realIp.value)) {
     emits('ipModelSend', { ip: realIp.value, port: String(portBase.value) })
}

    })
}

const focusInput = (index) => {
    active.value = true
    if (index > 0 && !ipAddress.value[0].num) {
        divDomList.value.get(0).focus()
    }
}
const setDefaultVal = (item, index) => {
    active.value = false
    //当input失去焦点,而ip没有赋值时,会自动赋值为0
    if (index > 0 && item.num == '') {
        item.num = '0'
    }
}
// 回车实践
const enterIp = (index) => {
    if (index === 3) {
        emits('enter')
    }
}
const handleKeyDown = (event, index, item) => {
    //删除键把当前数据删除完毕后会跳转到前一个input,左一不做任何处理
    let val = item.num
    if (event.keyCode == 8) {
        if (index == 0) {
        } else if (val == '') {
            let nextIndex = index - 1
            divDomList.value.get(nextIndex).focus()
        }
    }
    if (index > 0 && !ipAddress.value[0].num) {
        divDomList.value.get(0).focus()
    }
    //右箭头、回车键、空格键、冒号均向右跳转,右一不做任何措施  切必须有值
    if (event.keyCode == 39 || event.keyCode == 13 || event.keyCode == 32 || event.keyCode == 190 || event.keyCode == 110) {
        console.log(index)
        if (val && index != 3) {
            divDomList.value.get(index + 1).focus()
        }
        if (index === 3) {
            emits('enter')
        }
    }
}
const emits = defineEmits(['ipModelSend', 'enter'])
const portBase = ref()
const IpModelCancel = (newVal) => {
    if (props.catchIp) {
        let ip = JSON.parse(JSON.stringify(props.catchIp))
        ipAddress.value[0].num = ip.split('.')[0]
        ipAddress.value[1].num = ip.split('.')[1]
        ipAddress.value[2].num = ip.split('.')[2]
        ipAddress.value[3].num = ip.split('.')[3]
        portBase.value = Number(props.port) || null
    }
}
const active = ref(false)

watch(
    () => props.catchIp,
    (newVal, oldVal) => {
        IpModelCancel(newVal)
    },
    { immediate: true, deep: true }
)
</script>

<style scoped lang="scss">
.jc-ip-model {
    width: 210px;
    height: 24px;
    background: #ffffff;
    line-height: 24px;

    .ip-ground {
        padding: 0 5px;
        border-radius: 4px;
        color: $jc-text;
        border: 1px solid $jc-border-regular;
        &:hover {
            border: 1px solid $jc-border;
        }
        &.active {
            border: 1px solid $jc-primary;
        }
        &.isDisabled {
            background: #f5f7fa;
            color: $jc-text-disabled;
        }
        .ip-item {
            position: relative;
            height: 22px;
            .input {
                text-align: center;
                height: 20px;
                line-height: 22px;
                width: 50px;
            }
            span {
                position: absolute;
                bottom: -2px;
                right: 0;
            }
        }
    }

    input:focus {
        outline: none;
    }
    .port {
        height: 22px;
        line-height: 22px;
        width: 50px;
        margin-left: 8px;
        :deep(.el-input-number--small) {
            .el-input {
                width: 70px;
                .el-input__wrapper {
                    padding-left: 4px;
                    padding-right: 4px;
                }
            }
        }
    }
}
</style>
父组件

<ip-model :catchIp="catchIp" @ipModelSend="ipModelSend">