不管是 web 端还是移动端,信息流都是现在很流行的信息展示方式。信息流经常搭配自动加载一起使用以获得更好的使用体验。

最近在使用 Vue 开发过程中也遇到了首页信息流自动加载的需求。大致了解了一下几个滚动自动加载组件,发现多数都是把内容放在在一个单独的滚动容器内;但我遇到的需求是整个页面的滚动(博客列表首页那种),不是限制在容器内,不太符合。把整个页面放进滚动容器明显很奇怪,只是为了一个简单的下拉加载不值当。所以参考网上的一些介绍实现了一个几十行的简单小组件 ButtomDetector 来实现这个功能,同时也方便在多个需要到底自动加载的页面中进行复用。

实现原理

实现原理非常简单:

  • 监听页面的滚动事件
  • 在触发滚动时,调用 DOM api 来获取页面的滚动状态
  • 如果已经滚动到底,抛出事件供页面使用

JS 事件监听

// 监听 scroll 事件,绑定回调函数
window.addEventListener('scroll', this.listenBottomOut) // 取消事件监听
window.removeEventListener('scroll', this.listenBottomOut, false)

页面滚动状态

DOM 提供了获取页面元素滚动状态的相关属性,这里主要用到以下三个:scrollHeight 滚动内容高度,scrollTop 滚动内容顶部离显示区域的距离,clientHeight 显示区域高度。如下图所示。

因此,判断滚动到底就很简单了:

if (scrollTop + clientHeight >= scrollHeight - delta) {
// emit bottom event
}

其中 delta 的作用是可以在快到底端(例如还有50px)时提前进行加载,避免拉到底后等待加载的这段时间。

一些细节问题

重复抛出事件

因为监听的是 scroll 事件,并且使用 delta 做了一点提前加载,因此可能会触发多次触底事件(距离底部48px, 30px, 12px... 都符合判断条件),造成页面重复多次加载数据。因此选择在组件中增加一个 loadingMore 属性,表示父页面正在加载数据,此时不再继续抛出事件;当页面完成加载后,将 loadingMore 重置为 false 以继续监听触底。

没有更多数据

在信息流已经到底,没有更多数据的时候,触底事件就没有作用了。当然这个判断也可以在父页面中进行,当没有更多数据时不再继续处理触底事件;不过为了方便页面中的加载数据方法(不用每次都单独判断是否有更多),给组件增加一个 noMore 参数,此时不再抛出触底事件。

代码实现

bottomDetector 组件

<template>
<div style="text-align: center">
<div v-if="loadingMore">加载中</div>
<div v-if="noMore">没有更多了</div>
</div>
</template>
<script>
export default {
props: {
loadingMore: {
type: Boolean,
required: true,
},
distance: {
type: Number,
default: 50,
},
noMore: {
type: Boolean,
default: false,
},
},
mounted() {
window.addEventListener('scroll', this.listenBottomOut)
this.element = document.documentElement
},
destroyed() {
window.removeEventListener('scroll', this.listenBottomOut, false)
},
data() {
return {
element: null,
}
},
methods: {
listenBottomOut() {
if (this.noMore || this.loadingMore) return
let scrollTop = this.element.scrollTop || document.body.scrollTop
let clientHeight = this.element.clientHeight
let scrollHeight = this.element.scrollHeight
if (scrollTop + clientHeight >= scrollHeight - this.distance) {
this.$emit('arriveBottom')
}
},
},
}
</script>

页面使用

从触底功能上来说,detector 组件放在页面中的任何位置都可以。放在信息流下方的话还可以顺便做加载动画和信息到底的提示信息。

<div class="infos">
<div v-for="item in infos" :key="item.id">
<!-- info -->
</div>
</div>
<bottom-detector
:loadingMore="infosLoadingMore"
:noMore="infos.length >= infoTotal"
@arriveBottom="getMoreInfo"
/>
</div>
getMoreInfo() {
this.infosLoadingMore = true
// loading more info
this.infosLoadingMore = false
},

结语

以上是简单的 Vue 页面触底加载组件的原理及实现,希望对你有所帮助,欢迎在评论区进行讨论或指正。

监听事件函数部分参考了博客:触底加载更多(原理 + 在vue中的使用)

