滚动加载的列表

开始之前

今儿的项目又遇见一个不按套路出牌的设计:一个列表页,设计图上是不分页查询,后台给的接口是分页查询。跟产品说加个分页,产品说用户就不想要分页(任性呀!)。可这么多数据一次性返回肯定是不行的,接口响应时间太长了。现在的爸爸们真的越来越有(难)品(伺)味(候)了。为了解决这个问题,决定把移动端常见的滚动加载放进来。

代码开撸

关于滚动加载的原理简单来讲就是我们设置一个高度固定的列表,当数据超过列表的高度,我们将产生出的滚动条拖拉到底部,到底部的时刻我们触发一次数据请求,把请求的数据添加数据列表中,触发页面重渲染就可以完成。没有想象中那么复杂。项目是基于Vue 和 ElementUI 做的,翻看 el-table 的时候发现一个属性,正好是用于实现该项功能的。

看说明,如果需要对表格内容进行无限滚动的操作,就用这个。那就是我们用 el-tablev-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方法。

另外,对于后端接口的请求往往都是异步请求,返回数据是需要时间的,如果我们等待后台服务器返回数据这段时间内,反复触发了这个滚动加载的事件,特别是用户网络慢或者服务器负载大延长了服务器响应时间的时候,用户无聊的滚动着滚轮,大量的事件就会形成一个队列,依次向服务器发起请求,一个恶性的循环就形成了😨。另外测试人员对于这个问题也会测试的,他们就是拼命滑滚轮,玩死你(测试的同事看到了不要打我😷)。对于这个问题,我们同样需要设置一个条件,在请求后台数据的时候,我们不能进行数据请求的操作,另外为了交互的友好性,我们要提示用户数据正在加载中,请他们不要着急。

再就是如果当前我们请求的数据总量已经达到了后台数据量的总数,我们同样不能再触发后台的数据请求,然后给用户一个友好的提示,告诉他们数据已经加载完了,就不要拼命玩滚轮了。

综上我们需要改进的地方有三个:

  1. 判断页面初始化时是否要执行load方法

  2. 等待响应期间不能进行数据请求,并给出加载中的友好性提示

  3. 数据加载完成,禁止数据加载,并给出加载完成的友好性提示

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煲了一个小时的电话粥。希望疫情快点过去,大家喜乐安康,平安复工!最后附上这个指令的具体方式,希望能和大家在前端道路的一起进步。

el-table-infinite-scroll 实现原理

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,847评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,208评论 1 292
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,587评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,942评论 0 205
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,332评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,587评论 1 218
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,853评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,568评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,273评论 1 242
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,542评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,033评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,373评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,031评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,073评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,830评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,628评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,537评论 2 269