自定义在input生成tag标签样式,标签可删除。组件封装

news2024/11/25 7:55:30

 生成效果如图:

<template>
  <div class="tag-input">
    <!-- 父盒子 -->
    <div class="father_box" @click="fatherOnclick" :class="verify?'':'notVerify'">
      <!-- 生成的标签 -->
      <div v-for="(item, index) in deepTagsAll" :key="index" class="has-created">
        <span class="tag-title">{{ item }}</span>
        <a-icon type="close" class="i-close"  @click="removeTag(index, item)"/>
      </div>
      <!-- 输入框 -->
      <input
        placeholder="输入后按<回车>创建"
        v-model="currentval"
        @keyup.enter="addTags"
        @keyup.delete="deleteTags"
        class="input-tag"
        ref="inputTag"
        type="text"
      />
    </div>
    <div v-show="!verify" class="verify-text">{{verifyText}}</div>
  </div>
</template>

<script>
export default {
  name: 'tagsInput',
  data () {
    return {
      // 输入框
      currentval: '',
      // 深拷贝tag
      // deepTagsAll: [],
      // 计算删除位置
      n: 0
    }
  },
  props: {
    // 标签tags
    tags: {
      type: Array,
      default: () => {
        return []
      }
    },
    // tag标签字符长度  默认99
    tagLength: {
      type: Number,
      default: 99
    },
    // 标签个数限制
    tagNumLimit: {
      type: Number,
      default: 99
    },
    // 是否直接去重  默认true自动去重,false不自动去重,页面提示
    repeat: {
      type: Boolean,
      default: true
    },
    // 标签正则校验
    tagReg: {
      type: String,
      default: ''
    },
    // 校验 form校验不通过 false时border为红色不通过  true:为默认色通过
    verify: {
      type: Boolean,
      default: true
    },
    // 校验不通过时文案提示
    verifyText: {
      type: String,
      default: '请输入'
    }
  },
  watch: {
    // 深度监听,避免父级组件接口返回数据过慢导致的页面组件数据不一致
    // tags: {
    //   handler (newValue) {
    //     console.log(newValue, 'newValue tags')
    //     this.deepTagsAll = newValue ? JSON.parse(JSON.stringify(newValue)) : JSON.parse(JSON.stringify([]))
    //   },
    //   deep: true // 深度监听
    // }
  },
  computed: {
    deepTagsAll: {
      get () {
        return this.tags
      },
      set (value) {
        // 在这里可以对 tags 值进行处理,例如去重、排序等
        this.$emit('update:tags', value)
      }
    }
  },
  mounted () {
    // this.deepTagsAll = JSON.parse(JSON.stringify(this.tags))
  },
  methods: {
    // 点击叉叉删除tag
    removeTag (index, item) {
      this.deepTagsAll.splice(index, 1)
    },
    // 回车增加tag
    addTags () {
      // 新增函数中可以加一些你所需要的校验规则。比如只能是数子,或者不能输入‘,’等
      if (!this.currentval.length) return
      // 限制标签个数
      if (this.deepTagsAll.length + 1 > this.tagNumLimit) {
        this.$message.warning('标签个数不能超过 ' + this.tagNumLimit + ' 个!')
        // 清空输入框
        this.currentval = ''
        return
      }
      // 限制输入长度
      if (this.currentval.length > this.tagLength) {
        this.$message.warning('单标签长度不能超过 ' + this.tagLength + ' 个字符!')
        return
      }
      // 根据父级参数实现页面是否自动去重
      // 标签自动去重
      if (this.repeat) {
        // 添加tag
        this.deepTagsAll.push(this.currentval)
        this.deepTagsAll = Array.from(new Set(this.deepTagsAll))
        // 清空输入框
        this.currentval = ''
      } else {
        // 标签不需要自动去重 仅页面提示
        if (this.deepTagsAll.indexOf(this.currentval) > -1) {
          // 与已有标签重复 页面提示
          this.$message.warning('标签已存在')
        } else {
          // 与已有标签不重复 --> 添加tag
          this.deepTagsAll.push(this.currentval)
          // 清空输入框
          this.currentval = ''
        }
      }
    },
    // 键盘删除键删除tag
    deleteTags () {
      // 逻辑:当删除到最后一个字符的时候,删除后currentval为空,所以继续执行,n++。这时候n=1.然后判断n是否等于2,不等于不执行。
      // 这里是保证当你删除最后一个字符的时候不会执行删除tag的方法,当我们删完了字符后再按一次删除的时候,n就等于2了。就开始删除tag。
      // 当有多个tag时,我们连续删除,就会出现,因为currentval为空,所以一直执行n++,导致n不等于2了,所以没法删除后面的tag。
      // 所以增加判断,当n大于2的时候我们看tag的长度有没有,有那就继续删除,没有就归0,从来。
      if (this.currentval === '') {
        this.n++
        if (this.n === 2) {
          this.deepTagsAll.pop()
        }
        if (this.n > 2) {
          if (this.deepTagsAll.length) {
            this.deepTagsAll.pop()
          } else {
            this.n = 0
          }
        }
      } else {
        this.n = 0
      }
    },
    // 点击父盒子输入框获取焦点
    fatherOnclick () {
      this.$nextTick(() => {
        this.$refs.inputTag.focus()
        this.$emit('update:verify', true)
      })
    },
    // 标签数据传递给父组件
    sendTagsParams () {
      this.$emit('getCustomTag', this.deepTagsAll)
    }
  }
}
</script>

