解决elementUI Select multiple 抖动问题,复制并重写elementUI中Select源码函数,全局配置Select的filterable

341 阅读2分钟

解决elementUI Select multiple 抖动问题,复制并重写elementUI中Select源码函数,全局配置Select的filterable属性

问题

  • 问题: 项目中出现 el-select 设置了 multiple ,多选tag后,在将页面放大或缩小时,el-selet中的el-input的高度一直在抖动, 在这里插入图片描述

bug定位

  • 定位: 在elment源码中,在 node_modules/element-ui/packages/select/src/select.vue 文件下的第644行存在一个 resetInputHeight 函数,该函数被我重写后打印发现上图的 tags.clientHeight 的获取每次获取都不一致,在85和84之间跳动,导致页面抖动

解决

  • 解决: 复制并修改 element-ui 中 select 的 resetInputHeight 函数,利用 getBoundingClientRect() 函数,获取指定 dom 的具体高度,然后直接添加到 heitht (浏览器会自动将height识别为一个整数)
    • 添加 elementUi.js 文件,在 main.js 文件中引入 element-ui 之后 使用 Vue.use(elementUi) 的方法实现重写
    • 顺路配置了全局 select 的 filterable 属性
import ElementUI from 'element-ui'

let elementUiComponent = {}
elementUiComponent.install = function (Vue) {
  // const seletRender = ElementUI.Select.render
  // ElementUI.Select.render = function () {
    // 重写select渲染方法,看情况使用-添加渲染时操作
    // return seletRender.apply(this, arguments)
  // }

  // 全局统一添加 filterable 默认传参,可被组件使用时的 filterable 属性覆盖
  ElementUI.Select.props.filterable = { type: Boolean, default: true }

  // 全局select直接修改
  // TODO:如果el-select 多选还会导致页面抖动,则使用这个方法重写,并删除 .el-select .el-tag--mini 自定义样式配置和 --el-tag-height css变量配置
  ElementUI.Select.methods.resetInputHeight = function () {
    // 重写tag高度判定
    if (this.collapseTags && !this.filterable) return
    this.$nextTick(() => {
      if (!this.$refs.reference) return
      let inputChildNodes = this.$refs.reference.$el.childNodes
      let input = [].filter.call(inputChildNodes, (item) => item.tagName === 'INPUT')[0]
      const tags = this.$refs.tags
      // element 使用 clientHeight 计算高度,但是在某些情况下,会出现高度不一致的情况,所以这里使用 getBoundingClientRect 计算高度
      const tagsRect = tags ? tags.getBoundingClientRect() : null
      const sizeInMap = this.initialInputHeight || 40
      input.style.height =
        this.selected.length === 0
          ? sizeInMap + 'px'
          : // 备份element-ui的原代码
            // Math.max(tags ? tags.clientHeight + (tags.clientHeight > sizeInMap ? 6 : 0) : 0, sizeInMap) + 'px'
            Math.max(tags ? tagsRect.height + (tagsRect.height > sizeInMap ? 6 : 0) : 0, sizeInMap) + 'px'

      // console.log('el-input__inner height -->', input.style.height, 'tags.clientHeight -->', tags.clientHeight)
      if (this.visible && this.emptyText !== false) {
        this.broadcast('ElSelectDropdown', 'updatePopper')
      }
    })
  }
}

export default elementUiComponent
  • main.js 中文件使用
// main.js
...
import ElementUI from 'element-ui'
import 'element-ui/lib/theme-chalk/index.css'
...
import elementUiComponent from '@/plugins/elementUi.js'
Vue.use(elementUiComponent)

后话

也可以看看另一个大佬的文章提到修改tag高度和tag的margin方法,如果可以的话也不用我这样麻烦(我没成功,测试太严谨了,各种比列看抖动) 文章:解决elementUI multiple Select 抖动问题