el-select的二次封装,用于解决tag超出时的省略

177 阅读2分钟

该组件用于解决el-select的tag展示,将两者结合,当多选超出宽度时使用+1的方式展示,在原作者的基础上做了修改

原作者

图片.png

功能实现如下

图片.png

子组件

<template>

  <!-- el-select组件的二次封装,用于处理标签超出时省略展示 -->

  <el-select

    v-model="values"

    multiple

    style="width: 100%"

    placeholder="请选择"

    @change="handleChange"

  >

    <el-option

      v-for="item in options"

      :key="item.value"

      :label="item.label"

      :value="item.value"

    >

    </el-option>

  </el-select>

</template>

  


<script>

var observer = null

export default {

  props: {

    options: {

      type: Array,

      default: () => []

    },

    value: {

      type: Array,

      default: () => []

    }

  },

  data() {

    return {}

  },

  mounted() {

    let tagLIstDom = document.querySelector('.el-select__tags')

    //   需要加上组件自定义的类名,防止监听失效

    let tagSpanDom = document.querySelector(

      '.select-tags .el-select__tags > span'

    )

    let hideDom = document.createElement('span')

    hideDom.classList = ['count-node'] //设置样式

    tagSpanDom.append(hideDom) //插入到span中

    var config = { childList: true }

  


    // 当观察到突变时执行的回调函数

    var callback = function (mutationsList) {

      mutationsList.forEach(function (item, index) {

        if (item.type == 'childList') {

          let tagList = item.target.childNodes

          let tagWidth = 0 //标签总宽度

          let tagNum = 0 //标签多余个数

          let avaliableTagWidth = 0 //显示标签的总宽度

          for (let i = 0; i < tagList.length; i++) {

            const e = tagList[i]

            if (tagWidth > tagLIstDom.offsetWidth) {

              e.style.display = 'none' //隐藏多余标签

            } else {

              e.style.display = 'inline-block' //显示标签

            }

            tagWidth += e.offsetWidth + 5

            if (tagWidth > tagLIstDom.offsetWidth) {

              e.style.display = 'none' //隐藏多余标签

            } else {

              e.style.display = 'inline-block' //显示标签

            }

            if (e.style.display != 'none') {

              tagNum++

              hideDom.style.display = 'none' //隐藏多余标签个数

              const margin = tagNum === 1 ? 0 : 7

              avaliableTagWidth += e.offsetWidth + margin

            } else {

              hideDom.style.display = 'inline-block' //显示多余标签个数

              hideDom.style.left = `${avaliableTagWidth}px` //数字标签的位置设置

              hideDom.innerHTML = `+${tagList.length - tagNum}` //显示多余标签个数

            }

          }

        }

      })

    }

  


    // 创建一个链接到回调函数的观察者实例

    observer = new MutationObserver(callback)

  


    // 开始观察已配置突变的目标节点

    observer.observe(tagSpanDom, config)
  


    // 随后,您还可以停止观察

    // observer.disconnect();

  },

  methods: {

    handleChange(val) {
    //原作者此处直接使用this.value,会出现bug,点击第一次是this.value还未绑定,故第二次点击才会记录第一次的值

      this.value = val//修改

      this.$emit('change', this.value)

    }

  },

  computed: {

    values: {

      get() {

        return this.value

      },

      set(val) {

        this.$emit('input', val)

      }

    }

  },

  //销毁时

  beforeDestroy() {

    // 停止观察

    observer.disconnect()

  }

}

</script>

<style>

.count-node {

  position: absolute;

  top: 2px;

  display: none;

  height: 20px;

  padding: 0 6px;

  line-height: 20px;

  margin-left: 0px;

  background-color: #f4f4f5;

  border: 1px solid #e9e9eb;

  border-radius: 4px;

  color: #909399;

  font-size: 12px;

  box-sizing: border-box;

}

</style>


父组件

设置的class类名‘select-tags’用于保证获取组件需要监听的元素的唯一性

<leSelect
 @change="oneSandChange"
style="width: 300px"
v-model="oneSandId"
:options="oneSandNumberList"
class="select-tags"
></leSelect>