第一步,创建select-load-more.js文件
// 定义全局自定义指令
import Vue from 'vue'
const selectLazyLoad = function(Vue) {
// el-select组件数据过多,使用翻页加载数据指令
Vue.directive('selectLazyLoad', {
bind(el, binding) {
const SELECT_WRAP_DOM = el.querySelector('.el-select-dropdown .el-select-dropdown__wrap')
SELECT_WRAP_DOM.addEventListener('scroll', function() {
// toFixed:把this.scrollTop转换为整数,兼容不同版本浏览器
const condition = this.scrollHeight - this.scrollTop.toFixed(0) <= this.clientHeight
if (condition) binding.value()
})
}
})
}
if (window.Vue) {
Vue.use(selectLazyLoad)
}
export default selectLazyLoad
第二步, 在main.js中注册引入自定义指令
import selectLazyLoad from './directive/select-load-more' //引入
Vue.use(selectLazyLoad) // 使用自定义指令
第三步, 创建公共组件并在组件中使用自定义指令v-selectLazyLoad
<template v-slot>
<el-select
v-model="currentBranchNumber"
v-selectLazyLoad:pageNum="loadMoreData(pageNum)"
class="w-72"
:dropdown-style="{maxHeight: '400px', overflow: 'auto'}"
placeholder="可根据机构ID或机构名称筛选"
filterable
clearable
remote
:remote-method="onSearch"
:loading="loading"
@clear="clearSelect"
@focus="focusSelect"
>
<el-option v-for="item in branchTreeData" :key="item.id" :label="item.name" :value="item.id" />
</el-select>
</template>
<script>
import axios from 'axios'
export default {
name: 'BranchTreeSelect',
props: {
branchNumber: {
type: String,
default: ''
}
},
data() {
return {
branchTreeData: [],
pageNum: 1,
currentBranchNumber: '',
allowSearchFlag: true, // 是否允许检索, 防止连续输入时未组装好数据就再次检索
loading: false,
queryParam: { // 查询后端所用参数对象, 可根据自己需求变更请求参数对象
'xCode': '', // 模糊检索code
'xName': '', // 模糊检索name
'xParentCode': 'AYBBRNNO',
'xType': '',
'xFormat': 'Y',
'xPage': 1,
'xPageSize': 50
}
}
},
watch: {
'currentBranchNumber': { // 选中数据改变时,调用父组件的setBranchNumber方法,并传入选中的值
handler(val) {
if (val) {
this.$emit('setBranchNumber', this.currentBranchNumber.toString().split(':')[0])
} else {
this.$emit('setBranchNumber', '')
}
}
},
'pageNum': { // 当前页数改变时, 重新触发查询
handler(val) {
if (val) {
this.queryParam.xPage = val
this.queryBranchData('', true)
}
}
}
},
created() { // 组件实例创建后(data和methods已经初始化完毕), 请求后端数据
this.queryBranchData()
},
methods: {
loadMoreData() { // 数据到底部继续滑动,会自动触发页数+1
return () => {
this.pageNum += 1
}
},
onSearch(val) { // 检索功能, 后端可以支持模糊检索
if (val) {
if (this.allowSearchFlag && val.length > 2) { // 输入超过两个字符进行检索
this.allowSearchFlag = false
this.branchTreeData = []
this.queryParam.xPage = 1
this.queryBranchData(val)
}
}
},
queryBranchData(param, appendFlag) { // 请求后端数据
const cacheUrl = 'http://XXXXXXXXX.uat.cn/cache/queryParamPager'
if (!isNaN(parseInt(param)) && isFinite(param)) {
this.queryParam['xCode'] = param
} else if (param && param.trim() !== '') {
this.queryParam['xName'] = param
}
axios.post(cacheUrl, this.queryParam, {
headers: { 'Content-Type': 'application/json' },
withCredentials: false
}).then(res => {
if (res.data.code === 200 && res.data.data.list.join() !== '') { // 如果后端返回数据有值
if (appendFlag) { // 是否拼接数据
this.branchTreeData = this.branchTreeData.concat(res.data.data.list)
} else {
this.branchTreeData = res.data.data.list
}
this.allowSearchFlag = true
this.loading = false
}
}).catch(err => console.error(`获取机构参数异常, ${err}`))
},
clearSelect() { // 清空下拉框选中的值,会向后端重新查询第一页的数据
this.queryParam['xCode'] = ''
this.queryParam['xName'] = ''
this.queryParam.xPage = 1
this.branchTreeData = []
this.queryBranchData()
},
focusSelect() { // 光标触发下拉框时,如果下拉框数据为空,则向后端查询第一页数据
if (this.branchTreeData.join() === '') {
this.queryParam['xCode'] = ''
this.queryParam['xName'] = ''
this.queryBranchData()
}
}
}
}
</script>
<style scoped>
</style>
第四步, 在父组件中引入第三步创建的子组件
// 使用第三步创建的子组件
<branch-tree-select ref="accBranchRef" :branch-number="QueryProtocolListX1.accBranch" @setBranchNumber="setAccBranchNumber" />
// 引入子组件
import BranchTreeSelect from '@/components/BranchTreeSelect'
components: {
BranchTreeSelect
}
mothods: {
setAccBranchNumber(val) {
// val就是子组件选中的值
}
}
以上内容四个步骤从下面链接复制https://devpress.csdn.net/vue/66caf7da8f4f502e1cfda77e.html
以下内容四个步骤从下面链接复制
https://www.cnblogs.com/caihongmin/p/17920859.html
自定义指令
import { debounce } from "lodash";
export default {
inserted(el, binding, vnode) {
// 获取滚动容器dom
let scrollWrap = el.querySelector('.el-select-dropdown .el-scrollbar .el-select-dropdown__wrap')
// 把监听的句柄防抖一下
const handle = debounce((e) => {
let scrollDistance = scrollWrap.scrollHeight - scrollWrap.scrollTop
// 比如此处预留6个像素的位置用于触底
if (scrollWrap.clientHeight + 6 > scrollDistance) {
binding.value() // 触底通知一下,外界
}
}, 170)
// 绑定监听滚动事件
scrollWrap?.addEventListener('scroll', handle)
// 把监听的句柄挂载到元素身上便于解绑时使用
el._hanlde = handle
},
unbind() {
// 获取滚动容器dom
let scrollWrap = el.querySelector('.el-select-dropdown .el-scrollbar .el-select-dropdown__wrap')
// 解绑
scrollWrap?.removeEventListener('scroll', el._hanlde)
// 清空
delete el._hanlde;
}
}
给el-select使用这个自定义指令
<template>
<div class="box">
<el-select v-model="value" filterable :popper-append-to-body="false" v-down="loadmore" clearable>
<el-option v-for="item in options" :key="item.id" :label="item.name" :value="item.id">
</el-option>
</el-select>
</div>
</template>
<script>
import axios from "axios";
export default {
data() {
return {
options: [],
value: '',
pageIndex: 1,
pageSize: 20
};
},
mounted() {
this.getOptions()
},
methods: {
async getOptions() {
// 笔者自己的服务器,给大家提供了一个分页接口
let url = `http://ashuai.work/api/pageData?pageIndex=${this.pageIndex}&pageSize=${this.pageSize}`
let { data } = await axios.get(url)
if (data.length == 0) return this.$message('没数据了')
// 合并一下下拉框数据
this.options = [
...this.options,
...data
]
},
// 触底了,继续发请求
loadmore() {
this.pageIndex = this.pageIndex + 1
this.getOptions()
},
},
};
</script>