美文网首页
优化elementui框架Select组件远程搜索不支持上拉加载

优化elementui框架Select组件远程搜索不支持上拉加载

作者: 前端蜗牛老师 | 来源:发表于2020-02-18 18:38 被阅读0次

    一,封装组件背景

    elementui框架Select组件远程搜索不支持上拉加载功能, 本教程用vue 自定义指令(directive)结合element Select远程搜索mixin混合模式,封装select选择器上拉夹杂支持远程搜索功能组件

    image.png

    二,首先要封装一个自定义组件

    image.png

    loadMore.js 文件里的代码如下

    import { addClass } from '../../utils'
    
    export default {
      bind(el, binding) {
        // 获取element-ui定义好的scroll盒子
        const SELECTWRAP_DOM = el.querySelector('.el-select-dropdown .el-select-dropdown__wrap')
        const loadingDom = document.createElement('div')
        loadingDom.style.width = '100%'
        loadingDom.style.height = '50px'
        loadingDom.style.lineHeight = '30px'
        loadingDom.style.backgroundColor = '#fff'
        loadingDom.style.color = '#606266'
        loadingDom.style.textAlign = 'center'
        loadingDom.innerHTML = '加载中...'
    
        SELECTWRAP_DOM.addEventListener('scroll', function() {
          /*
           * scrollHeight 获取元素内容高度(只读)
           * scrollTop 获取或者设置元素的偏移值,常用于, 计算滚动条的位置, 当一个元素的容器没有产生垂直方向的滚动条, 那它的scrollTop的值默认为0.
           * clientHeight 读取元素的可见高度(只读)
           * 如果元素滚动到底, 下面等式返回true, 没有则返回false:
           * ele.scrollHeight - ele.scrollTop === ele.clientHeight;
           */
          const CONDITION = this.scrollHeight - this.scrollTop <= this.clientHeight
          if (CONDITION) {
            SELECTWRAP_DOM.append(loadingDom)
            binding.value()
          }
        })
      }
    }
    

    (本案例不讲解自定义组件的知识,请自行学习或者加入我们的qq群或者关注公众号 程序员蜗牛,回复你的问题)
    文件结构是
    ---src--
    -------directive--
    ------------------index.js(directive入口文件,解释如下)
    ------------------loadMore--
    ------------------------------index.js和loadMore.js

    index.js 里面代码

    import loadMore from '@/directive/load-more/index'
    Vue.directive('loadMore', loadMore)
    

    main.js里面代码

    import '@/directive/index'
    

    自此自定义指令就可以引用了
    在需要使用自定义指令的地方 v-load-more=loadMore(接收函数)


    image.png image.png

    结果:


    屏幕录制-2020-02-18-下午1.42.15.gif

    这样做不太完美,接下来就是高度封装代码
    在 loadMore.js

    import { addClass, removeClass } from '../../utils'
    
    export default {
      bind(el, binding, vNode) {
        // 获取element-ui定义好的scroll盒子
        const SELECTWRAP_DOM = el.querySelector('.el-select-dropdown .el-select-dropdown__wrap')
        const loadingDom = document.createElement('div')
        loadingDom.style.width = '100%'
        loadingDom.style.height = '50px'
        loadingDom.style.lineHeight = '30px'
        loadingDom.style.backgroundColor = '#fff'
        loadingDom.style.color = '#606266'
        loadingDom.style.textAlign = 'center'
        loadingDom.style.fontSize = '14px'
        loadingDom.className = 'loadingBox'
        const loadingIcon = document.createElement('i')
        loadingDom.append(loadingIcon)
        SELECTWRAP_DOM.append(loadingDom)
        const i = el.getElementsByClassName('loadingBox')[0].getElementsByTagName('i')[0]
        SELECTWRAP_DOM.addEventListener('scroll', function() {
          /*
           * scrollHeight 获取元素内容高度(只读)
           * scrollTop 获取或者设置元素的偏移值,常用于, 计算滚动条的位置, 当一个元素的容器没有产生垂直方向的滚动条, 那它的scrollTop的值默认为0.
           * clientHeight 读取元素的可见高度(只读)
           * 如果元素滚动到底, 下面等式返回true, 没有则返回false:
           * ele.scrollHeight - ele.scrollTop === ele.clientHeight;
           */
          const CONDITION = this.scrollHeight - this.scrollTop <= this.clientHeight
          if (CONDITION) {
            addClass(i, 'el-icon-loading')
            binding.value()
          } else {
            removeClass(i, 'el-icon-loading')
          }
        })
      }
    }
    

    然后在自定义组件里新建hospitalForm.vue

    <template>
      <el-form-item label="医院名称:" prop="hospitalNo">
        <el-select
          v-model="ruleForm.hospitalNo"
          v-load-more="loadMore"
          filterable
          placeholder="请选择"
          remote
          :remote-method="remoteMethod"
          value=""
          clearable
          :loading="loading"
          popper-class="option-box"
          :style="styles"
          @change="handleChange"
        >
          <el-option
            v-for="(item, index) in hospitalNoOptions"
            :key="index"
            :label="item.hospitalName"
            :value="item.hospitalNo"
          />
        </el-select>
      </el-form-item>
    </template>
    
    <script>
    import { searchHospital } from '../../api/user'
    import { S_OK } from '../../utils/constant'
    
    export default {
      name: 'HospitalForm',
      props: {
        hospitalNo: {
          type: String,
          default: ''
        },
        styles: {
          type: String,
          default: ''
        }
      },
      data() {
        return {
          ruleForm: {
            hospitalNo: ''
          },
          hospitalNoOptions: [],
          loading: false,
          pageNo: 0,
          searchKey: {
            'hospitalNo': '',
            'hospitalName': '',
            'pageNo': 1
          },
          hospitalTotalCount: 0
        }
      },
      mounted() {
        this.searchHospitalFun()
      },
      methods: {
        // 初始化数据,并上啦加载时
        searchHospitalFun() {
          searchHospital(this.searchKey).then(res => {
            if (res.resultCode === S_OK) {
              this.hospitalNoOptions = this.hospitalNoOptions.concat(res.resultObj.list)
              this.hospitalTotalCount = res.resultObj.totalCount
              if (res.resultObj.pages * 10 > res.resultObj.totalCount) {
                this.searchKey.pageNo = res.resultObj.pages
               this.$refs['hospitalForm'].popperElm.getElementsByClassName('loadingBox')[0].innerHTML = '~见底了~'
              }
            }
          })
        },
        // 上拉加载
        loadMore() {
          if (this.searchKey.pageNo * 10 <= this.hospitalTotalCount) {
            this.handleLoad()
            this.searchHospitalFun()
          }
          this.searchKey.pageNo += 1
        },
        // 远程搜索
        remoteMethod(query) {
          this.handleLoad()
          this.handleTop()
          if (query !== '') {
            this.loading = true
            this.searchKey.hospitalName = query
            this.searchKey.pageNo = 1
            searchHospital(this.searchKey).then(res => {
              if (res.resultCode === S_OK) {
                this.hospitalNoOptions = res.resultObj.list
                this.hospitalTotalCount = res.resultObj.totalCount
                this.loading = false
                if (res.resultObj.pages * 10 > res.resultObj.totalCount) {
                  this.searchKey.pageNo = res.resultObj.pages
          this.$refs['hospitalForm'].popperElm.getElementsByClassName('loadingBox')[0].innerHTML = '~见底了~'
                }
              }
            })
          } else {
            this.hospitalNoOptions = []
            this.searchKey = {
              'hospitalNo': '',
              'hospitalName': '',
              'pageNo': 1
            }
            this.searchHospitalFun()
          }
        },
        // 点击搜索时,就将见底了变回加载icon
        handleLoad() {
          this.$refs['hospitalForm'].popperElm.getElementsByClassName('loadingBox')[0].innerHTML = `
               <i class='el-icon-loading'></i>
            `
        },
        handleChange() {
          this.$emit('update:hospitalNo', this.ruleForm.hospitalNo)
        },
        handleTop() {
          const dom = document.getElementsByClassName('option-box')[0].getElementsByClassName('el-scrollbar__wrap')[0]
          dom.scrollTop = 0 // 回到顶部,有点问题,滚动条没有回去,其实是回到顶部了,有看出问题的也欢迎留言
        }
      }
    }
    </script>
    
    <style scoped>
    
    </style>
    
    

    回到顶部,有点问题,滚动条没有会去,其实是回到顶部了,有看出问题的也欢迎提留言

    定义全局组件:在main.js中

    Vue.component('hospitalForm', () => import('@/components/hospitalForm'))
    

    接下来就是使用了

      <hospital-form styles="width: 225px" :hospital-no.sync="ruleForm.hospitalNo" />
    

    其中子组件改变父组件传过来的值并没有保存是因为使用了.sync修饰符
    https://www.jianshu.com/p/3dbbbc7a259c

    最终实现结果为

    屏幕录制-2020-02-18-下午6.17.04.gif

    欢迎关注我的公众号:程序员蜗牛,会有惊喜哦


    image.png

    相关文章

      网友评论

          本文标题:优化elementui框架Select组件远程搜索不支持上拉加载

          本文链接:https://www.haomeiwen.com/subject/nifgfhtx.html