前端 | 页面触底自动加载 Vue 组件的更多相关文章

  1. 页面滚动动态加载数据,页面下拉自动加载内容 jquery

    <!DOCTYPE=html> <html> <head> < script src="js/jquery.js" type=" ...

  2. Jquery页面滚动动态加载数据,页面下拉自动加载内容

    <!DOCTYPE=html> <html> <head> <script src="js/jquery.js" type="t ...

  3. require.js 加载 vue组件 r.js 合并压缩

    https://www.taoquns.com 自己搭的个人博客 require.js 参考阮一峰 Javascript模块化编程(三):require.js的用法 r.js 合并压缩 参考司徒正美 ...

  4. AngularJS 实现页面滚动到底自动加载数据的功能

    要实现这个功能,可以通过https://github.com/sroze/ngInfiniteScroll这个第三方控件来实现.步骤如下: 1. 下载ng-infinite-scroll.js程序ht ...

  5. Vue 去脚手架插件,自动加载vue文件,style怎么办

    书接上上会,因为当时也没想好怎么办,所以装聋作哑的忽略了Vue文件中的Style,Vue的做法我看着晕乎乎的,细想的话,无非就是自动填写到dom中,所担心的无非是命名冲突. 在一个项目中(像我这种自娱 ...

  6. AngularJS:实现页面滚动到底自动加载数据的功能

    要实现这个功能,可以通过https://github.com/sroze/ngInfiniteScroll这个第三方控件来实现.步骤如下: 1. 下载ng-infinite-scroll.js程序ht ...

  7. Android打造(ListView、GridView等)通用的下拉刷新、上拉自动加载的组件

    原文 http://blog.csdn.net/bboyfeiyu/article/details/39253051       前言 下 拉刷新组件在开发中使用率是非常高的,基本上联网的APP都会采 ...

  8. Vue 去脚手架插件,自动加载vue文件

    接上回 一些本质 本质上,去脚手架也好,读取vue文件也好,无非是维护options,每个Vue对象的初始化配置对象不触及Vue内部而言,在外部想怎么改都是可以的,只要保证options的正确,一切都 ...

  9. 如何自动加载scratch3.0的页面上实现自动加载原有的作品

    首先,我们在安装scratch3.0后,浏览器默认打开的是编程的页面.如下图: 那么我们希望开发一个功能,就是打开的时候默认加入某一个SB3的开发文件 1.首先,我们需要有一个.SB3的开发文件,建议 ...

随机推荐

  1. 小猿圈-IT自学人的小圈子 【强力推荐学习】

    笔记链接 https://book.apeland.cn/details/322/ 学习视频 https://www.apeland.cn/python

  2. Java多线程(上)

    Java多线程 程序.进程和线程 一.程序 程序是存储在磁盘上, 包含可执行机器指令和数据的静态实体. 即进程或者任务是处于活动状态的计算机程序. 二.进程 进程是资源(CPU.内存等)分配的基本单位 ...

  3. 计算机基础-Socket

    计算机基础-Socket 当时明月在,曾照彩云归. 简介:计算机基础-Socket 一.I/O 模型 一个输入操作通常包括两个阶段: 等待数据准备好 从内核向进程复制数据 对于一个套接字上的输入操作, ...

  4. 【游记】OI 2020-2021(在更)

    [CSP-S2020初赛] [CSP-S2020] [NOIp 2020] [NOI冬令营 2021] [省选 2021] [NOI 2021]

  5. 第十三天 -- 如何用U盘重装系统Win10以及如何用VMware12安装Win10

    U盘制作启动盘 1.在电脑上插入U盘,关闭安全软件杀毒工具,然后打开装机吧U盘启动盘制作工具 2.选择刚插入的U盘,勾选上,点击一键制作启动U盘,制作前U盘数据必须转移备份: 3.选择格式化U盘,记得 ...

  6. 最长公共子序列问题(LCS)——Python实现

      # 最长公共子序列问题 # 作用:求两个序列的最长公共子序列 # 输入:两个字符串数组:A和B # 输出:最长公共子序列的长度和序列 def LCS(A,B): print('输入字符串数组A', ...

  7. Python - 解包的各种骚操作

    为什么要讲解包 因为我觉得解包是 Python 的一大特性,大大提升了编程的效率,而且适用性很广 啥是解包 个人通俗理解:解开包袱,拿出东西 正确理解:将元素从可迭代对象中一个个取出来 python ...

  8. 使用C#winform编写渗透测试工具--SQL注入

    使用C#winform编写渗透测试工具--SQL注入 本篇文章主要介绍使用C#winform编写渗透测试工具,实现SQL注入的功能.使用python编写SQL注入脚本,基于get显错注入的方式进行数据 ...

  9. Vue-Promise

    promise 就是一种异步编程的的解决方案 当执行网络请求的时候,代码就会出现阻塞,下面的代码要等待请求完成了在运行,所以我们一般网络请求的时候就去开启一个异步任务,一边请求一边执行其他代码 请求到 ...

  10. 040_Spring注解开发

    目录 Spring注解开发 bean注册到Spring容器中 applicationContext.xml添加包扫描注解 实体类添加注解@Component 属性注入 属性添加注解@Value(&qu ...