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

 生成效果如图:

<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>

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值