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

一,封装组件背景

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
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 162,710评论 4 376
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 68,839评论 2 308
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 112,295评论 0 255
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,776评论 0 223
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 53,198评论 3 297
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 41,074评论 1 226
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 32,200评论 2 322
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,986评论 0 214
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,733评论 1 250
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,877评论 2 254
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,348评论 1 265
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,675评论 3 265
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,393评论 3 246
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,209评论 0 9
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,996评论 0 201
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 36,212评论 2 287
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 36,003评论 2 280

推荐阅读更多精彩内容