手写vue无限滚动指令的详细过程

 更新时间:2022年09月07日 10:44:13   作者:ginp  
今天在移动端项目中遇见一个需求,需要数据无限滚动,所以下面这篇文章主要给大家介绍了关于手写vue无限滚动指令的详细过程,文中通过实例代码介绍的非常详细,需要的朋友可以参考下

概述

日常的开发当中,为了处理大量数据的情况,一般前端会采用分页展示,可以通过分页插件进行数据的按需分页请求展示,另一种解决大量数据的渲染的方式就是无限滚动,在移动端比较常见,也就是我们常见的滚动到底部加载更多数据,一般web端用下拉加载更多场景不是很多,但是也还是有,比如京东和淘宝的web官方,就用到了无限滚动,通过滚动到底部,然后加载更多数据。总之,无限滚动和分页插件都是为了解决大数据展示的问题,现在介绍下vue中通过自定义指令实现无限滚动。

最终效果

实现原理

在开始敲代码之前,先讲一下无限滚动的原理,首选我们需要之前的,怎么才算滚动到底部,然后我们才能去执行加载更多的函数。

关于高度计算的几个方法

clientHeigt

  • 这两个属性用于获取元素块可视区的宽高,该属性包括内边距 padding,但不包括边框 border、外边距 margin 和垂直滚动条

scrollHeight

  • 一个元素内容高度的度量,包括由于溢出导致的视图中不可见内容,也就是一个元素宽的实际高度,包含被滚动条卷走的部分。具体看下图:

scrollTop

  • 滚动条卷走的高度。,参考下图:

综上

得出滚动条到达底部的计算公式为:clientHeight + scrollTop == scrollHeight,知道这个之后,我们写逻辑就容易多了,只需要在滚动条到达底部的时候,重新取获取数据就可以了。

目录结构

App.vue

无限滚动首选需要一个固定高度的盒子然后设置 style="overflow: auto" 然后可以根据需要加上滚动结束的限制,比如loading等

<template>
  <div id="app">
  //外层包裹盒子
      <div
        class="infinite-list"
        v-infinite-scroll.loading.complated.immediate="load"
        style="overflow: auto"
        ref="infiniteList"
      >
        <ul>
          <li v-for="i in count" class="infinite-list-item">{{ i }}</li>
        </ul>
        //加载中
        <p v-if="loading && !complated" class="text">加载中...</p>
        //结束了
        <p v-if="complated" class="text">没有更多了</p>
      </div>
    </div>
  </div>
</template>

<script>
import Velocity from "velocity-animate";
import { DatePicker } from "./components/DatePicker/index";
export default {
  name: "App",
  components: {
    DatePicker,
  },
  data() {
      count: 1,
      loading: false,
      complated: false,
    };
  },
  methods: {
  //滚动到底部的处理逻辑
    load() {
      // 以下是定时器模拟异步数据请求,可根据自己的需求进行变更
      this.loading = true;
      setTimeout(() => {
        if (this.count >= 15) {
          this.complated = true;
          return;
        }
        this.count += 3;
        this.loading = false;
      }, 1000);
    },
  },
};
</script>

<style lang="less">
#app {
  .infinite-list {
    height: 300px;
    width: 500px;
    border: 1px solid red;
    li {
      height: 50px;
      background: #e8f3fe;
      margin: 10px;
      color: #7dbcfc;
      text-align: center;
      line-height: 50px;
    }
    .text {
      color: green;
      text-align: center;
      line-height: 50px;
    }
  }
}
</style>

./components/v-infinite-scroll/index.js

import { checkArriveBottom } from "./utils";
export default {
  install(Vue) {
    Vue.directive("infinite-scroll", {
      // 指令在插入的时候会执行一次
      inserted: function (el, binding, vnode) {
        const fn = binding.value;
        const context = vnode.context;
        let timer = null;
        // 指令的值必须是一个函数,我们好执行回调
        if (typeof fn != "function") {
          throw new Error("指令value必须为函数");
        }
        // 事件处理函数
        function handleScroll() {
          // 判断滚动条到达底部了,才开始执行回调
          if (checkArriveBottom(el)) {
            // 执行回调的时候,要把this指向组件实例
            fn.bind(context)();
          }
        }
        // 将滚动处理函数挂载到对应组件实例上面,便于组件更新的时候,对设置了loading和complate属性进行移除事件绑定
        context.handleScroll = handleScroll;
        // 如果设置有immediate说明立即执行,则立即执行回调,直到将内容撑满内容区
        if (binding?.modifiers?.immediate) {
          timer = setInterval(() => {
            // 子元素的总高度大于设置指令的父级包裹元素就表示填满了可视区,停止加载
            const childScrollHeight = el.firstElementChild.scrollHeight;
            if (childScrollHeight >= el.clientHeight) {
              return clearInterval(timer);
            }
            handleScroll();
          }, 1500);
        }
        // 绑定滚动处理函数
        el.addEventListener("scroll", context.handleScroll);
      },
      //   组件更新的时候,会不断触发(最明显就是data中的响应式数据变化,会继续执行update方法)
      update(el, binding, vnode) {
        const context = vnode.context;
        // 如果加载中或者已经加载完了,就移除滚动事件
        if (
          (binding?.modifiers?.complated && context.complated) ||
          (binding?.modifiers?.loading && context.loading)
        ) {
          el.removeEventListener("scroll", context.handleScroll);
        } else {
          // 当loading和complate都是false的时候,表示可以继续加载
          el.addEventListener("scroll", context.handleScroll);
        }
      },
    });
  },
};

