一,封裝組件背景
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