361 lines
9.0 KiB
Vue
361 lines
9.0 KiB
Vue
<template>
|
||
<div :class="{ 'disabled': disabled }">
|
||
<ul class="ipAdress">
|
||
<li v-for="(item, index) in ipAddress" :key="index">
|
||
<input :ref="el => getInputRef(el, index)" v-model="item.value" type="text" class="ipInputClass"
|
||
:disabled="disabled" @input="checkIpVal(item)" @keyup="$event => turnIpPosition(item, index, $event)"
|
||
@blur="handleBlur" @mouseup="handleMouseUp(index)" />
|
||
<div></div>
|
||
</li>
|
||
</ul>
|
||
</div>
|
||
</template>
|
||
|
||
<script lang="ts" setup name="routePage">
|
||
import { ref, watch } from 'vue'
|
||
|
||
// 接收来自上层的数据
|
||
const props = defineProps(['value', 'disabled'])
|
||
|
||
// 更新数据
|
||
const $emits = defineEmits(['update:value', 'blur'])
|
||
|
||
// 存储四个ref
|
||
const ipInputRefs = ref<HTMLInputElement[]>([]);
|
||
// 存储左右标识位
|
||
let markFlag = ref([
|
||
{
|
||
left: false,
|
||
right: false
|
||
},
|
||
{
|
||
left: false,
|
||
right: false
|
||
},
|
||
{
|
||
left: false,
|
||
right: false
|
||
},
|
||
{
|
||
left: false,
|
||
right: false
|
||
}
|
||
])
|
||
|
||
// 更新标识
|
||
let flag = ref(false)
|
||
|
||
// 鼠标点击
|
||
const handleMouseUp = (index: any) => {
|
||
let input = ipInputRefs.value[index]
|
||
// 全为false
|
||
markFlag.value.forEach(item => {
|
||
item.left = false
|
||
item.right = false
|
||
})
|
||
// 证明在开始阶段
|
||
if (input.selectionStart == 0) {
|
||
//console.log('鼠标设置了,', index)
|
||
markFlag.value[index].left = true
|
||
} else {
|
||
markFlag.value[index].left = false
|
||
}
|
||
// 证明在结束
|
||
if (input.selectionStart == (input.value || '').length) {
|
||
markFlag.value[index].right = true
|
||
} else {
|
||
markFlag.value[index].right = false
|
||
}
|
||
}
|
||
|
||
// 获取四个input refs
|
||
const getInputRef = (el: any, index: number) => {
|
||
if (el) {
|
||
ipInputRefs.value[index] = el;
|
||
}
|
||
};
|
||
// 声明IP存储类型
|
||
interface IpType {
|
||
value: string
|
||
}
|
||
// 定义要显示的四个ip
|
||
let ipAddress = ref<IpType[]>([
|
||
{
|
||
value: "",
|
||
},
|
||
{
|
||
value: "",
|
||
},
|
||
{
|
||
value: "",
|
||
},
|
||
{
|
||
value: "",
|
||
},
|
||
])
|
||
// 初始化显示数据
|
||
const initShowData = () => {
|
||
// 判断不合理行为
|
||
if (props.value === '') {
|
||
ipAddress.value.forEach(item => {
|
||
item.value = ''
|
||
})
|
||
} else {
|
||
let ipList = props.value.split('.')
|
||
ipAddress.value.forEach((item: IpType, index: number) => {
|
||
item.value = ipList[index]
|
||
})
|
||
}
|
||
}
|
||
|
||
// 检查ip输入
|
||
const checkIpVal = (item: any) => {
|
||
let val = item.value;
|
||
//console.log(val, '===========')
|
||
// 处理非数字
|
||
val = val.toString().replace(/[^0-9]/g, "");
|
||
val = parseInt(val, 10);
|
||
if (isNaN(val)) {
|
||
val = "";
|
||
} else {
|
||
val = val < 0 ? 0 : val;
|
||
if (val > 255) {
|
||
// 判断val是几位数
|
||
let num = (val + '').length
|
||
if (num > 3) {
|
||
val = parseInt((val + '').substring(0, 3))
|
||
} else {
|
||
val = 255
|
||
}
|
||
}
|
||
}
|
||
item.value = val;
|
||
//console.log(item.value, '=========')
|
||
}
|
||
|
||
// 判断光标左右移动位置
|
||
const turnIpPosition = (item: IpType, index: number, event: any) => {
|
||
let e = event || window.event;
|
||
if (e.keyCode === 37) {
|
||
// 左箭头向左跳转,左一不做任何措施
|
||
if (index == 0) {
|
||
return
|
||
}
|
||
if (e.currentTarget.selectionStart === 0) {
|
||
if (markFlag.value[index].left) {
|
||
handleFocus(index - 1, 'toLeft')
|
||
markFlag.value[index].left = false
|
||
markFlag.value[index].right = false
|
||
} else {
|
||
console.log('左键设置了,', index)
|
||
markFlag.value[index].left = true
|
||
}
|
||
} else {
|
||
markFlag.value[index].right = false
|
||
markFlag.value[index].left = false
|
||
}
|
||
} else if (e.keyCode == 39) {
|
||
// 右箭头向右跳转,右一不做任何措施
|
||
markFlag.value[index].left = false
|
||
let start = e.currentTarget.selectionStart
|
||
if (index != 3 && start === item.value.toString().length) {
|
||
if (markFlag.value[index].right) {
|
||
handleFocus(index + 1, 'toRight')
|
||
markFlag.value[index].left = false
|
||
markFlag.value[index].right = false
|
||
} else {
|
||
markFlag.value[index].right = true
|
||
}
|
||
} else {
|
||
markFlag.value[index].right = false
|
||
}
|
||
} else if (e.keyCode === 8) {
|
||
//console.log('删除键把当前数据删除完毕后会跳转到前一个input')
|
||
// 删除键把当前数据删除完毕后会跳转到前一个input,左一不做任何处理
|
||
if (index !== 0 && e.currentTarget.selectionStart === 0) {
|
||
if (markFlag.value[index].left) {
|
||
ipInputRefs.value[index - 1].focus();
|
||
markFlag.value[index].left = false
|
||
} else {
|
||
//console.log('左键设置了删除,', index)
|
||
markFlag.value[index].left = true
|
||
}
|
||
}
|
||
} else if (e.keyCode === 13 || e.keyCode === 32) {
|
||
//console.log('回车键、空格键、冒号均向右跳转,右一不做任何措施')
|
||
// 回车键、空格键、冒号均向右跳转,右一不做任何措施
|
||
if (index !== 3) {
|
||
ipInputRefs.value[index + 1].focus();
|
||
}
|
||
}
|
||
else if (e.keyCode === 110 || e.keyCode === 190) {
|
||
// 点 . 向右跳转,右一不做任何措施
|
||
// console.log('点击')
|
||
if (item.value == '') {
|
||
return
|
||
}
|
||
if (index !== 3) {
|
||
ipInputRefs.value[index + 1].select();
|
||
}
|
||
}
|
||
else if (item.value.toString().length === 3) {
|
||
//console.log('满3位,光标自动向下一个文本框')
|
||
// 满3位,光标自动向下一个文本框.
|
||
if (index !== 3) {
|
||
//ipInputRefs.value[index + 1].setSelectionRange(0, 0)
|
||
ipInputRefs.value[index + 1].focus();
|
||
}
|
||
}
|
||
}
|
||
|
||
// 处理聚焦
|
||
const handleFocus = (index: number, direction: string) => {
|
||
// 设置当前位置为选中状态 toRight:从左边来的
|
||
let input = ipInputRefs.value[index]
|
||
input.focus()
|
||
let value = input.value
|
||
// null 左右全部设置为true,可以直接跳转
|
||
if ((value || '').length == 0) {
|
||
markFlag.value[index].right = true
|
||
markFlag.value[index].left = true
|
||
} else {
|
||
if (direction == 'toRight') {
|
||
// 可以直接跳回
|
||
//console.log('右键focus,', index)
|
||
markFlag.value[index].left = true
|
||
// 设置光标为左边第一个
|
||
ipInputRefs.value[index].setSelectionRange(0, 0)
|
||
// 设置上一个的右边标识为false
|
||
markFlag.value[index - 1] && (markFlag.value[index - 1].right = false)
|
||
} else {
|
||
// 直接跳回
|
||
markFlag.value[index].right = true
|
||
// 设置后一个侧边为false
|
||
markFlag.value[index + 1] && (markFlag.value[index + 1].left = false)
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
// 格式化补零方法
|
||
const formatter = (val: string) => {
|
||
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;
|
||
}
|
||
|
||
// 监听数据变化,并初始化显示四个数据
|
||
watch(() => props.value, () => {
|
||
//console.log('变化了~', props.value);
|
||
if(flag.value){
|
||
|
||
}else{
|
||
initShowData()
|
||
}
|
||
}, {
|
||
immediate: true
|
||
})
|
||
|
||
// 监听ipAddress数据变化
|
||
watch(ipAddress, () => {
|
||
let str = "";
|
||
for (const i in ipAddress.value) {
|
||
str += formatter(ipAddress.value[i].value);
|
||
}
|
||
if (str === "000000000000") {
|
||
str = "";
|
||
} else {
|
||
str = ipAddress.value.map(item => {
|
||
if (item.value !== null) {
|
||
return item.value + ''
|
||
} else {
|
||
return '0'
|
||
}
|
||
}).join(".")
|
||
}
|
||
$emits('update:value', str)
|
||
flag.value = true
|
||
setTimeout(() => {
|
||
flag.value = false
|
||
}, 100)
|
||
}, {
|
||
deep: true
|
||
})
|
||
|
||
const handleBlur = () => {
|
||
$emits('blur')
|
||
}
|
||
|
||
</script>
|
||
<style lang="scss" scoped>
|
||
.disabled {
|
||
cursor: not-allowed;
|
||
background-color: #f5f7fa;
|
||
|
||
.ipAdress {
|
||
li {
|
||
.ipInputClass {
|
||
color: #c3c4cc;
|
||
cursor: not-allowed;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
.ipAdress {
|
||
display: flex;
|
||
border: 1px solid #dcdfe6;
|
||
border-radius: 4px;
|
||
line-height: 40px;
|
||
width: 120%;
|
||
height: 35px;
|
||
padding-inline-start: 0px;
|
||
padding-left: 10px;
|
||
padding-right: 10px;
|
||
box-sizing: border-box;
|
||
margin: 0;
|
||
}
|
||
|
||
.ipAdress li {
|
||
position: relative;
|
||
margin: 0;
|
||
list-style-type: none;
|
||
}
|
||
|
||
.ipInputClass {
|
||
border: none;
|
||
width: 50px;
|
||
height: 23px;
|
||
text-align: center;
|
||
color: #606266;
|
||
background: transparent;
|
||
}
|
||
|
||
.ipAdress li div {
|
||
position: absolute;
|
||
bottom: 12px;
|
||
right: 0;
|
||
border-radius: 50%;
|
||
background: #b6b8bc;
|
||
width: 2px;
|
||
height: 2px;
|
||
}
|
||
|
||
/*只需要3个div*/
|
||
.ipAdress li:last-child div {
|
||
display: none;
|
||
}
|
||
|
||
/*取消掉默认的input focus状态*/
|
||
.ipAdress input:focus {
|
||
outline: none;
|
||
}
|
||
</style>
|
||
|
||
|