最优-scroll事件的监听实现
1. 背景和目标
前端在监听scroll这类高频率触发事件时,常常需要一个监听函数来实现监听和回调处理。传统写法上利用setInterval或setTimeout来实现。
为了减小 CPU 开支,往往需要节流函数,但是,interval的指定依旧是个难题。interval较大,会处理不及时;较小,占用内存资源。
为了实践和解决问题,打算实现一个监听 HTML 元素滚动到底部的函数:
- 监听指定 HTML 元素的
scroll事件,并正确判断是否到底部- 正确确定确定回调间隔
- 正确使用节流函数
- 组件封装
2. window.requestAnimationFrame()
前文说到,如果利用
setTimeout或者setInterval,回调间隔interval很难确定。最理想的情况就是:回调间隔等于显示屏(浏览器)刷新频率。
浏览器刷新频率一般会略低于显示屏刷新频率,为16.7次/ms。具体说,就是:scroll事件每次触发时候的时间间隔。通过代码来看一下:
var app = document.getElementById("app");
app.addEventListener("scroll", function() {
console.log(new Date().getTime());
});
控制台输出:

可以看到,有时候间隔是 10ms,有时候是 30ms,如果我们自己来设定interval,应该取最小值。然而,不同浏览器和不同电脑的刷新频率不确定。如果设置过小,还会造成刷新频率低的显示屏的 CPU 损耗。
所以,使用window.requestAnimationFrame()来让浏览器根据刷新频率自动设置interval。我们只需要关注回调函数即可。
当然,这个函数本身还实现了很多优化,可以点我看一下。
3. 节流函数
由于window.requestAnimationFrame()的特效,所以它可以在同一帧中被重复绘制。这时候,就需要节流函数,保证requestAnimationFrame的回调队列中只有一个函数在执行。
// 节流函数 : 减少浏览器内存消耗
function throttle(ele, callback) {
var isRunning = false;
return function() {
if (isRunning) return;
isRunning = true;
// requestAnimationFrame:回调间隔 = 浏览器重绘频率
window.requestAnimationFrame(function(timestamp) {
if (ele.scrollTop + ele.clientHeight >= ele.scrollHeight) {
// 检测是否滚动到元素底部
callback();
}
isRunning = false;
});
};
}
4. 代码封装
函数封装详见script.js,调用样例详见index.html
基于上面,我们封装script.js:
// 节流函数 : 减少浏览器内存消耗
function throttle(ele, callback) {
var isRunning = false;
return function() {
if (isRunning) return;
isRunning = true;
// requestAnimationFrame:回调间隔 = 浏览器重绘频率
window.requestAnimationFrame(function(timestamp) {
if (ele.scrollTop + ele.clientHeight >= ele.scrollHeight) {
// 检测是否滚动到元素底部
callback();
}
isRunning = false;
});
};
}
/**
* 监听HTML元素是否滚动到底部 : 兼容ES5
* @param {object} ele HTML元素
* @param {function} callback 滚动到底部后的回调函数
*/
function listenScrollToBottom(ele, callback) {
if (ele === null || ele === undefined) {
// 节点不存在:抛出错误
throw new Error("Undefined COM");
return;
}
ele.addEventListener("scroll", throttle(ele, callback), false); // 监听 scroll 事件
}
将需要监听的 HTML 元素和回调函数传入,即可在 HTML 元素滚动到底部时,触发相应的操作。例如:瀑布流、缓冲加载等。下面是控制台输出一段文字。
<body>
<div id="app">
<div class="inner"></div>
</div>
<script>
var app = document.getElementById('app')
listenScrollToBottom(app , function() { // 回调函数
console.log("Scroll to bottom")
})
</script>
</body>
4. 关于
欢迎技术交流,引用请注明出处。
个人网站:董沅鑫的个人网站
原文链接:最优-scroll事件的监听实现
最优-scroll事件的监听实现的更多相关文章
- Spring Boot 事件和监听
Application Events and Listeners 1.自定义事件和监听 1.1.定义事件 package com.cjs.boot.event; import lombok.Data; ...
- uniapp仿h5+fire自定义事件触发监听
仿h5+fire自定义事件触发监听 uni-app调用 event.js 源码记录(点击查看) 1.js下载地址 [event.js](https://ext.dcloud.net.cn/plugin ...
- 事件的监听是由awt完成的
学swing 之前先学awt ,因为awt 是Java实现图形界面的基础. 它能够完成编写界面的基本功能,最重要的是,事件的监听是由awt完成的. 而swing是在awt基础上提供的新的界面工具包,它 ...
- 深入理解Spring的容器内事件发布监听机制
目录 1. 什么是事件监听机制 2. JDK中对事件监听机制的支持 2.1 基于JDK实现对任务执行结果的监听 3.Spring容器对事件监听机制的支持 3.1 基于Spring实现对任务执行结果的监 ...
- MVC框架入门准备(三)事件类 - 事件的监听和触发
在mvc框架中可以看到事件类,实现事件的监听和触发. 举例: <?php /** * 事件类 */ class Event { // 事件绑定记录 private static $events; ...
- Spring Boot(六)自定义事件及监听
事件及监听并不是SpringBoot的新功能,Spring框架早已提供了完善的事件监听机制,在Spring框架中实现事件监听的流程如下: 自定义事件,继承org.springframework.con ...
- 【spring源码学习】spring的事件发布监听机制源码解析
[一]相关源代码类 (1)spring的事件发布监听机制的核心管理类:org.springframework.context.event.SimpleApplicationEventMulticast ...
- PIE SDK矢量数据编辑事件的监听
1.功能简介 通过IEditEvents接口,开发者可以监听到Editor对象的相关的事件,并且做出反应.包括Editor中开始编辑.结束编辑等操作,下面对矢量数据的编辑事件的监听功能进行介绍. 2. ...
- PIE SDK元素事件的监听
1功能简介 元素在操作的过程中,如添加,删除,选中等操作都需要有事件的监听,PIE SDK支持对元素操作事件的监听,下面对元素事件的监听进行介绍. 2功能实现说明 2.1.1 实现思路及原理说明 第一 ...
随机推荐
- HSmartWindowControl之安装篇 (Visual Studio 2013 & Halcon 18)
1.环境简介 Visual Studio 2013社区版 Halcon18.05 2.使用Nuget在VS工程中安装Halcon插件 搜索栏输入关键字halcon,出现两个插件,分别是halcon语言 ...
- Input and Output File
Notes from C++ Primer File State Condition state is used to manage stream state, which indicates if ...
- JQuery Mobile - 固定住页面和页脚
在点击页面空白时候,页眉和页脚会隐藏,在页眉和页脚加入以下代码就可以了: data-tap-toggle ="false" 例子: <div data-role=" ...
- 使用tinymce富文本
1.tinymce入门参考 https://www.tiny.cloud/docs/general-configuration-guide/basic-setup/ 2.tinymce安装选项 htt ...
- 深圳scala-meetup-20180902(2)- Future vs Task and ReaderMonad依赖注入
在对上一次3月份的scala-meetup里我曾分享了关于Future在函数组合中的问题及如何用Monix.Task来替代.具体分析可以查阅这篇博文.在上篇示范里我们使用了Future来实现某种non ...
- 火狐浏览器安装 Modify Headers 插件
一.火狐浏览器插件安装 这里以火狐浏览器的Modify Headers插件安装为例,展示火狐插件的安装: 1.打开火狐浏览器,右上角选择“附加组件” 2.搜索Modify Headers插件 3.安装 ...
- javascript Navigator对象属性和方法
Navigator对象 Navigator 对象包含的属性描述了正在使用的浏览器.可以使用这些属性进行平台专用的配置.虽然这个对象的名称显而易见 的是 Netscape 的 Navigator 的浏览 ...
- D3.js的一些基础部分 (v3版本)
最近公司有需求要做一些可视化的功能.之前一直都是用Echarts做的,但是Echarts难以满足我们的需求,经过多方请教,查找发现D3可以满足我们的需求.第一次接触到D3,发现这些图标的可交互性非常丰 ...
- 【LeetCode】14. 最长公共前缀
题目 编写一个函数来查找字符串数组中的最长公共前缀.如果不存在公共前缀,返回空字符串 "". 示例 1:输入: ["flower","flow&quo ...
- [EXP]K8 jboss invoke deploy getshell exploit
MSF jboss invoke deploy EXPLOIT moudle Date:2013.11.28 Author:K8gege 改这个EXP中 过程有点不进人意 没能在一个payload里直 ...