<style scoped lang="less">
/* 外层div */
.father_box {
  width: 100%;
  box-sizing: border-box;
  background-color: white;
  border: 1px solid #d9d9d9;
  border-radius: 4px;
  font-size: 12px;
  text-align: left;
  padding-left: 5px;
  word-wrap: break-word;
  overflow: hidden;
  display: flex;
  flex-wrap: wrap;
}
.notVerify {
  border: 1px solid #f5222d;
}
.verify-text {
  color: #f5222d;
  font-size: 12px;
  transform: scale(0.9);
  margin-top: -10px;
  margin-left: -15px;
  height: 12px;
}
/* 已生成的标签 box */
.has-created {
  display: inline-block;
  font-size: 14px;
  margin: 3px 4px 3px 0;
  padding-right:3px;
  background-color: #ecf5ff;
  border: 1px solid #e8eaec;
  border-radius: 3px;
  //box-shadow: 0 2px 4px rgba(0, 0, 0, .12), 0 0 6px rgba(0, 0, 0, .04);
  line-height: 24px;
}
/* 标签文字 */
.tag-title {
  height: 24px;
  line-height: 22px;
  max-width: 99%;
  position: relative;
  display: inline-block;
  padding-left: 8px;
  color: #409EFF;
  font-size: 14px;
  opacity: 1;
  vertical-align: middle;
  overflow: hidden;
  transition: 0.25s linear;
}
/* tag的叉叉 */
.i-close {
  padding:2px;
  opacity: 1;
  -webkit-filter: none;
  filter: none;
  color: #409EFF;
  cursor:pointer;
  vertical-align: middle;
  font-size: 10px;
}
/* 鼠标经过叉叉 */
.i-close:hover{
  background-color: #409EFF;
  border-radius: 50%;
  color: #fff;
}
/* input */
.input-tag {
  font-size: 16px;
  border: none;
  box-shadow: none;
  outline: none;
  background-color: transparent;
  padding: 0;
  flex-grow: 1;
  vertical-align: top;
  height: 30px;
  color: #495060;
  line-height: 32px;
}
/* 输入框提示文字大小 */
input:placeholder-shown {
  font-size: 0.6rem;
}

</style>

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

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

相关文章

部署DB-GPT

