input space carriage return input label

analyze

We need to pay attention to the following points when encapsulating the input input tag by ourselves:

  1. Style realization, span realizes label effect, input hides border (Element-UI can directly use tag).
  2. Event monitoring, to determine the operation of generating labels, which can be carriage return, and needs to monitor the situation of leaving the focus.
  3. Tag limit, up to several, and input validation
  • html:
    <template>
          <!-- 外层div -->
          <div ref="arrbox" :style="{width:`${width}px`,'min-height':`${height}px`}" class="arrbox" @click="onclick">
            <!-- 标签 -->
            <el-tag v-for="(item,index) in tagsArr" :key="index" type="info" closable @close.stop="removeTag(index)"><span :ref="`span_${index}`" :show="getTitle(index,item)" class="tagSPan"><span :ref="`spanRef_${index}`" @dblclick="selectDiv">{
         
         { item }}</span></span></el-tag>
            <!-- 标签 自定义的标签样式 -->
            <!-- <div v-for="(item,index) in tagsArr" :key="index" class="spantab">
              <span class="tagtext" :ref="`span_${index}`"  :show="getTitle(index,item)" ><span :ref="`spanRef_${index}`" @dblclick="selectDiv">{
          
          { item }}</span></span>
              <i class="tagclose" @click.stop="removeTag(index)" />
            </div> -->
            <!-- 输入框 -->
            <input
              ref="inputTag"
              v-model="currentval"
              :placeholder="tagsArr.length==0?placeholder:''"
              class="inputTag"
              type="text"
              @keyup="keyupFn"
              @blur="addTags('bulr')"
            >
          </div>
        </template>
    
  • js:
  1. First of all, we need to focus the input when clicking on the outermost div
  2. In the css style, we put the input and those tags in one line using flex layout, and add the newline attribute, and set the input minimum width and flex: 1, so that the input can always be behind the tag, and the width is smaller than the defined minimum Wrap automatically when width
  3. Need to monitor space and carriage return, and out of focus, put the input value into the tag array, and then clear the tag.
  4. Add some restrictions when adding tags, so that users can operate better
    export default {
          
          
          name: 'inputTags',
          model: {
          
          
            prop: 'parentArr',
            event: 'change-parentArr'
          },
          props: {
          
          
            width: {
          
          
              type: Number,
              default: 300
            },
            height: {
          
          
              type: Number,
              default: 40
            },
            parentArr: {
          
          
              type: Array,
              default() {
          
          
                return []
              }
            },
            limit: {
          
           // 最多生成标签数
              type: Number,
              default: -1
            },
            placeholder: {
          
          
              type: String,
              default: '请输入'
            },
            reg: {
          
          
              type: String,
              default: ''
            }
          },
          data() {
          
          
            return {
          
          
              currentval: '',
              tagsArr: [],
              inputLength: ''
            }
          },
          watch: {
          
          
            tagsArr(value) {
          
          
              this.$emit('change-parentArr', value)
            },
            parentArr: {
          
          
              handler(value) {
          
          
                this.tagsArr = value
              },
              deep: true,
              immediate: true
            },
            currentval(val) {
          
          
      // 获取最后三个字符,如果是逗号或者分号就分割,主要是为了使用者复制整段话
    	      const lastValue = val.substr(-3)
    	      //   输入逗号,生成标签
    	      if (lastValue.indexOf(',') > -1 || lastValue.indexOf(',') > -1 || lastValue.indexOf(';') > -1 || lastValue.indexOf(';') > -1) {
          
          
    	        this.currentval = this.currentval.split(',')[0]
    	        this.currentval = this.currentval.split(',')[0]
    	        this.currentval = this.currentval.split(';')[0]
    	        this.currentval = this.currentval.split(';')[0]
    	        this.addTags()
    	      }
    	    }
          },
          mounted() {
          
          
          },
          methods: {
          
          
           getTitle(index, title) {
          
          
              this.$nextTick(() => {
          
          
                const spanDom = this.$refs[`span_${
            
            index}`][0]
                const textDom = this.$refs[`spanRef_${
            
            index}`][0]
                if (textDom.offsetWidth > spanDom.offsetWidth) {
          
          
                  spanDom.setAttribute('title', title)
                }
              })
            },
             // 双击选中
    	    selectDiv (e){
          
          
    	      var range;
    	      var element=e.currentTarget
    	      if (document.body.createTextRange) {
          
          
    	        range = document.body.createTextRange()
    	        range.moveToElementText(element)
    	        range.select()
    	      } else if (window.getSelection) {
          
          
    	        var selection = window.getSelection()
    	        range = document.createRange()
    	        range.selectNodeContents(element)
    	        selection.removeAllRanges()
    	        selection.addRange(range)
    	        /* if(selection.setBaseAndExtent){
    	              selection.setBaseAndExtent(text, 0, text, 1);
    	          }*/
    	      } else {
          
          
    	        console.log('none')
    	      }
    	    },
            removeTag(index) {
          
          
              this.tagsArr.splice(index, 1)
            },
            // 监听按键,空格或者Enter
            keyupFn(e) {
          
          
            //   if (e.code == 'Space' || e.keyCode == 32) {
          
          
            //     this.currentval = this.currentval.slice(0, -1)
            //     this.addTags()
            //   }
              if (e.key == 'Enter' || e.keyCode == 13) {
          
          
                this.addTags()
              }
            },
            addTags(type = 'click') {
          
          
              if (this.limit != -1 && this.tagsArr.length >= this.limit) {
          
          
                this.$message.warning(`只能输入${
            
            this.limit}`)
                return
              }
              if (this.tagsArr.indexOf(this.currentval) > -1) {
          
          
                if (type == 'click') {
          
          
                  this.$message.warning(`已经输入了【${
            
            this.currentval}`)
                } else {
          
          
                  this.currentval = ''
                }
    
                return
              }
              // 格式校验
              if (this.reg != '') {
          
          
                if (!this.reg.test(this.currentval)) {
          
          
                  this.$message.warning('格式不正确!')
                  this.currentval = ''
                  return
                }
              }
              this.tagsArr.push(this.currentval)
              this.tagsArr = this.tagsArr.filter(n => n != '')
              this.currentval = ''
            },
            onclick() {
          
          
              this.$nextTick(() => {
          
          
                this.$refs.inputTag.focus()
              })
            }
          }
        }
    
  • css:
     /* 外层div */
        input::-webkit-input-placeholder {
          
          
            /* placeholder颜色  */
            color: #c1c7cf;
            /* placeholder字体大小  */
            font-size: 14px;
        }
        .arrbox {
          
          
            box-sizing:border-box;
            background-color: white;
            border: 1px solid #dcdee2;
            border-radius: 4px;
            font-size: 12px;
            text-align: left;
            word-wrap: break-word;
            overflow: hidden;
            display: inline-flex;
            flex-wrap: wrap;
            align-items: center;
        }
        /* input */
        .inputTag {
          
          
            font-size: 12px;
            border: none;
            box-shadow: none;
            outline: none;
            background-color: transparent;
            min-width: 40%;
            color: #495060;
            flex: 1;
            height: 30px;
            margin-left: 15px;
            padding-left: 0;
        }
        .el-tag{
          
          
            height: 25px;
            line-height: 25px;
            margin: 3px 3px;
            max-width: calc(100% - 5px) !important;
    
        }
        .tagSPan{
          
          
            display: inline-block;
            max-width: calc(100% - 10px) !important;
            text-overflow: ellipsis;
            overflow: hidden;
            white-space: nowrap;
        }
        ::v-deep .el-tag__close {
          
          
            background-color: #C0C4CC;
            top:-10px;
            transform: scale(.8);
            &::before{
          
          
                transform: translate(0,0.5px);
            }
        }
    
        /* 自定义的标签 */
        .spantab {
          
          
            display: inline-block;
            font-size: 14px;
            margin: 3px;
            height: 20px;
            background-color: #f7f7f7;
            border: 1px solid #e8eaec;
            border-radius: 3px;
            max-width: calc(100% - 5px);
            position: relative;
            padding-right: 20px;
          }
    
          .tagtext {
          
          
            height: 20px;
            line-height: 20px;
            max-width: 100%;
            position: relative;
            display: inline-block;
            padding-left: 8px;
            color: #495060;
            font-size: 12px;
            cursor: pointer;
            opacity: 1;
            vertical-align: top;
            overflow: hidden;
            transition: 0.25s linear;
            max-width: 100% !important;
            text-overflow: ellipsis;
            overflow: hidden;
            white-space: nowrap;
          }
    
          .tagclose {
          
          
            opacity: 1;
            -webkit-filter: none;
            filter: none;
            position: absolute;
            top: 0;
            right: 0;
          }
    
          .tagclose:after {
          
          
            content: "x";
            -webkit-font-smoothing: antialiased;
            -moz-osx-font-smoothing: grayscale;
            line-height: 14px;
            vertical-align: top;
            text-align: center;
            margin: 2px 2px 2px 5px;
            cursor: pointer;
            width: 14px;
            height: 14px;
            display: inline-block;
            background-color: #C0C4CC;
            border-radius: 50%;
          }
    
    
  • use:
    <template>
            <tagInput v-model="from.tag" :width="302" placeholder="请输入标签" />
    </template>
    <script>
    import tagInput from ./tagInput'
    export default {
            
            
      components: {
            
            
        tagInput
      },
      data(){
            
            
            return{
            
            
                    from:{
            
            
                            tag:[]
                    }
            }
      }
    }
    </script>
    

insert image description here

Guess you like

Origin blog.csdn.net/qq_40591925/article/details/127990604