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

news2024/11/16 23:37:37

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.Clipboard
  clipboardText.value = clipboardData.getData('text')
  handlePaste(activeIndex.value)
}
const copyListener = (event: any) => {
  if (activeIndex.value === -1) { return }
  const clipboardData = event.clipboardData || window.Clipboard
  clipboardData.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] = newValue
  if (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 = -1
  if(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.value
  const tempArr = clipboardText1.split('.')
  let i
  for (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) return

    if (valid) {
      // const res = await dataApi()
    }
  })
}
</script>
<style lang='scss' scoped>

</style>

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

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

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

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

const handleBlur = (index: any) => {
  activeIndex.value = -1
  if(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.coloradmin.cn/o/1713793.html

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

相关文章

Python装饰器的应用

Python 中的装饰器是一种语法糖&#xff0c;可以在运行时&#xff0c;动态的给函数或类添加功能。装饰器本质上是一个函数&#xff0c;使用 函数名就是可实现绑定给函数的第二个功能 。它的作用就是在不修改被装饰对象源代码和调用方式的前提下为被装饰对象添加额外的功能。 …

清华大学提出IFT对齐算法,打破SFT与RLHF局限性

监督微调&#xff08;Supervised Fine-Tuning, SFT&#xff09;和基于人类反馈的强化学习&#xff08;Reinforcement Learning from Human Feedback, RLHF&#xff09;是预训练后提升语言模型能力的两大基础流程&#xff0c;其目标是使模型更贴近人类的偏好和需求。 考虑到监督…

奥利奥罚单背后的启示:企业合规与反垄断的边界

在全球化的经济环境中&#xff0c;企业面临着激烈的市场竞争。为了在竞争中脱颖而出&#xff0c;一些企业可能会采取不正当的竞争手段&#xff0c;如垄断、价格歧视等。然而&#xff0c;这些行为往往会触犯反垄断法规&#xff0c;给企业带来严重的法律风险。最近&#xff0c;奥…

jsp音乐网站的设计与实现

需求收集 经过与客户探讨后 得到初步的活动图,此活动图叙述了游客、会员、管理员在网站的活动得到初步的类图得到网站功能包图得到用例图 ●活动图 ●初步的类图 注&#xff1a;为得到良好的安全性&#xff0c;登入管理员的时候&#xff0c;应该再输入管理员密码.所以在admin…

AI联想扩图解决方案,智能联想,无需人工干预

对于众多企业而言&#xff0c;无论是广告宣传、产品展示还是客户体验&#xff0c;高质量、宽广视野的图像都是不可或缺的。受限于车载摄像头等设备的物理限制&#xff0c;我们往往难以捕捉到完整、宽广的视觉场景。针对这一挑战&#xff0c;美摄科技凭借其前沿的AI联想扩图解决…

Vue3实战笔记(50)—Vue 3+ECharts还能看股票?附源码

文章目录 前言一、改进之前的封装echarts组件二、封装股票k线图总结 前言 今天封装股票k线图组件 前几天学的几个知识点都有用到&#xff0c;都是在封装k线图的时候遇到的问题&#xff0c;又啃了一遍基础。 一、改进之前的封装echarts组件 使用ref对象方式封装useEChartsRef.t…

git 学习随笔

git 学习随笔 基本概念 git 对待数据类似快照流的形式而不是类似 cvs 那样的纪录文件随时间逐步积累的差异 git 中所有数据在存储钱都会计算校验和&#xff08;hash) 三种状态&#xff1a;已提交(committed)&#xff0c;已修改(modified)&#xff0c;已暂存(staged)。 add…

计算机图形学入门03:二维变换

变换(Transformation)可分为模型(Model)变换和视图(Viewing)变换。在3D虚拟场景中相机的移动和旋转&#xff0c;角色人物动画都需要变换&#xff0c;用来描述物体运动。将三维世界投影变换到2D屏幕上成像出来&#xff0c;也需要变换。 1.缩放变换 缩放(Scale)变换&#xff1a; …

电脑提示:“找不到vcruntime140_1.dll无法执行”该怎么恢复?一键修复vcruntime140_1.dll丢失

vcruntime140_1.dll是一个关键的系统文件&#xff0c;它在电脑运行过程中被调用。如果该文件丢失或找不到&#xff0c;将会导致弹出"找不到vcruntime140_1.dll无法执行"的错误提示。缺失vcruntime140_1.dll文件将导致软件或游戏无法正常打开或运行。 一键修复vcrunti…

沃飞长空总部落地成都高新,为蓉低空经济发展助力!

5月25日&#xff0c;吉利科技集团与成都高新区签署合作协议&#xff0c;吉利科技集团旗下沃飞长空全球总部落地成都高新区。 根据协议&#xff0c;沃飞长空全球总部项目落地成都未来科技城&#xff0c;将布局总部办公、研发和生产制造低空出行航空器等业务。双方将积极发挥各自…

微信图片识别文字怎么弄?介绍三个识别方法

微信图片识别文字怎么弄&#xff1f;在信息爆炸的时代&#xff0c;我们每天都会接触到大量的图片信息&#xff0c;其中包含的文字内容往往是我们获取信息的重要途径。然而&#xff0c;手动输入图片中的文字既费时又费力&#xff0c;这时&#xff0c;一款能够准确识别微信图片中…

量化交易入门:如何在QMT中配置Python环境,安装第三方依赖包

哈喽,大家好,我是木头左! 引言 QMT,作为量化交易系统中的佼佼者,以其强大的功能和灵活的操作性,受到了广大投资者的青睐。但是,对于很多新手来说,如何在QMT中配置Python环境,安装第三方依赖包,却是一个让人头疼的问题。本文将从零开始,手把手教你如何在QMT中配置Py…

【NumPy】全面解析subtract函数:高效数组减法指南

&#x1f9d1; 博主简介&#xff1a;阿里巴巴嵌入式技术专家&#xff0c;深耕嵌入式人工智能领域&#xff0c;具备多年的嵌入式硬件产品研发管理经验。 &#x1f4d2; 博客介绍&#xff1a;分享嵌入式开发领域的相关知识、经验、思考和感悟&#xff0c;欢迎关注。提供嵌入式方向…

游戏联运平台如何助力游戏行业飞速发展?

随着科技的进步和互联网的普及&#xff0c;游戏行业正以前所未有的速度飞速发展。在这个过程中&#xff0c;游戏联运平台凭借其独特的优势和功能&#xff0c;成为了推动游戏行业腾飞的关键力量。本文将探讨游戏联运平台如何助力游戏行业实现飞速发展。 一、游戏联运平台的定义与…

idea工具配置隐藏文件及文件夹

目录 引言配置步骤实例 引言 我们在使用idea工具编写代码的时候&#xff0c;有些文件和文件夹我们至始至终都不会查看和修改它们&#xff0c;那它们显示在那里就没有任何意义&#xff0c;反而使得项目文件看起来杂乱&#xff0c;一点也不够清爽。这些对我们写代码没有任何作用…

深入了解多维数组索引:以二维数组为例

新书上架~&#x1f447;全国包邮奥~ python实用小工具开发教程http://pythontoolsteach.com/3 欢迎关注我&#x1f446;&#xff0c;收藏下次不迷路┗|&#xff40;O′|┛ 嗷~~ 目录 一、二维数组的基础概念与重要性 二、二维数组的索引访问 1. 索引访问的基本方法 2. 切片…

docker删除所有容器

笔记 要使用 Docker 删除所有容器&#xff08;无论是停止的还是正在运行的&#xff09;&#xff0c;可以按照以下步骤操作&#xff1a; 1. **删除所有正在运行的容器**&#xff1a; 首先&#xff0c;您需要停止所有正在运行的容器。可以使用以下命令&#xff1a; dock…

差分曼彻斯特编码详解

这是一种双向码&#xff0c;和曼彻斯特编码不同的是&#xff0c;这种码元中间的电平转换边只作为定时信号&#xff0c;不表示数据。数据的表示在于每一位开始处是否有电平转换&#xff1a;有电平转换则表示0&#xff0c;无则表示1。然后这就出现一个问题&#xff0c;很多小伙伴…

Pooling Sequencing

1、混合(Pooling)样本测序研究 https://www.jianshu.com/p/19ce438ccccf 1.1 混合测序基础 测序成本虽然下降了,但对于植物育种应用研究来说还是很高,动不动就上百群体,小小植物个体价值又低,测完了很可能后面就用不到了。这时,混合样本测序是一种省钱的好办法。 混池…

qemu使用简介

安装qemu git clone https://github.com/qemu/qemu.git mkdir build cd build ../configure make -j16 make install 编译内核 wget https://mirror.bjtu.edu.cn/kernel/linux/kernel/v5.x/linux-5.10.tar.xz tar -xf linux-5.10.tar.xzsudo apt-get install gcc-arm-linux-g…