scroll事件的优化以及scrollTop的兼容性
scrollTop的兼容性
scroll事件,当用户滚动带滚动条的元素中的内容时,在该元素上面触发。<body>元素中包含所加载页面的滚动条。
虽然scroll事件是在window对象上发生,但他实际表示的则是页面中相应元素的变化。在混杂模式(document.compatMode的值为BackCompat)下,可以通过<body>元素的scrollLeft和scrollTop来监控到这一变化。
而在标准模式(document.compatMode的值为CSS1Compat)下,除Safari之外的所有浏览器都会通过<html>元素来反应这一变化。
以上内容来自《Javascript 高级程序设计(第三版)》。
以下是我自己测试的结果,截止2017-05-18,用的是最新版的chrome、Firefox和Win7中的IE。
- 混杂模式下,chrome、IE、Firefox都是通过document.body.scrollTop监听滚动条的位置。
- 标准模式下,chrome通过document.body.scrollTop监听滚动条位置,IE和Firefox通过document.documentElement.scrollTop监听滚动条位置
可以用下面的代码进行验证:
function outPutScrollTop() {
console.log(document.compatMode);
if(document.compatMode === 'CSS1Compat') {
console.log(document.documentElement.scrollTop + '标准模式');
console.log(document.body.scrollTop + '标准模式');
} else {
console.log(document.body.scrollTop + '混杂模式');
}
}
// 绑定监听
window.addEventListener('scroll', outPutScrollTop);
(去掉文档头部的文档声明就可以开启混杂模式。)
scroll事件的优化
scroll事件如果不做优化,默认情况下会频繁地被触发,如果在事件处理程序内进行了复杂的DOM操作,就会大大增加浏览器的负担,消耗性能。
通过看别人的文章,知道了可以通过防抖函数和节流函数对这种频繁触发的事件进行优化。
防抖函数达成的效果是:scroll事件被频繁触发时,不会每次都执行事件处理程序中的关键代码,当滚动条停止滚动时,经过事先设置好的时间间隔后才会执行真正想要执行的代码。
节流函数不像防抖函数那样只在用户停止滚动时才执行事件处理程序中的关键代码,而是在用户滚动滚动条的过程中每隔一定的时间必执行一次事件处理程序中的关键代码。
以下是对别人文章的总结。
防抖函数
简单的防抖优化:
function test() {
console.log('func');
} window.addEventListener('scroll',function(event) {
clearTimeout(test.timer);
test.timer = setTimeout(test,500);
},false);
将上面的代码封装成一个函数:
function debounce(fun,t,immediate) {
var timeout;
//返回真正的scroll事件的事件处理程序
return function(event) {
var that = this, arg = arguments;
var later = function() {
timeout = null;
if(!immediate) fun.apply(that,arguments);
};
var callNow = immediate && !timeout;//这一句位置很重要
clearTimeout(timeout);
timeout = setTimeout(later,t);
if(callNow) {
fun.apply(that,arguments);
}
}
};
debounce函数接收三个参数:
第一个参数是一个函数,该函数是事件处理程序中真正想要执行的代码。
第二个参数是数字,单位毫秒,表示间隔多久调用一次作为第一个参数的函数。这个参数不能小于当前浏览器的最小时间间隔(不同的浏览器的最小时间间隔不同,一般在10~20毫秒,HTML5规范中规定是4毫秒),如果这个参数等于或小于这个最小时间间隔,那么和没有优化没有区别。事实上,未优化时,scroll事件频繁触发的时间间隔也是这个最小时间间隔。
第三个参数是一个布尔值,不传或为false时,最终的效果与开始那个简单的防抖优化的效果一样;当为true时,表示滚动开始时执行一次作为第一个参数的函数,滚动停止时不执行。
用法:
var myEfficientFn = debounce(function() {
// 滚动中的真正想要执行的代码
console.log('ok' + new Date());
}, 500, false); // 绑定监听
window.addEventListener('scroll', myEfficientFn);
下面是underscore.js里封装的防抖函数:
// Returns a function, that, as long as it continues to be invoked, will not
// be triggered. The function will be called after it stops being called for
// N milliseconds. If `immediate` is passed, trigger the function on the
// leading edge, instead of the trailing.
_.debounce = function(func, wait, immediate) {
var timeout, args, context, timestamp, result; var later = function() {
var last = _.now() - timestamp; if (last < wait && last >= 0) {
timeout = setTimeout(later, wait - last);
} else {
timeout = null;
if (!immediate) {
result = func.apply(context, args);
if (!timeout) context = args = null;
}
}
}; return function() {
context = this;
args = arguments;
timestamp = _.now();
var callNow = immediate && !timeout;
if (!timeout) timeout = setTimeout(later, wait);
if (callNow) {
result = func.apply(context, args);
context = args = null;
} return result;
};
};
节流函数
简单的节流函数:
function throttle(fun,t,mustRun,denyLast) {
var timer = null;
var startTime = 0;
return function(event) {
var that = this, args = arguments;
clearTimeout(timer);
var later = function() {
timer = null;
if(denyLast) fun.apply(that,args);
console.log('执行的是later.');
};
var currTime = new Date().getTime();
if(currTime - startTime >= mustRun) {
console.log(currTime - startTime);
fun.apply(that,args);
startTime = currTime;
} else {
timer = setTimeout(later,t);
}
};
}
这个节流函数的整体结构与防抖函数的类似,相比防抖函数,节流函数内部多了一个对时间间隔的判断。
上面这个节流函数接收四个参数:
第一个参数是一个函数,表示当scroll事件被触发时,开发者真正想要执行的关键代码。
第二个参数是一个数字,单位毫秒,实际上是要传入setTimeout()方法的第二个参数。(这里setTimeout()的作用就是防止事件处理程序中的关键代码频繁地执行)
第三个参数也是一个数字,单位毫秒,表示在该时间段内必执行一次关键代码。
第四个参数是一个布尔值,表示在滚动停止时,是否要执行一次关键代码。true表示执行,false表示不执行。
在上面的节流函数中,因为startTime是在外部函数中初始化的,所以滚动开始时必会执行一次关键代码。
节流函数的用法示例:
var myEfficientFn = throttle(function() {
// 滚动中的真正想要执行的代码
console.log('ok' + new Date());
}, 500,1000,false); // 绑定监听
window.addEventListener('scroll', myEfficientFn);
//或者这样,效果是一样的
window.addEventListener('scroll',throttle(function() {
// 滚动中的真正想要执行的代码
console.log('ok' + new Date());
}, 500,1000,false));
underscore.js里封装的节流函数:
// Returns a function, that, when invoked, will only be triggered at most once
// during a given window of time. Normally, the throttled function will run
// as much as it can, without ever going more than once per `wait` duration;
// but if you'd like to disable the execution on the leading edge, pass
// `{leading: false}`. To disable execution on the trailing edge, ditto.
_.throttle = function(func, wait, options) {
var context, args, result;
var timeout = null;
var previous = 0;
if (!options) options = {};
var later = function() {
previous = options.leading === false ? 0 : _.now();
timeout = null;
result = func.apply(context, args);
if (!timeout) context = args = null;
};
return function() {
var now = _.now();
if (!previous && options.leading === false) previous = now;
var remaining = wait - (now - previous);
context = this;
args = arguments;
if (remaining <= 0 || remaining > wait) {
if (timeout) {
clearTimeout(timeout);
timeout = null;
}
previous = now;
result = func.apply(context, args);
if (!timeout) context = args = null;
} else if (!timeout && options.trailing !== false) {
timeout = setTimeout(later, remaining);
}
return result;
};
};
上面的防抖函数和节流函数可以应用到所有类似scroll事件这种频繁被触发的事件的优化,比如resize事件、键盘事件、鼠标滚轮事件等。
(完)
参考文章:
2.函数防抖与节流
3.setTimeout 和 setInterval最小执行时间问题
scroll事件的优化以及scrollTop的兼容性的更多相关文章
- 前端资讯周报 3.13 - 3.19: WebVR来了!以及如何优化scroll事件性能
每周一我都会分享上一周我订阅的技术站点中,和解决问题的过程中阅读到的值得分享的文章.这是迫使我学习的一个动力 本周推荐 Minecraft in WebVR with HTML Using A-Fra ...
- 如何提高scroll事件的性能
1. chrome devtool 是诊断页面滚动性能的有效工具 2. 提升滚动时性能,就是要达到fps高且稳. 3. 具体可以从以下方面着手 使用web worker分离无页面渲染无关的逻辑计算 触 ...
- 最优-scroll事件的监听实现
1. 背景和目标 前端在监听scroll这类高频率触发事件时,常常需要一个监听函数来实现监听和回调处理.传统写法上利用setInterval或setTimeout来实现. 为了减小 CPU 开支,往往 ...
- “如何稀释scroll事件”的思考(不小心写了个异步do...while)
看了下园友的一帖子:http://www.cnblogs.com/xzhang/p/4145697.html#commentform 本来以为是很简单的问题,但仔细想想还挺有意思的.简单的说就是增加事 ...
- jQuery scroll事件实现监控滚动条分页示例(转)
这篇文章主要介绍了jQuery scroll事件实现监控滚动条分页简单示例,使用ajax加载,同时介绍了(document).height()与$(window).height()的区别,需要的朋友可 ...
- scroll事件实现监控滚动条并分页显示示例(zepto.js)
scroll事件实现监控滚动条并分页显示示例(zepto.js ) 需求:在APP落地页上的底部位置显示此前其他用户的购买记录,要求此div盒子只显示3条半,但一页有10条,div内的滑动条滑到一页 ...
- JQUERY 滚动 scroll事件老忘记 标记下
制作笔记 这个scroll事件 老忘记.... 写的太垃圾了 希望有路过的大神指点的吧~ 这个貌似应该写个函数里 调用好些的吧~ 写个类这样的 也方便扩展貌似 不过就是想想 ~ $(windo ...
- jQuery scroll事件
scroll事件适用于window对象,但也可滚动iframe框架与CSS overflow属性设置为scroll的元素. $(document).ready(function () { //本人习惯 ...
- JavaScript中作用域回顾(避免使用全局变量)(瀑布流的实现)(scroll事件)以及Django自定义模板函数回顾
页面显示照片样式为瀑布流: 上面的div个数可以按照自己安排进行划分.img的分布可以使用模板标签以及自定义模板函数进行排布: 自定义模板函数实现可以看,最后几列:python---django中模板 ...
随机推荐
- 改变checkbox样式问题
选择1 选择2 选择3 选择4 选择5 <form action=""> <label for="test">选择1 <inp ...
- js自动小轮播
使用定时器,换个图片地址. 从1到5换,如果大于5了再跳到1,点击停止时关闭定时器. <!-- Author: XiaoWen Create a file: 2016-12-08 13:19:2 ...
- ZOJ 3469 Food Delivery(区间DP)
https://vjudge.net/problem/ZOJ-3469 题意:在一条直线上有一个餐厅和n个订餐的人,每个人都有随时间上升的不满意值,从餐厅出发,计算出送完时最小的不满意值总和. 思路: ...
- 使用rz,sz需要安装lrzsz
... tar zxvf lrzsz-1.12.20.tar.gz 4.进入目录 cd lrzsz-1.12.20 5../configure --prefix=/usr/local/lrzsz 6. ...
- C# 获取文件夹下的所有文件夹及其文件
//获得当前文件夹下所有文件夹 string path = "D://文件夹"; string[] dirstr = Directory.GetDirectories(path); ...
- C# asp.net 比较两个时间的差求天数
string str1 = "2017-2-13 23:59:59"; string str2 = "2017-2-14 0:00:01"; DateTime ...
- tyvj 1038 忠诚 区间最小值 线段树或者rmq
P1038 忠诚 时间: 1000ms / 空间: 131072KiB / Java类名: Main 描述 老管家是一个聪明能干的人.他为财主工作了整整10年,财主为了让自已账目更加清楚.要求管家每天 ...
- shell 求模
$ expr % $ let i=% $ echo $i $ echo % | bc $ ((i=%)) $ echo $i
- C++中int、string等常见类型转换
1.int型与string型的互相转换 最佳实践: int型转string型 void int2str(const int &int_temp,string &string_temp) ...
- Java EE、Java SE和Java ME
Java SE=Java Standard EditionJava EE=Java Enterprise EditionJava ME=Java Mobile Edition SE主要用于桌面程序,控 ...