優(yōu)化elementui框架Select組件遠(yuǎn)程搜索不支持上拉加載更多功能

一,封裝組件背景

elementui框架Select組件遠(yuǎn)程搜索不支持上拉加載功能, 本教程用vue 自定義指令(directive)結(jié)合element Select遠(yuǎn)程搜索mixin混合模式,封裝select選擇器上拉夾雜支持遠(yuǎn)程搜索功能組件

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 獲取元素內(nèi)容高度(只讀)
       * scrollTop 獲取或者設(shè)置元素的偏移值,常用于, 計算滾動條的位置, 當(dāng)一個元素的容器沒有產(chǎn)生垂直方向的滾動條, 那它的scrollTop的值默認(rèn)為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()
      }
    })
  }
}

(本案例不講解自定義組件的知識,請自行學(xué)習(xí)或者加入我們的qq群或者關(guān)注公眾號 程序員蝸牛,回復(fù)你的問題)
文件結(jié)構(gòu)是
---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(接收函數(shù))


image.png
image.png

結(jié)果:


屏幕錄制-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 獲取元素內(nèi)容高度(只讀)
       * scrollTop 獲取或者設(shè)置元素的偏移值,常用于, 計算滾動條的位置, 當(dāng)一個元素的容器沒有產(chǎn)生垂直方向的滾動條, 那它的scrollTop的值默認(rèn)為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="醫(yī)院名稱:" 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: {
    // 初始化數(shù)據(jù),并上啦加載時
    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
    },
    // 遠(yuǎn)程搜索
    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修飾符
http://www.itdecent.cn/p/3dbbbc7a259c

最終實現(xiàn)結(jié)果為

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

歡迎關(guān)注我的公眾號:程序員蝸牛,會有驚喜哦


image.png
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容