vue3 + ts 实现IP地址及Mac地址输入框功能

1、组件完成代码

<template><div class="ip-input"><div v-for="(item, index) in ipArr" :key="index" class="ip-input__item-wrap"><input ref="ipInput" v-model="ipArr[index]" type="text" class="ip-input__item" :disabled="(index==ipArr.length-1 && props.lastDisabled) || disabled" :class="{'ip-input__item--active': index === activeIndex}" @input="handleInput(index)" @focus="handleFocus(index)" @blur="handleBlur(index)"@keydown.left.exact="handleFocus(index - 1)" @keydown.right.exact="handleFocus(index + 1)"@keydown.backspace.exact="handleBackspace(index)"><span v-if="index !== ipArr.length - 1" class="ip-input__dot">.</span></div><div class="ip-tip" v-show="showTip">{{props.tipText}}</div></div>
</template>
<script setup lang="ts">const ipInput = ref()
const props = defineProps({// 默认值value: {type: String,default: ''},// 是否禁用输入框disabled: {type: Boolean,default: false},// 是否禁用最后一位,并默认赋值0 (公司业务要求,可忽略)lastDisabled: {type: Boolean,default: false},// 是否启用输入校验isValidate: {type: Boolean,default: false},// 校验提示信息tipText: {type: String,default: '请输入IP'}
})
const lastValue =  ref(props.lastDisabled?'0':'')
const ipArr = ref(['', '', '', lastValue.value])
const oldIpInput = ref(['', '', '',  lastValue.value])
const activeIndex = ref(-1)
const clipboardText = ref('')const emit = defineEmits(['change', 'input'])const pasteListener = (event: any) => {if (activeIndex.value === -1) { return }const clipboardData = event.clipboardData || window.ClipboardclipboardText.value = clipboardData.getData('text')handlePaste(activeIndex.value)
}
const copyListener = (event: any) => {if (activeIndex.value === -1) { return }const clipboardData = event.clipboardData || window.ClipboardclipboardData.setData('text', ipArr.value.join('.'))event.preventDefault()
}
window.addEventListener('paste', pasteListener)
window.addEventListener('copy', copyListener)onBeforeUnmount(() => {window.removeEventListener('paste', pasteListener)window.removeEventListener('copy', copyListener)
})
const isNumberValid = (value: any) => {return /^\d*$/.test(value) && value <= 255
}
const handleInput = (index: any) => {const newValue: any = ipArr.value[index]// 如果输入的是非数字,或者输入不在0-255之间,则阻止输入if (!isNumberValid(newValue)) {ipArr.value[index] = oldIpInput.value[index]return false}emit('input', ipArr.value.join('.'))oldIpInput.value[index] = newValueif (newValue.length === 3 || (newValue.length === 2 && newValue > 25)) {if (index === ipArr.value.length - 1) { return true }// 将焦点移动到下一个输入框handleFocus(index + 1)}return true
}
const handleFocus = (index: any) => {if (index < 0 || index > ipArr.value.length - 1) { return }if (activeIndex.value !== index) {ipInput.value[index].focus()}activeIndex.value = index
}
const showTip = ref(false)
const handleBlur = (index: any) => {activeIndex.value = -1if(props.isValidate && (ipArr.value[0]==='' || ipArr.value[1]==='' || ipArr.value[2]==='' || ipArr.value[3]==='')) {showTip.value = true} else {showTip.value = false}
}
const handlePaste = (startIndex: any) => {const clipboardText1 = clipboardText.valueconst tempArr = clipboardText1.split('.')let ifor (i = startIndex; i < startIndex + tempArr.length && i < ipArr.value.length; i++) {ipArr.value[i] = tempArr[i]if (!handleInput(i)) { break }}handleFocus(i)
}
const handleBackspace = (index: any) => {if (!ipArr.value[index]) {handleFocus(index - 1)}
}watch(() => props.value,(newVal: any, oldVal: any) => {if (newVal !== oldVal) {emit('change', newVal, oldVal)ipArr.value = ['', '', '', lastValue.value]const tempArr = newVal.split('.')for (let i = 0; i < tempArr.length; i++) {if (!isNumberValid(tempArr[i])) {break}ipArr.value[i] = tempArr[i]}}},{ deep: true, immediate: true }
)defineExpose({ handleBlur, showTip })
</script>
<style lang="scss" scoped>
.ip-input {position: relative;display: inline-flex;align-items: center;justify-content: center;flex-direction: row;.ip-tip {position: absolute;top: 100%;left: 0;color: #f56c6c;font-size: 12px;padding-top: 2px;line-height: 1;animation: topshow 0.1s ease-in-out;@keyframes topshow {from {top: 80%;}to {top: 100%;}}}
}.ip-input__item-wrap {display: flex;align-items: center;justify-content: center;
}.ip-input__item {height: 30px;line-height: 30px;width: 50px;color: #606266;border: none;box-shadow: 0 0 0 1px #dcdfe6 inset;border-radius: 4px;text-align: center;font-size: 13px;outline: none;
}.ip-input__item--active {border-color: #409eff;
}.ip-input__dot {margin: 0 3px;font-size: 20px;color: #606266;
}
input:disabled  {background-color: #ddd;
}
</style>

2、组件使用

<template>
<div><el-form ref="ruleFormRef" :model="formData" :rules="rules" label-width="180px"><el-form-item label="IP地址" prop="ip"><IpInput ref="refIpInput" :value="formData.ip" @input="ipChange" :isValidate="true" /></el-form-item><el-form-item label=""><el-button type="primary"  @click="submitForm">保 存</el-button></el-form-item></el-form>
</div>
</template>
<script setup lang='ts'>
import IpInput from '@/components/IpInput/index.vue'
const formData = ref<any>({ip: ''
})const rules = reactive({ip: [{ required: true, message: '', trigger: 'blur' }]
})// ip输入框
const refIpInput = ref<any>(null)
const ipChange = (val: string) => {formData.value.ip = val
}// 保存
const ruleFormRef = ref<any>()
const submitForm = () => {ruleFormRef.value!.validate(async (valid: boolean) => {// 校验IP输入refIpInput.value.handleBlur()if(refIpInput.value.showTip) returnif (valid) {// const res = await dataApi()}})
}
</script>
<style lang='scss' scoped></style>

3、实现Mac地址输入的修改

        - 将组件中所有的  ['', '', '', lastValue.value] 数组添加两个空值,即改成如下数组

['', '', '', '', '', lastValue.value]

        - 将组件中的 handleBlur 方法修改成

const handleBlur = (index: any) => {activeIndex.value = -1if(props.isValidate && (ipArr.value[0]==='' || ipArr.value[1]==='' || ipArr.value[2]==='' || ipArr.value[3]==='' || ipArr.value[4]==='' || ipArr.value[5]==='')) {showTip.value = true} else {showTip.value = false}
}

        - 将组件中的 isNumberValid 方法修改成

const isNumberValid = (value: any) => {return /^[0-9A-Fa-f]*$/.test(value) && value.length <= 2
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/18945.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【Python Cookbook】S01E01 将长度为N的序列分解为N个单独的变量

目录 问题解决方案讨论 问题 将一个包含 N N N 个元素的元组或者序列&#xff0c;现在想将其分解为 N N N 个单独的变量。 解决方案 任何序列都可以通过简单的赋值操作分解为单独的变量&#xff1a; p (4, 5) x, y p print("x", x) print("y", y)唯…

现在怎么做抖店才能赚钱?这四个重要建议,你千万不能忽略!

大家好&#xff0c;我是电商花花。 现在目前看抖音小店前景和红利依然有很大的市场空间&#xff0c;抖音小店平台流量大&#xff0c;商家入驻门槛低&#xff0c;抖店的运营技术也不像其它传统电商平台那么高。 所以&#xff0c;当下抖音小店仍然是流量大&#xff0c;机遇多。…

近屿OJAC带你解读:什么是API?

API的定义 API&#xff08;Application Programming Interface,应用程序编程接口&#xff09;是一些预先定义的函数&#xff0c;目的是提供应用程序与开发人员基于某软件或硬件得以访问一组例程的能力&#xff0c;而又无需访问源码&#xff0c;或理解内部工作机制的细节。 是…

【Linux】网络高级IO

欢迎来到Cefler的博客&#x1f601; &#x1f54c;博客主页&#xff1a;折纸花满衣 &#x1f3e0;个人专栏&#xff1a;Linux 目录 &#x1f449;&#x1f3fb;五种IO模型&#x1f449;&#x1f3fb;消息通信的同步异步与进程线程的同步异步有什么不同&#xff1f;&#x1f449…

远程工作利器:高效指南教你如何在Linux服务器上部署Jupyter Notebook并实现安全远程访问

远程工作利器&#xff1a;高效指南教你如何在Linux服务器上部署Jupyter Notebook并实现安全远程访问 1.安装 Anaconda和python 你可以在终端中运行以下命令来检查是否已安装&#xff1a; python --version python3 --version安装 pip pip 是 Python 的包管理工具&#xff0c…

长方形边框 上方中间有缺口 css

<div class"text_6">大234234师掌4234柜</div><div class"text-wrapper_1"><span class"paragraph_1">四川慧创云戈科技有限公司推出的“大师掌柜”&#xff0c;是一个以餐饮外卖为切入口&#xff0c;专注实体小店新零售…

一款即支持3v3单片机又支持5v单片机的485收发芯片

原理图参考 H7-TOOL 特此记录 anlog 2024年5月21日

蓝桥杯嵌入式 第六届国赛 更新中……

题目 配置 注意事项 复制LCD的工程&#xff0c;先配置资源 --- 勾选完选项一定要再看一眼&#xff0c;可能选择错误 ADC&#xff1a;配置ADC2_IN15&#xff0c;对应PB15引脚 EEROM&#xff0c;配置PB6和PB7 按键 输入模式PB0、PB1、PB2、PA0 LED 一定要使能PD2 PWM互补输出&…

jquery---ajax方法示例

ajax方法 $.ajax({name:value, name:value, ... }) ajax方法有一个参数&#xff0c;一定长度的对象&#xff0c;内部指定了ajax的请求地址和格式&#xff0c;方式等等&#xff0c;它可以有以下的属性和值 示例 这里展示了一个简单的get请求图片url的实例 let data; let url…

【Spring】认识 Spring AOP

认识 Spring AOP 1.什么是 AOP2.AOP 中的概念3.用 AOP 方式管理日志3.1 编写 AOP 日志注解类3.2 编写控制器用于测试 1.什么是 AOP AOP&#xff08;Aspect Oriented Program&#xff0c;面向切面编程&#xff09;把业务功能分为核心、非核心两部分。 核心业务功能&#xff1a…

ssm校园疫情防控管理系统-计算机毕业设计源码30796

目 录 摘要 1 绪论 1.1目的及意义 1.2开发现状 1.3ssm框架介绍 1.3论文结构与章节安排 2 校园疫情防控管理系统系统分析 2.1 可行性分析 2.2 系统流程分析 2.2.1 数据流程 3.3.2 业务流程 2.3 系统功能分析 2.3.1 功能性分析 2.3.2 非功能性分析 2.4 系统用例分…

真实测评:9款电脑加密软件最新排名

2024年已经过半&#xff0c;电脑加密软件市场发生了很多变化&#xff0c;根据资料汇总&#xff0c;一些电脑加密软件排名也发生了变化&#xff0c;下面是最近的排名。 1、安企神&#xff1a; 可以试试7天的免费试用&#xff0c;用过之后就回不去了 试用版https://work.weix…

【数据分析面试】56.数据格式转换(Python:melt函数)

题目 给定一个df&#xff0c;包含ABCDE多个列。请编写一个 Python 程序&#xff0c;将列 ‘D’ 和 ‘E’ 转换为长格式&#xff0c;并使用 ‘A’、‘B’ 和 ‘C’ 作为标识符。 换句话说&#xff0c;将数据中的D、E两列转换为行&#xff0c;使数据从宽变长。 示例&#xff1…

The First项目报告:一场由社区驱动的去中心化加密冒险—Turbo

2023年3月14日&#xff0c;由OpenAI公司开发自回归语言模型GPT-4发布上线&#xff0c;一时之间引发AI智能领域的轩然大波&#xff0c;同时受到影响的还有加密行业&#xff0c;一众AI代币纷纷出现大幅度拉升。与此同时&#xff0c;一款名为Turbo的Meme代币出现在市场中&#xff…

AI大模型探索之路-实战篇10:数据预处理的艺术:构建Agent智能数据分析平台的基础

系列篇章&#x1f4a5; AI大模型探索之路-实战篇4&#xff1a;深入DB-GPT数据应用开发框架调研 AI大模型探索之路-实战篇5&#xff1a;探索Open Interpreter开放代码解释器调研 AI大模型探索之路-实战篇6&#xff1a;掌握Function Calling的详细流程 AI大模型探索之路-实战篇7…

redis常用数据结构及命令

Redis数据结构简介 Redis可以存储键与5种不同数据结构类型之间的映射&#xff0c;这五种数据结构分别为String(字符串)、List&#xff08;列表&#xff09;、Set&#xff08;集合&#xff09;、Hash&#xff08;散列&#xff09;、和Zset&#xff08;有序集合&#xff09;。 …

电流继电器DL-13 柜内安装带板前接线附件 JOSEF约瑟

DL-10系列电流继电器板前接线为电磁式瞬动过电流继电器&#xff0c;它广泛用于电力系统二次回路继电保护装置线路中&#xff0c;作为过电流启动元件。 系列型号 DL-11电流继电器; DL-12电流继电器; DL-13电流继电器&#xff1b; 一、应用范围 DL-13/2电流继电器 板前接线为…

怎么藏族翻译中文在线翻译?更好地了解藏族文化

怎么藏族翻译中文在线翻译&#xff1f;着全球化的发展&#xff0c;语言交流的重要性日益凸显。藏族&#xff0c;作为中国的一个古老而神秘的民族&#xff0c;其语言对于很多人来说充满了神秘感。然而&#xff0c;在今天的数字化时代&#xff0c;我们有了更多的工具来打破语言壁…

mp4文件损坏怎么修复?三种修复办法分享!

对于我们平时使用到的MP4视频文件&#xff0c;有时候在播放时会遇到文件损坏&#xff0c;无法正常打开&#xff0c;针对这个问题&#xff0c;如何修复损坏的MP4视频文件&#xff1f; 首先&#xff0c;我们需要了解MP4文件损坏的可能原因。常见的原因包括&#xff1a;逻辑损坏、…

sprongboot+vue 游泳馆管理系统

游泳馆管理系统 spring bootvue 主要有游泳课程预约、网上购票、教练预约、游泳器材管理、会员管理等功能&#xff1b; 1、管理员 登录、修改密码 购票管理&#xff1a;查看订单、删除订单、修改订单 教练管理&#xff1a;教练信息查询、修改 课程信息&#xff1a;增删改查课程…