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

目录
  • 概述
  • 最终效果
  • 实现原理
    • 关于高度计算的几个方法
      • clientHeigt
      • scrollHeight
      • scrollTop
    • 综上
  • 目录结构
    • App.vue
    • ./components/v-infinite-scroll/index.js
    • ./components/v-infinite-scroll/utils.js
    • ./components/v-infinite-scroll/main.js
  • 总结

概述

日常的开发当中,为了处理大量数据的情况,一般前端会采用分页展示,可以通过分页插件进行数据的按需分页请求展示,另一种解决大量数据的渲染的方式就是无限滚动,在移动端比较常见,也就是我们常见的滚动到底部加载更多数据,一般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无限滚动指令内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • 基于Vue实现卡片无限滚动动画

    目录 概要设计 详细设计 进阶功能 功能分析 概要设计 详细设计 完整代码 概要设计 设置css的animation在适当的时间点重置动画来现实视觉上无限滚动的效果. 详细设计 计算动画中所需预设的卡片dom节点个数(即视觉上最多能看到的卡片个数),如图1视窗高度为120px,卡片高度为56px,上下margin均为24px,因此一张卡片最多占据56+24*2=104px.当卡片处于视窗垂直居中的位置时,卡片上下各有(120-104)/2 = 8px的高度来承载其余卡片,因此所需预设卡片dom节

  • Vue.js 的移动端组件库mint-ui实现无限滚动加载更多的方法

    通过多次爬坑,发现了这些监听滚动来加载更多的组件的共同点, 因为这些加载更多的方法是绑定在需要加载更多的内容的元素上的, 所以是进入页面则直接触发一次,当监听到滚动事件之后,继续加载更多, 所以对于无限滚动加载不需要写首次载入列表的函数, 代码如下: html: //父组件 <div v-infinite-scroll="loadMore" infinite-scroll-disabled="loading" infinite-scroll-distance=

  • Vue 无限滚动加载指令实现方法

    也不存在什么加载咯, 就是一个判断滚动条是否到达浏览器底部了. 如果到了就触发事件,米到就不处理. 计算公式提简单的   底部等于(0) =  滚动条高度 - 滚动条顶部距离 - 可视高度.  反正结果就是0. 一.获取滚动条位置 class Scroll { static get top() { return Math.max(document.documentElement.scrollTop || document.body.scrollTop); } static get clientH

  • 详解无限滚动插件vue-infinite-scroll源码解析

    最近在项目中遇到一个需求,有一个列表需要滚动加载,类似于微博的无限滚动.当时第一反应时监听滚动事件,在判断滚动到达底部时加载下一页,同时心里也清楚,监听滚动事件需要做好截流.顺手搜索了下发现有一个现成的插件vue-infinite-scroll,用法也很简单,于是乎就用了起来. 需求上线后,对它的实现挺好奇的,于是研究了一番源码,这篇文章就是源码解析笔记. 插件使用方法 这是一个 vue 的指令,按照 github 仓库上的介绍,用法挺简单的,例如: <div class="app&quo

  • vue和iview实现Scroll 数据无限滚动功能

    在做项目的时候因为数据比较多,一次性全部渲染的话会花费较多的时间,所以,想到每一次渲染10条数据 也想过每一次获取十条数据然后显示就行了,就目前自己所知最好的方法是修改接口,一次返回10条,可是这样子太麻烦了,所以决定一次性请求所有数据,然后每次渲染十条,需要再上拉加载更多 使用的是iview中的组件Scroll 以下是获取数据和封装数据的方法: 原理是先定义两个全局的变量,一个存储全部的数据,一个存储渲染的数据 在首次获得数据的时候,往渲染的变量中存入全部数据的前十条: 然后在数据最底时上拉加

  • Vue.js 无限滚动列表性能优化方案

    问题 大家都知道,Web 页面修改 DOM 是开销较大的操作,相比其他操作要慢很多.这是为什么呢?因为每次 DOM 修改,浏览器往往需要重新计算元素布局,再重新渲染.也就是所谓的重排(reflow)和重绘(repaint).尤其是在页面包含大量元素和复杂布局的情况下,性能会受到影响.那对用户有什么实际的影响呢? 一个常见的场景是大数据量的列表渲染.通常表现为可无限滚动的无序列表或者表格,当数据很多时,页面会出现明显的滚动卡顿,严重影响了用户体验.怎么解决呢? 解决方案 既然问题的根源是 DOM

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

    目录 概述 最终效果 实现原理 关于高度计算的几个方法 clientHeigt scrollHeight scrollTop 综上 目录结构 App.vue ./components/v-infinite-scroll/index.js ./components/v-infinite-scroll/utils.js ./components/v-infinite-scroll/main.js 总结 概述 日常的开发当中,为了处理大量数据的情况,一般前端会采用分页展示,可以通过分页插件进行数据的按

  • 简单方法实现Vue 无限滚动组件示例

    目录 1. 前言 2. 整体思路 开始 3. 钩子函数 3.1 获取偏移初始位置的像素值 3.2 获取开始滚动和结束滚动的钩子函数 4. 完整代码 1. 前言 对于列表类型的大量数据,前端展示往往采用 分页 和 无限滚动 的方式来展示,对于用户来说,鼠标滚轮和触控屏使滚动行为要比点击更快更容易. element-plus 组件库提供了简单的 vue 指令,就可以轻易的实现 但是 element-plus 只支持无限向下滚动,不支持无限向上滚动,同时也没缺少丰富的 钩子函数,我们无法在这个基础上更

  • 手写Vue内置组件component的实现示例

    目录 前言 内置组件component的使用 component组件的原理分析 虚拟DOM与原生DOM render函数的使用 尝试手写实现component 总结 最近在复习Vue的源码,今天带大家手写实现一下Vue内置组件component,比较简单,最近面试有被问到. 前言 Vue大家都很熟悉,除了原生的组件,其自己也封装了一下内置组件,比如component,transition,keep-alive等等. component算是用的比较多的了,当我们遇到需要根据不同条件显示不同组件的时

  • 手写Vue源码之数据劫持示例详解

    源代码: 传送门 Vue会对我们在data中传入的数据进行拦截: 对象:递归的为对象的每个属性都设置get/set方法 数组:修改数组的原型方法,对于会修改原数组的方法进行了重写 在用户为data中的对象设置值.修改值以及调用修改原数组的方法时,都可以添加一些逻辑来进行处理,实现数据更新页面也同时更新. Vue中的响应式(reactive): 对对象属性或数组方法进行了拦截,在属性或数组更新时可以同时自动地更新视图.在代码中被观测过的数据具有响应性 创建Vue实例 我们先让代码实现下面的功能:

  • 手写Vue弹窗Modal的实现代码

    Vue作为最近最炙手可热的前端框架,其简单的入门方式和功能强大的API是其优点.而同时因为其API的多样性和丰富性,所以他的很多开发方式就和一切基于组件的React不同,如果没有对Vue的API(有一些甚至文档都没提到)有一个全面的了解,那么在开发和设计一个组件的时候有可能就会绕一个大圈子,所以我非常推荐各位在学习Vue的时候先要对Vue核心的所有API都有一个了解.这篇文章我会从实践出发,遇到一些知识点会顺带总结一下.文章很长,一次看不完可以先收藏,如果你刚入门vue,那么相信这篇文章对你以后

  • 如何手写一个简易的 Vuex

    前言 本文适合使用过 Vuex 的人阅读,来了解下怎么自己实现一个 Vuex. 基本骨架 这是本项目的src/store/index.js文件,看看一般 vuex 的使用 import Vue from 'vue' import Vuex from './myvuex' // 引入自己写的 vuex import * as getters from './getters' import * as actions from './actions' import state from './stat

  • 手写Vue2.0 数据劫持的示例

    一:搭建webpack 简单的搭建一下webpack的配置.新建一个文件夹,然后init一下.之后新建一个webpack.config.js文件,这是webpack的配置文件.安装一下简单的依赖. npm install webpack webpack-cli webpack-dev-server -D 在同级目录下新建一个public/index.html和src/index.js,作为出口文件和入口文件. j简单配置一下webpack, 在webpack.config.js文件中: cons

  • 手写vite插件教程示例

    目录 前言 1. 什么是 vite 插件 2. 为什么要写 vite 插件 创建  vite 插件通用模板 1. 初始化 2. 配置 eslint 和 prettier(可选) 3. 新增 src/index.ts 入口 4. 创建 examples 目录 5. 配置 examples/vite-vue3 项目 6. 安装 tsup 配置运行命令 7. 开发环境运行 8. 发布 vite 的插件钩子 hooks 们 1. vite 独有的钩子 2. vite 与 rollup 的通用钩子之构建阶

随机推荐