我有这段代码,它完全按照我想要的方式工作。菜单栏位于顶部,并识别它所在的部分。您可以单击黄色菜单中的链接在各节之间移动。
演示:http://jsfiddle.net/spadez/2atkZ/9/和http://jsfiddle.net/spadez/2atkZ/9/embedded/result/
$(function () {
var $select = $('#select');
var $window = $(window);
var isFixed = false;
var init = $select.length ? $select.offset().top : 0;
$window.scroll(function () {
var currentScrollTop = $window.scrollTop();
if (currentScrollTop > init && isFixed === false) {
isFixed = true;
$select.css({
top: 0,
position: 'fixed'
});
$('body').css('padding-top', $select.height());
} else if (currentScrollTop <= init) {
isFixed = false;
$select.css('position', 'relative');
$('#select span').removeClass('active');
$('body').css('padding-top', 0);
}
//active state in menu
$('.section').each(function(){
var eleDistance = $(this).offset().top;
if (currentScrollTop >= eleDistance-$select.outerHeight()) {
var makeActive = $(this).attr('id');
$('#select span').removeClass('active');
$('#select span.' + makeActive).addClass('active');
}
});
});
$(".nav").click(function (e) {
var divId = $(this).data('sec');
$('body').animate({
scrollTop: $(divId).offset().top - $select.height()
}, 500);
});
});
然而,一旦您开始将任何内容放入框中,代码本身就会变得相当滞后。根据我收到的帮助,这是我通过动画反复改变页面布局属性,并在滚动处理程序中查询页面布局属性,从而触发大量的强制布局。
用户Tibos说:您可以通过禁用滚动处理程序来获得很大的改进点击动画,而不是触发没有检查的效果制作(在被点击的元素上设置活动类)
谁能告诉我如何才能实现这个优化?
演示页面和另一个概念演示:http://codepen.io/vsync/pen/Kgcoa
这里的关键是将你的select
放置在另一个元素中,所以当它被固定到屏幕上时,它不会因为突然缺乏高度而影响其他元素。我还添加了一些CSS。使用jQuery 1.11或更高版本是很重要的,因为它们修正了导致同一个类被一次又一次添加的但是,而不管一个元素是否已经有了它。对性能不利。此外,我在section元素上使用了for
循环而不是jquery each
循环,因为for循环由于缺少each
函数回调而更快。另外,很重要的一点是要确保每个可以被缓存的元素都被缓存了,这样我们就不会在DOM中没完没了地寻找它了。
为了显示我们在哪个部分,我循环所有的部分,从最后一个开始,这是很重要的,并检查每个顶部是否已经通过窗口的顶部使用getBoundingClientRect
方法来知道这样的事情。这有助于知道我们在哪里。
var pos,
$el = $('#select'),
navItems = $el.find('.nav'),
menuHeight = $el[0].clientHeight,
scrollY,
sections = $('.section').toArray(), // cache sections elements
pointOfAttachment = $('.jumbo')[0].clientHeight - menuHeight;
// Bind events
$(window).on('scroll.nav', updateNav)
.on('resize.nav', updateNav);
function updateNav(){
scrollY = window.pageYOffset || document.documentElement.scrollTop;
for( var i = sections.length; i--; ){
if( sections[i].getBoundingClientRect().top < 0 ){
navItems.filter('.' + sections[i].id).addClass('active').siblings().removeClass('active');
break;
}
navItems.removeClass('active');
}
if( scrollY > pointOfAttachment )
$el.addClass('fixed');
else
$el.removeClass('fixed');
}
为什么这是最优的?
获得良好性能的关键是尽可能少地实现您的目标,这里的"最小"意味着尽可能少地访问DOM,并且更改它的次数甚至比访问它的次数还要少。这是高度优化的代码,只在需要更改时更改DOM,而不会在任何其他情况下更改。
您不需要在每个scroll
事件上都这样做。您可以限制事件,每隔20毫秒才运行一次回调。用户不应该注意到。您可以使用下划线来完成此操作,或者编写您自己的解决方案。
另一个可以缓解延迟的方法是尽可能多地移出滚动事件回调。您不需要一直查询$('body')
,例如,将其保存为变量