./components/v-infinite-scroll/utils.js

/**
 * @Description 用于判断滚动条是否到达底部
 * @param { Element }
 * @return { Boolean }
 **/
export function checkArriveBottom(el) {
  const clientHeight = el.clientHeight;
  const scrollTop = el.scrollTop;
  const scrollHeight = el.scrollHeight;
  //可以设置>=就行,这里也可以设置距离底部一定距离,自定义,不一定非要到达底部
  return clientHeight + scrollTop >= scrollHeight;
}

./components/v-infinite-scroll/main.js

import Vue from "vue";
import App from "./App.vue";
import vInfiniteScroll from "./components/v-infinite-scroll";
Vue.use(vInfiniteScroll);
Vue.use(myUi);
new Vue({
  render: (h) => h(App),
}).$mount("#app");

总结

完成上述指令,需要先阅读官网自定义指令文档,搞懂具体指令的一些钩子函数的用途以及触发时机,还有就是参数的意义,链接放这里cn.vuejs.org/v2/guide/cu…

到此这篇关于手写vue无限滚动指令的文章就介绍到这了,更多相关vue无限滚动指令内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • nuxt.js 缓存实践

    nuxt.js 缓存实践

    这篇文章主要介绍了nuxt.js 缓存实践,nuxt 的缓存可以分为 组件级别缓存 , API级别缓存 以及 页面级别缓存,本文就详细的介绍了这三种缓存,感兴趣的小伙伴们可以参考一下
    2018-06-06
  • vue实现监控视频直播的示例代码

    vue实现监控视频直播的示例代码

    本文主要介绍了vue实现监控视频直播的示例代码,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2022-05-05
  • layui实际项目使用过程中遇到的兼容性问题及解决

    layui实际项目使用过程中遇到的兼容性问题及解决

    这篇文章主要介绍了layui实际项目使用过程中遇到的兼容性问题及解决方案,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2023-04-04
  • 解决element-ui el-drawer抽屉el-dialog弹框关闭优化demo

    解决element-ui el-drawer抽屉el-dialog弹框关闭优化demo

    这篇文章主要为大家介绍了解决element-ui el-drawer抽屉el-dialog弹框关闭优化demo,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪<BR>
    2023-06-06
  • 8个非常实用的Vue自定义指令

    8个非常实用的Vue自定义指令

    这篇文章主要介绍了8个非常实用的Vue自定义指令,帮助大家更好的理解和使用vue,感兴趣的朋友可以了解下
    2020-12-12
  • vue页面加载闪烁问题的解决方法

    vue页面加载闪烁问题的解决方法

    这篇文章主要介绍了vue页面加载闪烁问题的解决方法,文中给大家提到了v-if 和 v-show 的区别,解决vue页面加载时出现{{message}}闪退的两种方法,感兴趣的朋友一起看看吧
    2018-03-03
  • vue-property-decorator用法详解

    vue-property-decorator用法详解

    这篇文章主要介绍了vue-property-decorator用法详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-12-12
  • Element Table 自适应高度的实现示例

    Element Table 自适应高度的实现示例

    el-table的高度不能适应不同电脑的分辨率,也不能跟随浏览器的高度变化而变化的问题,本文就来解决一下Element Table 自适应高度,感兴趣的可以了解一下
    2024-07-07
  • Vue+element使用row-class-name修改el-table某一行解决背景色无效的方法

    Vue+element使用row-class-name修改el-table某一行解决背景色无效的方法

    本文主要介绍了Vue+element使用row-class-name修改el-table某一行解决背景色无效的方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-01-01
  • vue.js移动端app之上拉加载以及下拉刷新实战

    vue.js移动端app之上拉加载以及下拉刷新实战

    这篇文章主要介绍了vue.js移动端app之上拉加载以及下拉刷新实战,非常具有实用价值,需要的朋友可以参考下
    2017-09-09

最新评论