项目中,有个 select 下拉选择做成了分页的形式,就是默认请求第一页的数据,然后当用户下拉到底部的时候,在重新请求一个接口,页码 +1。
这个做法有两个难点,第一个难点是你需要知道用户何时滚动到底部,并且调用接口获取数据;第二个难点是,比如说用户选择了第三页的某个 option,但是当你复原数据的时候,默认只请求第一页的数据,你直接赋值的话,会把用户选择第三页的值原封不动的显示在页面上。
首先是如何知道用户滚动到底部,因为使用的是 Vue + element-ui,所以可以使用 Vue 提供的自定义指令来监听滚动条,然后判断高度。代码如下:
// template
<el-select v-model="form.test" v-loadmore="someFunction" ></el-select>
// script
directives: {
loadmore: {
bind(el, binding) {
const dom = el.querySelector(".el-select-dropdown .el-select-dropdown__wrap")
dom.addEventListener("scroll", () => {
let different = dom.scrollHeight - dom.scrollTop <= dom.clientHeight
if (different) {
binding.value()
}
})
},
},
}
methods: {
someFunction() {
// 获取接口
// 假设接口获取到的数据为 axiosInfo
//数据组合
// 假设当前的 v-for 为 testList
this.testList = [...this.testList, ...axiosInfo]
}
}
上面数据获取到了,之后就是第二个问题。一般来说分页接口都有 total
来表示数据总共的条数,以及 page
表示当前的页码,那么在保存数据的时候,可以顺便把当前请求的最后页码保存起来,下次再请求的时候,可以使用 while
循环来判断。
let userSavePage = 3 // 假设通过接口获取到用户选择的最后一页为 3
let currentPage = 1 // 当前页数,默认为 1
while(currentPage < userSavePage) {
currentPage++
getAxiosFun() // 获取数据接口
}
这样就解决了这个问题,但是有一种情况可以优化一下,假设用户选择了第三页的数据,当前的 currentPage
为 3,当用户取消选择了第三页的数据,又选择了第一页的数据,那么 currentPgae
还是 3,保存的时候页码还是 3,你下次请求还是请求 3 次,所以这就造成了一种资源浪费,不仅多了 2 次 http 请求,还加大了页面渲染的压力。
那么优化的方法思路是:
首先是需要根据用户所选择的数据,获取到数据里所在页码的最大值,而不是用户选择的最后一个值,因为如果用户选择了第三页的某个值,当前获取到的页码是 3,如果用户选择了第四页的值,当前获取到的页码是 4,用户继续选择第一页的值,那么当前获取到的页码是 1,如果你直接根据最后一个值,那么获取到的页数是 1,那么就不对了。
所以,因为依次遍历用户选择的每一项,找到所在 index
最大的那个值,然后计算出页码,进行保存。
代理逻辑是:
- 使用
forEach
依次遍历所选数据 - 使用
findIndex
找到index
并保存在一个列表里 - 根据
Math.max(...xxx)
找到最大的index
- 根据
size
计算出页码(一般是10),Math.ceil(index/size)
这里有个隐藏的 bug,就是 size 是不固定的,如果你保存的时候,size 比较大,那么相对的保存的 page 就较小,但是当你把 size 变小的时候,那么真实获取的其实 page 应该变大,所以以上优化应该在 size 固定的情况下使用