vue-virtual-scroll-list与selectLoadmore对比:
vue-virtual-scroll-list:一次性返回所有数据。即数据量适中,几千到一两万条,可一次性被后台接口返回的情况下,建议使用vue-virtual-scroll-list。
selectLoadmore:可懒加载下拉框,数据量超级大,几万甚至十几万条以上,后台无法一次性返回,只能分页加载的情况下,建议使用selectLoadmore。
一、components/selectLoadmore/index.vue
<template>
<el-select class="ba-content" :popper-append-to-body="false"
:value-key="valueName"
v-model="selectedOptions"
v-el-select-loadmore="loadmore"
@change="change"
:remote-method="remoteMethodThrottle"
:loading="loading"
@visible-change="visibleChange" clearable filterable remote
:placeholder="!disabled?'请输入关键词':'——'" :disabled="disabled">
<el-option v-for="item in showList" :key="item[valueName]" :label="item[valueName]" :value="item"></el-option>
</el-select>
</template>
<script>
export default {
name: 'el-select-loadmore',
props: {
value: {
type: String
},
showList: {
type: Array
},
placeholder: {
type: String
},
disabled: {
type: Boolean,
default: false
},
//相同名称的label和value不需传参给子组件,采用默认值
valueName: {
type: String,
default: 'label'
},
labelName: {
type: String,
default: 'value'
}
},
data() {
return {
//data重新定义变量接受组件v-model(value:名称必须为value)值,不改变props接收的值
selectedOptions: this.value,
loading: false
}
},
//监听值的变化
watch: {
value(newVal) {
this.selectedOptions = newVal
}
//若选择器的值发生改变,则传参给父组件
//this.$emit(‘input’,val),在父组件直接用v-model绑定,则可以直接获取到
// selectedOptions(newVal, oldVal) {
// this.$emit('input', this.selectedOptions)
// }
},
// 自定义指令(和method同级)
directives: {
// 下拉框懒加载(el-select-loadmore是自定义的指令,使用时前面加v-)
'el-select-loadmore': {
// el:使用自定义指令的元素(下拉框),
bind(el, binding) {
// 下拉框下拉的框
const SELECTWRAP_DOM = el.querySelector(
'.el-select-dropdown .el-select-dropdown__wrap'
)
// 增加滚动监听,
SELECTWRAP_DOM.addEventListener('scroll', function () {
// scrollHeight:当前所有选项的高度
// scrollTop:滚动的距离
// clientHeight:下拉框的高度
// const condition =
// this.scrollHeight - this.scrollTop == this.clientHeight ||
// this.scrollHeight - this.scrollTop == this.clientHeight + 1
const condition =
this.scrollHeight - this.scrollTop <= this.clientHeight + 40
// 当滚动条滚动到最底下的时候执行接口加载下一页
if (condition) {
binding.value()
}
})
}
}
},
computed: {
// 防抖
remoteMethodThrottle() {
let time = null
return (param) => {
if (time) {
clearTimeout(time)
}
time = setTimeout(() => {
// 搜索方法
this.remoteMethod(param)
clearTimeout(time)
}, 1000)
}
}
},
methods: {
// 下拉框出现、隐藏
visibleChange(val) {
this.$emit('visibleChange', val)
},
// 自定义指令的方法:下拉框滚动到底懒加载
loadmore() {
this.$emit('loadmore')
},
// 远程搜索物料类别
remoteMethod(query) {
this.$emit('remoteMethod', query)
},
// 选择器的值发生改变
change(item) {
this.$emit('change', item)
}
}
}
</script>
<style lang="scss" scoped>
</style>
二、调用页面
<template>
<selectLoadmore :disabled="disabled" :value="base.otpTcmDise" :showList="selectOptions" valueName="diagName" @loadmore="loadmore" @remoteMethod="remoteMethod" @visibleChange="visibleChange" @change="(val) => change(val, 'tcmDiseCode')"></selectLoadmore>
</template>
<script>
data() {
return {
// 搜索,远程,懒加载下拉相关数据
querys: '', // 远程搜索输入的内容
selectLoading: false, //select加载
stopLoading: false, // 最后一次加载之后,不再加载
pageData: {
// 懒加载相关参数,这里代表从第一条数据开始加载,一次加载十项
current: 1,
size: 10
},
selectOptions: [],
}
},
methods: {
// 下拉框出现、隐藏
visibleChange(val) {
if (!val) {
//隐藏
// 重置懒加载
this.stopLoading = false
// 重置数据
this.querys = null
this.pageData = {
// 懒加载相关参数,这里代表从第一条数据开始加载,一次加载十项
current: 1,
size: 10
}
this.selectOptions = []
}
},
// 自定义指令的方法:下拉框滚动到底懒加载
loadmore() {
if (!this.stopLoading) {
this.pageData.current++ // 搜索下一页
this.getTypeOption(this.pageData) //调用接口获取下拉框数据
}
},
// 远程搜索物料类别
remoteMethod(query) {
this.querys = query // 保存搜索内容
// 重置懒加载
this.stopLoading = false
this.pageData = {
current: 1,
size: 10
}
let params = this.pageData
params.query = query
// 调用接口
this.selectLoading = true
_interface(params).then((res) => {
if (res.code == 200) {
this.selectOptions = res.result.records
} else {
this.$message({ type: 'error', message: '错误返回提示' })
}
this.selectLoading = false
})
},
// 获取物料类别下拉内容
getTypeOption(params) {
params.query = this.querys
this.selectLoading = true
_interface(params).then((res) => {
if (res.code == 200) {
// 如果某次返回值是[],表示已经加载完了,不必再加载
if (res.result.records.length == 0) {
this.stopLoading = true
return
}
if (params.current == 1) {
// 保存数据
this.selectOptions = res.result.records
} else {
this.selectOptions = [...this.selectOptions, ...res.result.records]
}
} else {
this.$message({ type: 'error', message: '错误返回提示' })
}
this.selectLoading = false
})
},
// 西医
change(obj, key) {
this.base[key] = obj.diagCode
}
}
</script>