踩坑 参考文献安装环境与模型运行安装conda环境下载git-lfs克隆源码配置.env文件加载SQLite的数据运行DB-GPT配置sqlite数据库数据库示例 pydantic版本问题bash报错 参考文献 https://zhuanlan.zhihu.com/p/629467580 https://blog.csdn.net/qq_40231723/article/details/1339…

Python异步网络编程利器——详解aiohttp的使用教程

一、引言 在现代Web应用程序开发中&#xff0c;网络请求是非常常见的操作。然而&#xff0c;传统的同步网络请求方式在处理大量请求时会导致性能瓶颈。为了解决这个问题&#xff0c;Python提供了aiohttp库&#xff0c;它是一个基于异步IO的网络请求库&#xff0c;可以实现高效…

CCF ChinaSoft 2023 论坛巡礼 | 测试预期问题与蜕变测试研究进展论坛

2023年CCF中国软件大会&#xff08;CCF ChinaSoft 2023&#xff09;由CCF主办&#xff0c;CCF系统软件专委会、形式化方法专委会、软件工程专委会以及复旦大学联合承办&#xff0c;将于2023年12月1-3日在上海国际会议中心举行。 本次大会主题是“智能化软件创新推动数字经济与社…

win10-mmgen安装/cyclegan运行问题记录

mmconda环境&#xff1a; conda&#xff1a; CUDA 11.3 conda install pytorch1.11.0 torchvision0.12.0 torchaudio0.11.0 cudatoolkit11.3 -c pytorch pip install mmcv-full1.5.0 -f https://download.openmmlab.com/mmcv/dist/cu113/torch1.11.0/index.html 成功运行 c…

golang 发起 http 请求,获取访问域名的 ip 地址(net, httptrace)

前言 今天碰到了个需求&#xff0c;我要知道程序对外访问的 http 请求域名的 ip 地址。 直接查看 golang 的 net/http 包&#xff0c;发现 Response 中并没有我想要的 ip 信息。 考虑到在 OSI 七层模型中&#xff0c;ip 是网络层协议&#xff0c;而 http 是应用层协议。去翻…

面试算法50:向下的路径节点值之和

题目 给定一棵二叉树和一个值sum&#xff0c;求二叉树中节点值之和等于sum的路径的数目。路径的定义为二叉树中顺着指向子节点的指针向下移动所经过的节点&#xff0c;但不一定从根节点开始&#xff0c;也不一定到叶节点结束。例如&#xff0c;在如图8.5所示中的二叉树中有两条…

喜讯!INFINI Easysearch 在墨天轮数据库排名中挺进前30!

近日&#xff0c;2023 年 10 月的 墨天轮中国数据库流行度排行 火热出炉&#xff0c;本月共有 283 个数据库参与排名&#xff0c;中国数据库行业竞争日益激烈。其中&#xff0c;极限科技旗下软件产品 INFINI Easysearch 稳步推进&#xff0c;在国内整个数据库排行中进入了前 30…

海康威视iVMS综合安防系统文件上传漏洞复现

简介 海康威视iVMS集中监控应用管理平台&#xff0c;是以安全防范业务应用为导向&#xff0c;以视频图像应用为基础手段&#xff0c;综合视频监控、联网报警、智能分析、运维管理等多种安全防范应用系统&#xff0c;构建的多业务应用综合管理平台。 漏洞描述 海康威视iVMS系统…

Qt 插件开发详解

1.简介 Qt插件是一种扩展机制&#xff0c;用于将应用程序的功能模块化&#xff0c;并且可以在运行时动态加载和卸载。Qt框架为插件提供了一套标准的接口和管理机制&#xff0c;使得插件的使用和集成变得简单和灵活&#xff0c;通过插件机制&#xff0c;可以将应用程序的功能划…

QT5.15.2搭建Android编译环境及使用模拟器调试(全)

一、安装QT5.15.2 地址&#xff1a;下载 我电脑的windows的&#xff0c;所以选windows 由于官方安装过程非常非常慢&#xff0c;一定要跟着步骤来安装&#xff0c;不然慢到怀疑人生 1&#xff09;打开"命令提示符"&#xff08;开始 -> Windows 系统 -> 命令…

