场景
修改个人信息时,职务信息回显,且加载全部职务数据的话,数据量太大,导致接口请求时间太久,用户体验不好。职务选项是el-select下拉选择,并且官方el-select不支持分页懒加载。
实现思路
1. 点击修改时,把职务id和职务名称带过来,直接添加到 list 中,保证回显速度。
2. 如果只有id没有名称,就用id查询列表,返回一条数据,实现回显,体验速度其次(跟后端协调好,接口要支持id检索和名称模糊检索)。
3. 同时加载第一页数据,取20条,保证下拉列表能有滚动效果。
4. 自定义vue滚动指令方法,获取下拉DOM,实现滚动触底加载,然后拼接数据,触底时判断现有数据量是否小于总数据量,然后决定是否加载下一页数据。
5. 支持搜索关键字检索,当输入关键字检索触发搜索时,page重置为1,同时支持触底分页;清空关键字时亦同理。
6. 当搜索关键字查询 list 为空,并且触发下拉框隐藏时,page重置为1,并重新加载第一页数据,避免重新触发下拉框显示时,没有内容的奇怪现象。
7. 当选择时,更新回显数据为选择的数据,并把list重置为选择数据数组,并加载第一页数据,重新赋值给list。
思路完成,上代码。
实现代码
页面处理代码
test.vue
<!-- 下拉部分 -->
<el-form-item label="选择xx:">
<el-select
v-model="formData.storeld"
placeholder="请选择"
filterable
clearable
remote
reserve-keyword
v-scroll="handleScroll
@change="handleChange"
:remote-method="remoteMethod"
@visible-change="visibleChange"
style="width: 100%;
>
<el-option
v-for="item in storelist'
:key="item.id"
:label="item.name
:value="item.id"
>
</el-option>
</el-select>
</el-form-item>
<script lang='ts'>
// 数据部分
@Prop({ required: true }) public srcData!: any // 当前的数据对象
public isLoading = false // 加载状态
public showRow: any = {} // 需要回显的下拉数据对象
public storelist = [] // 下拉列表
public page = 1 // 页码
public pageSize = 20 // 每页分页数量
public total = 0 // 数据总量
public formData = {} // 提交表单数据
/**
* 方法部分
*/
mounted() {
const { storeId, storeName } = this.srcData
this.$set(this.formData, 'storeId', storeId)
// storeId一定存在,sotreName不一定,所以做个判断
if (storeId && storeName) {
this.showRow = { id: storeId, name: storeName }
this.storeList = [this.showRow]
this.getStoreList({})
} else {
this.getStoreList({ storeId })
}
}
// 处理滚动事件
handleScroll (event) {
const { scrollTop, scrollHeight, clientHeight } = event.target
const isNearBottom = scrollTop + clientHeight >= scrollHeight // 触底加载更多
if (isNearBottom && !this.isLoading && this.storelist.length < this.total) {
this.page += 1
this.getStoreList({})
}
}
// 处理选择事件
handleChange(v) {
if (v) {
const row = this.storeList.filter(item => v === item.id)
this.showRow = row[0]
}
this.storeList = [this.showRow]
this.page = 1
this.getStoreList({})
}
// 处理搜索事件
remoteMethod(query: string) {
this.page = 1
if (query !== '') {
this.getStoreList({ storeName: query })
} else {
this.getStoreList({})
}
}
// 处理下拉显示隐藏事件
visibleChange(v: boolean) {
if (v === false && this.storeList.length === 0) {
this.getStoreList({})
}
}
// 获取下拉列表
getStoreList (obj: { storeId?: string, storeName?: string }) {
const { storeId, storeName } = obj
const params = {
page: this.page,
pageSize: this.pageSize
}
if (storeId) {
params.id = storeId
}
if (storeName) {
params.name = storeName
}
this.isLoading = true
const url = '/getList'
JavaHttp.postDataCallback(url, params, (ret: boolean, data: any) => {
this.isLoading = false
if (ret === true && data.code === 0) {
const list = data.data.list || []
this.total = data.data.total || 0
if (storeId) {
this.showRow = list[0]
this.storeList = list
this.getStoreList({})
} else {
if (this.page === 1) {
this.storeList = list
} else {
this.storeList = this.storeList.concat(list)
}
}
}
})
}
</script>
自定义指令v-scroll
main.ts
Vue.directive('scroll', {
inserted: function(el, binding) {
const selectDropdown: any = el.querySelector(
'.el-select-dropdown .el-select-dropdown__wrap'
)
selectDropdown.addEventListener('scroll', binding.value)
}
})
注意:我们这里用 class 类名取的 el-select 下的下拉滚动区域DOM对象,如果组件升级或者类名修改,要注意替换。或者可以用其他方式获取下拉滚动区域DOM。