适用场景
在项目中,我们需要运用到很多来自后端返回的数据。有时是上百条,有时甚至上千条。如果加上后端的多表查询或者数据量过大,这就导致在前端的显示就会及其慢,特别是在网络不好的时候更是如此。所以分页展示就是一种较好的交互体验了。
功能基本介绍
- 基于
element-ui
的el-select
实现的。 - 已封装成组件,可以实现单选、多选、远程搜索、滚动分页加载数据、数据回显。
效果
上代码
组件代码:
<template>
<el-select
v-model="selectedValue"
v-loadData="loadData"
remote
filterable
:remote-method="remoteMethod"
class="more-select"
:popper-class="`more-select-dropdown ${loading && 'loading'}`"
:multiple="multiple"
:clearable="clearable"
@change="selectChange"
>
<!-- 只有isShow定义了false,才进行隐藏,否则正常显示 -->
<el-option
v-for="(item,index) in list"
v-show="item.isShow===false?false:true"
:key="item.value + `'${index}'`"
:label="item.label"
:value="item.value"
/>
</el-select>
</template>
<script>
import Vue from 'vue'
Vue.directive(
'loadData',
{
bind(el, binding) {
// 获取element-ui定义好的scroll盒子
const SELECTWRAP_DOM = el.querySelector('.el-select-dropdown .el-select-dropdown__wrap')
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) binding.value()
})
}
}
)
export default {
props: {
// 默认选中值
selectedValue: {
type: [Array, String, Number],
default: ''
},
// 默认选中值对应的数据,用于回显
defaultSelectedStr: {
type: Array,
default: () => ([])
},
// 是否可以多选
multiple: {
type: Boolean,
default: false
},
// 是否可以清空
clearable: {
type: Boolean,
default: false
},
// 远程搜索时,输入框搜索值的键名
searchKey: {
type: String,
default: 'searchKey'
},
// 获取下拉框值得方法名
getListMethods: {
type: Function,
default: null
},
// 获取下拉框值时 默认参数
getListParams: {
type: Object,
default: () => ({})
},
// 下拉框值的格式
getListFormat: {
type: Function,
default: (data) => {
return data.map(({ label, value }) => ({ label, value }))
}
}
},
data() {
return {
list: [],
activeValue: '',
searchText: '',
pageNum: 1,
pageSize: 10,
loading: false,
finished: false // 是否加载完所有数据
}
},
watch: {
// 默认选中值
defaultSelected: {
handler() {
this.activeValue = this.defaultSelected
},
immediate: true
},
// 将选中的数据 拼成数组,放在list中,用于解决回显时 非第一页数据无法正常显示的问题
defaultSelectedStr: {
handler() {
this.list = this.list.concat(this.defaultSelectedStr)
},
immediate: true
}
},
created() {
this.getData()
},
methods: {
getData() {
if (!this.getListMethods || this.finished) return
this.loading = true
const params = {
...this.getListParams,
[this.searchKey]: this.searchText,
pageNum: this.pageNum,
pageSize: this.pageSize
}
this.getListMethods(params).then(({ data }) => {
// 对数据进行格式化
data = this.getListFormat(data)
// 判断是否是最后一页了
if (data.length < this.pageSize) this.finished = true
this.list = this.list.concat(data)
}).finally(() => {
this.loading = false
})
},
searchMethod(searchText) {
if (searchText === this.searchText) return
// 防抖处理
let timeout = null
clearTimeout(timeout)
timeout = setTimeout(() => {
this.list = []
this.pageNum = 1
this.finished = false
this.searchText = searchText
this.getData()
}, 500)
},
loadData() {
// 防抖处理
let timeout = null
clearTimeout(timeout)
timeout = setTimeout(() => {
if (this.finished) return
this.pageNum += 1
this.getData()
}, 500)
},
reset() {
this.activeValue = ''
},
selectChange(value) {
console.log(value)
this.$emit('selectedChange', value)
}
}
}
</script>
使用示例:
<template>
<div>
<ScrollSelect
:selected-value="value"
:default-selected-str="valueStr"
:get-list-methods="getListMethods"
:get-list-format="getListFormat"
:get-list-params="getListParams"
:clearable="true"
:multiple="true"
search-key="keyword"
@selectedChange="selectedChange"
/>
</div>
</template>
<script>
import ScrollSelect from './_modules/scroll-select'
import { queryList } from '@/api/index'
export default {
components: {
ScrollSelect
},
data() {
return {
value: [],
valueStr: [],
getListMethods: queryList,
getListFormat: ({ list = [] }) => { // 下拉框数据格式
return list.map(({ name, id: value }) => ({ label: name, value }))
},
getListParams: { // 下拉框接口默认参数
isDisabled: 0
}
}
},
mounted() {
// 设置默认选中的值
this.value = [1, 12]
this.valueStr = [{
name: 'test',
id: 1,
isShow: false
}, {
name: '选中的',
id: 12,
isShow: false
}]
},
methods: {
selectedChange(ids) {
this.value = ids
}
}
}
</script>