安防监控系统EasyCVR视频汇聚平台,如何实现视频汇聚?

关注我们的朋友都知道&#xff0c;EasyCVR平台最初就是以汇聚为核心而进行打造的&#xff0c;那到底什么是汇聚平台呢&#xff1f;又如何进行视频资源汇聚&#xff1f;简单来说&#xff0c;视频汇聚平台是指能够从不同的视频源&#xff08;例如直播、点播等&#xff09;收集、整…

如何使用Ruby 多线程爬取数据

现在比较主流的爬虫应该是用python&#xff0c;之前也写了很多关于python的文章。今天在这里我们主要说说ruby。我觉得ruby也是ok的&#xff0c;我试试看写了一个爬虫的小程序&#xff0c;并作出相应的解析。 Ruby中实现网页抓取&#xff0c;一般用的是mechanize&#xff0c;使…

【JMeter】插件管理工具

1. 官方下载地址 Documentation :: JMeter-Plugins.org 2.安装 将该插件的jar包移动到lib/ext下 3.重启JMeter就可以看到插件管理器 4. 安装&#xff0c;更新&#xff0c;删除插件 安装插件 删除插件 更新插件

Windows10电脑上的此电脑图标在哪里找到?

Windows10电脑上的此电脑图标在哪里找到&#xff1f; 1、在Windows10电脑桌面上鼠标右键&#xff0c;找到个性化点击打开&#xff1b; 2、打开个性化桌面设置后&#xff0c;找到主题并点击进入&#xff1b; 3、在主题相关的设置中找到桌面图标设置&#xff0c;并点击打开&…

【python基础】魔法参数*args, **kwargs的使用

文章目录 前言一、*args 和 **kwargs 是什么&#xff1f;二、*args 的用法打包参数&#xff1a;将不定数量的参数传递给一个函数拆分参数&#xff1a;调用一个函数 三、**kwargs 的用法打包参数&#xff1a;将不定数量的参数传递给一个函数拆分参数&#xff1a;调用一个函数 四…

【算法专题】双指针—快乐数

一、题目解析 由题目我们可以分析出无非就两种情况&#xff1a; 这个数一直变化最终能变到1这个数一直变化最终是无限循环 其实这两种情况我们也可以抽象成是一种情况&#xff0c;因为第一种情况虽然变到了1但是1再继续变下去也是形成一个环&#xff0c;只不过这个环的数都是…

GROMACS Tutorial - TMD with NeqPCA

Contents IntroductionSystem BuildingGenerate Topologyfrom Solvation to Equilibration Create trajectoriesPCA for TMD Introduction 首先简单介绍一下TMD模拟&#xff0c;类似于SMD模拟&#xff08;可以参考这篇教程&#xff09;&#xff0c;TMD 通过pull_coord1_type …

2.Docker基本架构简介与安装实战

1.认识Docker的基本架构 下面这张图是docker官网上的&#xff0c;介绍了整个Docker的基础架构&#xff0c;我们根据这张图来学习一下docker的涉及到的一些相关概念。 1.1 Docker的架构组成 Docker架构是由Client(客户端)、Docker Host(服务端)、Registry(远程仓库)组成。 …

树型表查询的两种方式(inner join 和 mysql递归查询)

方法一: 使用inner join来查询 SELECTone.id one_id,one.label one_label,two.id two_id,two.label two_label FROMcourse_category oneINNER JOIN course_category two ON two.parentid one.id WHEREone.parentid 1 AND one.is_show 1 AND two.is_show 1查询结果 方法…

IDEA远程调试代码

IDEA->RUN->Edit Configurations 端口随便选一个&#xff0c;选择调试模块&#xff0c;然后用IDEA生成的命令调试 java -agentlib:jdwptransportdt_socket,servery,suspendn,address*:8081 -jar backend-1.18.11.jar &