Element ui multi-select drop-down component (el-select) has too many tags to deal with the solution (secondary packaging)

Problem Description:

如下图所示,当标签选择过多时,会占用过多空间
insert image description here
期待效果:超过n行就自动省略,并可以进行展开收起,下图是实现后的效果图
insert image description here
insert image description here

Realize analysis:

  1. Inherit the el-select component through extends
  2. Paste the template part of the select source code into the encapsulated component, so as to operate the part that needs to operate the dom, such as expanding and collapsing
  3. Monitor the changes of selected (selected item) to judge various states
  4. Define the maximum number of lines maxLine in props, so that users can customize the maximum number of lines when using

template part

整个template为el-select源码粘过来的,此处仅列出修改部分

If the following areas are located, you only need to select the source code select.vue file, search
<transition-group @after-leave="resetInputHeight" v-if="!collapseTags">, and you can locate the modified area

//向第一行最外层加入了class:el-select-new
  <div class="el-select el-select-new"></div>
	.
	.
	.
      <transition-group @after-leave="resetInputHeight" v-if="!collapseTags">
        <template>
          <el-tag
            v-for="item in showTags"//标签要根据一定的条件进行展示showTags放在了computed中
            :key="getValueKey(item)"
            :closable="!selectDisabled"
            :size="collapseTagSize"
            :hit="item.hitState"
            type="info"
            @close="deleteTag($event, item)"
            disable-transitions>
            <span class="el-select__tags-text">{
    
    {
    
     item.currentLabel }}</span>
          </el-tag>
        </template>
      </transition-group>
     //所有tag应该占的总行数大于最大行数时
      <span  v-if="lineCount > maxLine" class="text-primary expand">
        <span v-if="!expand">...</span>
        <span class="expand-button" @click.stop="expandChange">{
    
    {
    
    lineCount > maxLine && !expand? '展开' :'收起'}}</span>
      </span>  

js part

export default {
    
    
  extends: Select,
  props:{
    
    
    maxLine:{
    
    //超过最大行数进行省略
      type:Number,
      default:3
    }
  },
  computed:{
    
    
    showTags(){
    
    //多选框标签得展示
      return this.lineCount > this.maxLine && !this.expand ? this.selected.slice(0,this.maxLineIndex-1) : this.selected
    }
  },
  data(){
    
    
    return {
    
    
      lineCount:1,//所有tag应该占的行数
      //最大显示行(maxLine)内的最后一个元素的位置,需要通过maxLine和当前元素会占多少位置计算得来
      maxLineIndex:0,
      expand:false,//默认收起
    }
  },
  watch:{
    
    
	//监听选项得变化,经分析得出,选项内得$el为弹窗框得dom
    selected(newVal,oldVal){
    
    
      if(this.collapseTags){
    
    return}//若是标签进行api中所说的多标签汇总到一个标签进行省略,则不需要如下判断
      if(
        // 增加标签,没有出现收起的情况
        (newVal.length>oldVal.length && this.lineCount <= this.maxLine) ||
        //减少标签且出现收起的情况
        (newVal.length < oldVal.length  && this.lineCount > this.maxLine) 
      ){
    
    
        setTimeout(()=>{
    
    
/*
  整体思路是
  监听下拉框选择内容,当内容变化时,根据内容计算文本出选中时tag所要占据的空间,
  根据tag所占用空间、tag个数,容器单行总宽度等信息,
  计算出第多少个元素会超出最大行数、若是标签全选中不省略占据的总行数等信息,以下是具体实现步骤
*/
          const dom=document.querySelector('.el-select-new .el-select__tags>span')
          const allTagWidth=newVal.map(item=>this.tagWidth(dom,item.label))
          const containerWidth=document.querySelector('.el-select-new .el-select__tags').clientWidth
          let lineCount = 1//占据行数
          let nowWidth=0//当前行容纳的tag占据的宽度
          allTagWidth.forEach((width,index)=>{
    
    
            if(nowWidth + width>=containerWidth){
    
    //超出单行可容纳宽度
              lineCount += 1
              nowWidth = width//超出宽度后,把当前宽度放到下一行计算
              if(lineCount  === this.maxLine +1 ){
    
    
                this.maxLineIndex = index
              }
            }else{
    
    
              nowWidth = nowWidth + width
            }
          })
          this.lineCount = lineCount//得出所有标签占据的最大行数
        },100)
      }
    },
    //监听展示的标签,每当展示标签变化时,调用组件内容已有的方法重新计算input的高度来重绘
    showTags(){
    
    
      this.resetInputHeight()
    },
  },
  methods:{
    
    
  //点击展开收起
    expandChange(){
    
    
      this.expand=!this.expand
    },
    //根据dom获取每个tag所占用的宽度,包括margin
    getTagSpace(dom){
    
    
      const marginLeft=Number(getComputedStyle(dom).marginLeft.replace('px',''))
      const marginRight=Number(getComputedStyle(dom).marginRight.replace('px',''))
      const offsetWidth=dom.offsetWidth
      return marginLeft + marginRight + offsetWidth
    },
    //fatherDom为父容器,text为内容,此方法是计算text所生成的tag在fatherDom中所占据宽度
    tagWidth(fatherDom,text){
    
    
      const spanOut = document.createElement('span')
      const spanInner =document.createElement('span')
      const i =document.createElement('i')
      spanOut.setAttribute('class','el-tag el-tag--info el-tag--mini el-tag--light')
      spanInner.setAttribute('class','el-select__tags-text')
      i.setAttribute('class','el-tag__close el-icon-close zzzz')
      spanInner.innerText=text
      spanOut.appendChild(spanInner)
      spanOut.appendChild(i)
      fatherDom.appendChild(spanOut)
      const width = this.getTagSpace(spanOut)
      fatherDom.removeChild(spanOut)
      return width
    }
  },
}

Component usage:

collapse-tags:false && multiple :true
Pass in maxLine to customize the number of omitted lines, the default is three lines

喜欢的话记得点赞、关注、收藏多多支持,有问题的话可以评论或私聊,会及时进行反馈!

Guess you like

Origin blog.csdn.net/weixin_43695002/article/details/130733761