开始之前
今儿的项目又遇见一个不按套路出牌的设计:一个列表页,设计图上是不分页查询,后台给的接口是分页查询。跟产品说加个分页,产品说用户就不想要分页(任性呀!)。可这么多数据一次性返回肯定是不行的,接口响应时间太长了。现在的爸爸们真的越来越有(难)品(伺)味(候)了。为了解决这个问题,决定把移动端常见的滚动加载放进来。
代码开撸
关于滚动加载的原理简单来讲就是我们设置一个高度固定的列表,当数据超过列表的高度,我们将产生出的滚动条拖拉到底部,到底部的时刻我们触发一次数据请求,把请求的数据添加数据列表中,触发页面重渲染就可以完成。没有想象中那么复杂。项目是基于Vue 和 ElementUI 做的,翻看 el-table
的时候发现一个属性,正好是用于实现该项功能的。
看说明,如果需要对表格内容进行无限滚动的操作,就用这个。那就是我们用 el-table
和 v-infinite-scroll
就可实现这个内容。但是直接用,还是稍微会有一点麻烦,所以在这里推荐使用在 github
发现的一个指令el-table-infinite-scroll
直接实现对 el-table
的滚动加载。
此指令依赖于 element-ui@2.12.0,使用前请熟悉:
安装
npm install --save el-table-infinite-scroll
全局引入
import Vue from 'vue';
import elTableInfiniteScroll from 'el-table-infinite-scroll';
Vue.use(elTableInfiniteScroll);
局部引入
<script>
import elTableInfiniteScroll from 'el-table-infinite-scroll';
export default {
directives: {
'el-table-infinite-scroll': elTableInfiniteScroll
}
}
</script>
组件中使用
<template>
<el-table
border
height="400px"
v-el-table-infinite-scroll="load"
:data="tableData"
>
<el-table-column prop="date" label="日期" width="180"> </el-table-column>
<el-table-column prop="name" label="姓名" width="180"> </el-table-column>
<el-table-column prop="address" label="地址"> </el-table-column>
</el-table>
</template>
<script>
import elTableInfiniteScroll from 'el-table-infinite-scroll';
const exampleData = new Array(10).fill({
date: '2016-05-02',
name: '王小虎',
address: '上海市普陀区金沙江路 1518 弄'
});
export default {
directives: {
'el-table-infinite-scroll': elTableInfiniteScroll
},
data() {
return {
tableData: exampleData
};
},
methods: {
load() {
this.$message.success('加载下一页');
this.tableData = this.tableData.concat(exampleData);
}
}
};
</script>
<style scoped>
.el-table {
width: 100%;
}
</style>
配置选项
参考 element-ui 官网 https://element.eleme.cn/#/zh-CN/component/infiniteScroll#attributes
用户体验改进
我们把上面的代码实现一遍,会看到我们很轻松的就实现了我们想要的滚动列表加载的效果。上面的代码中我们看到当我们一进入页面就会执行一遍load方法。但是想如果我们数据初始化的时候数据量很小,没有必要进行翻页查询,举个极端的例子比如我们只有一条数据,那我们这次的请求就是无效请求,是一种浪费用户时间,加重服务器负担的行为 ,是不可取的,所以我们需要有一个判断,判断数据是否需要在进来页面就执行load方法。
另外,对于后端接口的请求往往都是异步请求,返回数据是需要时间的,如果我们等待后台服务器返回数据这段时间内,反复触发了这个滚动加载的事件,特别是用户网络慢或者服务器负载大延长了服务器响应时间的时候,用户无聊的滚动着滚轮,大量的事件就会形成一个队列,依次向服务器发起请求,一个恶性的循环就形成了😨。另外测试人员对于这个问题也会测试的,他们就是拼命滑滚轮,玩死你(测试的同事看到了不要打我😷)。对于这个问题,我们同样需要设置一个条件,在请求后台数据的时候,我们不能进行数据请求的操作,另外为了交互的友好性,我们要提示用户数据正在加载中,请他们不要着急。
再就是如果当前我们请求的数据总量已经达到了后台数据量的总数,我们同样不能再触发后台的数据请求,然后给用户一个友好的提示,告诉他们数据已经加载完了,就不要拼命玩滚轮了。
综上我们需要改进的地方有三个:
-
判断页面初始化时是否要执行load方法
-
等待响应期间不能进行数据请求,并给出加载中的友好性提示
-
数据加载完成,禁止数据加载,并给出加载完成的友好性提示
el-table-infinite-scroll
这个指令的属性同饿了么 InfiniteScroll 无限滚动,饿了么这个指令中 infinite-scroll-disabled
:禁止滚动加载,infinite-scroll-immediate
:是否立即执行加载,来充满容器,正好对应我们这三个改进的地方。
指令我是全局配置,我把改进的代码线全部放到这里:
<template>
<el-row :gutter="20">
<el-col :span="8">滚动的列表</el-col>
<el-col :span="15">
<el-table
border
height="100%"
v-el-table-infinite-scroll="load"
infinite-scroll-immediate="first"
infinite-scroll-disabled="disabled"
:data="tableData"
>
<el-table-column prop="date" label="日期" width="180"> </el-table-column>
<el-table-column prop="name" label="姓名" width="180"> </el-table-column>
<el-table-column prop="address" label="地址"> </el-table-column>
<div slot="append" style="text-align: center">
<span v-if="loading" class="prompt">--- 加载中 ---</span>
<span v-if="noMore" class="prompt">--- 没有更多了 ---</span>
</div>
</el-table>
</el-col>
</el-row>
</template>
<script>
const exampleData = new Array(10).fill({
date: '2016-05-02',
name: '王小虎',
address: '上海市普陀区金沙江路 1518 弄'
});
export default {
name: "Table",
data() {
return {
loading:false,
dataCount:10,
tableData: []
};
},
computed:{
first(){
return this.dataCount > 10
},
noMore(){
return this.tableData.length >= this.dataCount
},
disabled(){
return this.loading || this.noMore
}
},
methods: {
load() {
this.$message.success('加载下一页');
this.loading = true;
setTimeout(()=>{
this.tableData = this.tableData.concat(exampleData);
this.loading = false;
},2000);
}
},
mounted() {
this.dataCount = 10;
this.tableData = [...exampleData];
}
}
</script>
<style scoped>
.prompt{
display: inline-block;color: #d3dce6;margin: 10px
}
</style>
这里根据 el-table-infinite-scroll
要求,给table加了height属性并设置为100%,让高度自适应。我们假设每次请求后台只返回10条数据,而10条数据无法充满容器。所以设置计算属性first
,判断数据总量是否小于10,小于10时进入页面就不执行load方法,由于数据无法充满容器,其实这个指令相当于无效,列表就是正常的展示。通过 noMore 和 loading 控制 el-table 插槽中提示信息的显示。然后通过disabled计算属性通过loading || noMore
来控制是否允许滚动加载,也就是这两个值要有一个是true就不让其滚动加载。好了一个滚动的列表就完成了。测试的时候可以通过改动dataCount
值来看效果。
写在最后
眼看一个周又要过去,这是冠状疫情之后在北京禁足的第四个周。很想念上班的时光,今天看到集团公众号刊登的武汉同事的一句话:“好久没有一起为一个需求和方案跟工作中的小伙伴当面‘吵架’了”。然后晚上跟我的back-end partner煲了一个小时的电话粥。希望疫情快点过去,大家喜乐安康,平安复工!最后附上这个指令的具体方式,希望能和大家在前端道路的一起进步。
网友评论