更有效的方式来处理jQuery中的$(窗口).scroll函数?

在下面的代码中,我正在检查窗口是否正在滚动到某个点,如果是,请将元素更改为使用固定位置,以便它不会从页面的顶部滚动。 唯一的问题是,似乎是高度客户端内存密集型(并真正陷入滚动速度),因为在每一个滚动像素,我更新元素上的样式属性。

在尝试更新attr之前检查attr是否已经存在,是否有重大区别? 是否有一个完全不同的,更有效的做法来获得相同的结果?

$(window).scroll(function () { var headerBottom = 165; var fcHeight = $("#pnlMainNavContainer").height(); var ScrollTop = $(window).scrollTop(); if (ScrollTop > headerBottom) { $("#HeaderContentBuffer").attr("style", "margin-top:" + (fcHeight) + "px;"); $("#AddFieldsContainer").attr("style", "position:fixed;width:320px;top:70px;left:41px;"); } else { $("#HeaderContentBuffer").attr("style", "margin-top: 0px;"); $("#AddFieldsContainer").removeAttr("style"); } }); 

正如我input这个,我注意到,StackOverflow.com使用相同types的function与他们的黄色“类似的问题”和“帮助”菜单在这个页面的右侧。 我想知道他们是如何做到的。

您可以使用的一种技术是在滚动事件上设置定时器,并且只在滚动位置在短时间内没有改变时才执行主要工作。 我在resize事件时使用了这个技巧,这个事件有相同的问题。 你可以尝试什么超时值似乎是正确的。 时间越短,滚动中的停顿越短,因此在滚动期间可以更频繁地运行,更长的时间要求用户实际上将所有运动暂停有意义的时间。 你将不得不尝试什么超时值最适合你的目的,最好是在相对较慢的计算机上testing,因为这是滚动滞后问题最显着的地方。

以下是可以如何实现的一般概念:

 var scrollTimer = null; $(window).scroll(function () { if (scrollTimer) { clearTimeout(scrollTimer); // clear any previous pending timer } scrollTimer = setTimeout(handleScroll, 500); // set new timer }); function handleScroll() { scrollTimer = null; var headerBottom = 165; var fcHeight = $("#pnlMainNavContainer").height(); var ScrollTop = $(window).scrollTop(); if (ScrollTop > headerBottom) { $("#HeaderContentBuffer").attr("style", "margin-top:" + (fcHeight) + "px;"); $("#AddFieldsContainer").attr("style", "position:fixed;width:320px;top:70px;left:41px;"); } else { $("#HeaderContentBuffer").attr("style", "margin-top: 0px;"); $("#AddFieldsContainer").removeAttr("style"); } } 

您也可以通过在滚动首次启动时caching一些select器来加快滚动function,这样就不必每次都重新计算。 这是一个地方,每次创build一个jQuery对象的额外开销可能不会帮助你。


这里有一个jQuery插件方法来处理你的滚动计时器:

 (function($) { var uniqueCntr = 0; $.fn.scrolled = function (waitTime, fn) { if (typeof waitTime === "function") { fn = waitTime; waitTime = 500; } var tag = "scrollTimer" + uniqueCntr++; this.scroll(function () { var self = $(this); var timer = self.data(tag); if (timer) { clearTimeout(timer); } timer = setTimeout(function () { self.removeData(tag); fn.call(self[0]); }, waitTime); self.data(tag, timer); }); } })(jQuery); 

工作演示: http : //jsfiddle.net/jfriend00/KHeZY/

你的代码将会像这样被执行:

 $(window).scrolled(function() { var headerBottom = 165; var fcHeight = $("#pnlMainNavContainer").height(); var ScrollTop = $(window).scrollTop(); if (ScrollTop > headerBottom) { $("#HeaderContentBuffer").attr("style", "margin-top:" + (fcHeight) + "px;"); $("#AddFieldsContainer").attr("style", "position:fixed;width:320px;top:70px;left:41px;"); } else { $("#HeaderContentBuffer").attr("style", "margin-top: 0px;"); $("#AddFieldsContainer").removeAttr("style"); } }); 

我发现这个方法对于$(window).scroll()更有效率

 var userScrolled = false; $(window).scroll(function() { userScrolled = true; }); setInterval(function() { if (userScrolled) { //Do stuff userScrolled = false; } }, 50); 

看看John Resig关于这个话题的post 。

更高性能的解决scheme是设置一个更长的时间间隔,以检测您是否接近页面的底部或顶部。 这样,你甚至不必使用$(window).scroll()

让你的function更高效一点。

在删除/添加样式之前,检查样式​​属性是否存在/不存在。

 $(window).scroll(function () { var headerBottom = 165; var fcHeight = $("#pnlMainNavContainer").height(); var ScrollTop = $(window).scrollTop(); if (ScrollTop > headerBottom) { if (!$("#AddFieldsContainer").attr("style")) { $("#HeaderContentBuffer").attr("style", "margin-top:" + (fcHeight) + "px;"); $("#AddFieldsContainer").attr("style", "position:fixed;width:320px;top:70px;left:41px;"); } } else { if ($("#AddFieldsContainer").attr("style")) { $("#HeaderContentBuffer").attr("style", "margin-top: 0px;"); $("#AddFieldsContainer").removeAttr("style"); } } }); 

在这里设置一些逻辑。 你实际上需要一次设置atts,一次设置。 所以:

 var checker = true; $(window).scroll(function () { ....... if (ScrollTop > headerBottom && checker == true) { $("#HeaderContentBuffer").attr("style", "margin-top:" + (fcHeight) + "px;"); $("#AddFieldsContainer").attr("style", "position:fixed;width:320px;top:70px;left:41px;"); checker == false; } else if (ScrollTop < headerBottom && checker == false) { $("#HeaderContentBuffer").attr("style", "margin-top: 0px;"); $("#AddFieldsContainer").removeAttr("style"); checker == true; } });