当下拉列表数据过大时,该如何应对?

栏目: JavaScript · 发布时间: 7年前

内容简介:在日常开发中,除了现成插件的使用外,还有很多问题是只能自己动手的。先抛出问题,当一个下拉列表的数据达到几千条甚至上万,这个时候浏览器已经会出现严重卡顿了。看看下面的例子如图所示,数据量达到这个问题其实和表格数据是同一个性能问题,表格的解决方式是通过分页器来减少页面承载的数据量。那么下拉列表该如何解决呢?通常我们都是一次性加载下拉的所有数据的,针对目前的难题,思路也是一样,采用分页来解决页面的性能问题。问题又来了,分页器是可以点击的,那下拉列表又不可以点击,那就只有在监听滚动事件里实现这件大事了。先来大纲:

在日常开发中,除了现成插件的使用外,还有很多问题是只能自己动手的。先抛出问题,当一个下拉列表的数据达到几千条甚至上万,这个时候浏览器已经会出现严重卡顿了。看看下面的例子

当下拉列表数据过大时,该如何应对?

如图所示,数据量达到 2W简单测试数据 (页面没有其他东西),点击加载下拉列表花了大概 5s 时间。出现这种情况心里真的是很复杂,这不是在玩我吗?

当下拉列表数据过大时,该如何应对?

解决思路

这个问题其实和表格数据是同一个性能问题,表格的解决方式是通过分页器来减少页面承载的数据量。那么下拉列表该如何解决呢?通常我们都是一次性加载下拉的所有数据的,针对目前的难题,思路也是一样,采用分页来解决页面的性能问题。问题又来了,分页器是可以点击的,那下拉列表又不可以点击,那就只有在监听滚动事件里实现这件大事了。先来大纲:

  1. 监听滚动
  2. 向下滚动时往后加载数据
  3. 向上滚动时往前加载数据
  4. 数据有进有出
    当下拉列表数据过大时,该如何应对?

好戏开始

监听滚动

<el-select class="remoteSelect" v-scroll v-model="value">
      <el-option :value="item.id" v-for="item in list" :key="item.id">{{item.name}}</el-option>
    </el-select>
复制代码

这里是基于vue与element-ui中 el-select 实现的监听滚动。这里是采用自定义指令的方式监听滚动

// directives目录下index.js文件

import Vue from 'vue'
export default () => {
  Vue.directive('scroll', {
    bind (el, binding) {
      // 获取滚动页面DOM
      let SCROLL_DOM = el.querySelector('.el-select-dropdown .el-select-dropdown__wrap')
      SCROLL_DOM.addEventListener('scroll', function () {
        console.log('scrll')
      })
    }
  })
}
复制代码

在main.js中通过全局方法Vue.use()注册使用

import Directives from './directives'
Vue.use(Directives)
复制代码

这时滚动页面就可以看到控制的打印日志,代表监听已生效,接下来撸起袖子开干

当下拉列表数据过大时,该如何应对?

向下滚动时往后加载数据

首先要先判断出是向上滚动,还是向下滚动

  1. 记录上一次的滚动位置
  2. 当前位置与上一次的滚动位置作比较

通过一个公共变量来记录全局位置,通过 scrollTop 方法获取当前的滚动位置,并记录在公共变量 scrollPosition

bind (el, binding) {
      // 获取滚动页面DOM
      let SCROLL_DOM = el.querySelector('.el-select-dropdown .el-select-dropdown__wrap')
      let scrollPosition = 0
      SCROLL_DOM.addEventListener('scroll', function () {
        // 当前的滚动位置 减去  上一次的滚动位置
        // 如果为true则代表向上滚动,false代表向下滚动
        let flagToDirection = this.scrollTop - scrollPosition > 0
        // 记录当前的滚动位置
        scrollPosition = this.scrollTop
        console.log(flagToDirection ? '滚动方向:下' : '滚动方向:上')
      })
    }
复制代码
当下拉列表数据过大时,该如何应对?

目前已知晓滚动的方向,接下来便根据滚动方向做相应的处理。将滚动行为告诉组件

...省略
        // 记录当前的滚动位置
        scrollPosition = this.scrollTop
        // 将滚动行为告诉组件
        binding.value(flagToDirection)
复制代码

事件接受在 v-scroll 指令中接受事件 v-scroll="handleScroll" ,在该方法 handleScroll 处理滚动行为。 接下来只需要在该事件中针对为向下的滚动发起请求数据即可

/*********************************
      ** Fn: handleScroll
      ** Intro: 处理滚动行为
      ** @params: param 为true代表向下滚动
      ** @params: param 为false代表向上滚动
    *********************************/
    handleScroll (param) {
      if (param) {
        // 请求下一页的数据
        this.list.push(...this.ajaxData(++this.pageIndex))
      }
    },
复制代码
当下拉列表数据过大时,该如何应对?

到这里滚动加载已经实现。只是加载太频繁了,如果快速滚动则会同时发出多个请求后台数据,在密集一些游览器中ajax就要开发并发排队了,可见并不理想。那如何控制呢?那换种方式触发 handleScroll 事件,在滚动位置距离滚动页面底部一定高度时在触发,例如距页面底部只有 100px 时触发 handleScroll 事件

scrollHeight
// 记录当前的滚动位置
        scrollPosition = this.scrollTop
        const LIMIT_BOTTOM = 100
        // 记录滚动位置距离底部的位置
        let scrollBottom = this.scrollHeight - (this.scrollTop + this.clientHeight) < LIMIT_BOTTOM
        // 如果已达到指定位置则触发
        if (scrollBottom) {
          // 将滚动行为告诉组件
          binding.value(flagToDirection)
        }
复制代码
当下拉列表数据过大时,该如何应对?

通过数据长度的变化可以知道触发事件已经明显和谐了很多,这种效果很手机懒加载的方式一样,数据会被不断的叠加。

小提示:会存在一个bug,即ajax是异步的,如果这个ajax请求花了 1s 才返回数据,而此时还在继续往下滚,那就会触发多个请求事件。如何避免这种情况呢? 答案是增加一个标志位,在请求前将该标志位设置为false,请求结束后设置为true。每次请求时先判断该标志位。如果为false则阻止该事件。

中场

再来看看我们的大纲

  1. 监听滚动
  2. 向下滚动时往后加载数据
  3. 向上滚动时往前加载数据
  4. 数据有进有出

到这里我们只完成①和②两个步骤。如果已经满足了你的需求,那你可以结束阅读了。如果对你有那么一点点帮助,先点个赞在离开。

前面说的都还只是基础操作,还没开始划重点呢。说好的无性能压力呢?

当下拉列表数据过大时,该如何应对?

先下班回家吃饭吧。周末继续写完


以上所述就是小编给大家介绍的《当下拉列表数据过大时,该如何应对?》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Learning Vue.js 2

Learning Vue.js 2

Olga Filipova / Packt Publishing / 2017-1-5 / USD 41.99

About This Book Learn how to propagate DOM changes across the website without writing extensive jQuery callbacks code.Learn how to achieve reactivity and easily compose views with Vue.js and unders......一起来看看 《Learning Vue.js 2》 这本书的介绍吧!

HTML 压缩/解压工具
HTML 压缩/解压工具

在线压缩/解压 HTML 代码

JSON 在线解析
JSON 在线解析

在线 JSON 格式化工具

图片转BASE64编码
图片转BASE64编码

在线图片转Base64编码工具