我正在尝试使Bootstrap的scrollspy在响应迅速的站点上可靠地工作,该站点上的顶部导航栏的高度根据媒体/浏览器的宽度而变化。因此,不是通过硬编码data-offset
属性上的偏移量,而是通过Javascript初始化来动态设置它,如下所示:
$('body').scrollspy({ offset: 70, target: '#nav' });
对于较宽的布局(即Bootstrap -lg),它可以正常工作,但对于较窄的布局,似乎存在“累积”偏移量。换句话说,它适用于第一部分,但随后需要增加像素来激活随后的像素(例如,下一个像素为90像素,第三个像素为110像素,等等)。
我尝试按照此答案中的说明直接操作scrollspy对象:How do I set the offset for ScrollSpy in Bootstrap?,但无济于事。
有人可以推荐在偏移量根据介质宽度而变化的响应站点中实现滚动显示的规范方法吗?
附加信息:
我只是在两种情况下都分析了scrollspy对象,结果证明,仅通过data-
属性与通过JS进行初始化时,偏移量列表是不同的。似乎当我通过JS初始化偏移数组时,会在一些BS响应性调整发生之前填充偏移数组,因此高度有所不同。我如何触发scrollspy的初始化after所有响应性内容已运行? BS调整布局后是否有挂机/回调? JS是否参与其中,还是所有响应式内容都由CSS处理?
[不幸的是,当第一次调用data-*
函数时,jQuery仅拉入$().data(...)
属性一次。并且scrollspy
初始化时仅读取一次选项。 scrollspy的refresh
功能不会重新加载任何选项。在同一元素上再次调用$(..).scrollspy(...)
会忽略所有新数据选项(使用先前初始化的值)。
然而,scrollspy does将选项值存储在键'bs.scrollspy'
下的元素数据中。因此,您可以更改该数据密钥内的options.offset
字段。
为了解决导航栏高度动态变化以及需要更改scrollspy偏移值的问题,可以将以下示例用于可变高度的固定顶部导航栏。
以下内容可做一些事情。
window.load
事件触发之后,并以导航栏当前高度的偏移量开始(也将主体的padding-top
值调整为与导航栏高度相同)。padding-top
,并调整卷轴offset
以匹配。然后执行refresh
以重新计算锚点偏移。<body>
<style type="text/css">
/* prevent navbar from collapsing on small screens */
#navtop .navbar-nav > li { float: left !important; }
</style>
<nav id="navtop" class="navbar-fixed-top" role="navigation">
<div class="container">
<ul class="nav nav-pills navbar-nav">
<li><a href="#one">One</a></li>
<li><a href="#two">Two</a></li>
<li><a href="#three">Three</a></li>
... some more navlinks, or dynamically added links that affect the height ...
</ul>
</div>
</nav>
<section id="one">
...
</section>
<section id="two">
...
</section>
<section id="three">
...
</section>
....
</body>
$(window).on('load',function(){
var $body = $('body'),
$navtop = $('#navtop'),
offset = $navtop.outerHeight();
// fix body padding (in case navbar size is different than the padding)
$body.css('padding-top', offset);
// Enable scrollSpy with correct offset based on height of navbar
$body.scrollspy({target: '#navtop', offset: offset });
// function to do the tweaking
function fixSpy() {
// grab a copy the scrollspy data for the element
var data = $body.data('bs.scrollspy');
// if there is data, lets fiddle with the offset value
if (data) {
// get the current height of the navbar
offset = $navtop.outerHeight();
// adjust the body's padding top to match
$body.css('padding-top', offset);
// change the data's offset option to match
data.options.offset = offset;
// now stick it back in the element
$body.data('bs.scrollspy', data);
// and finally refresh scrollspy
$body.scrollspy('refresh');
}
}
// Now monitor the resize events and make the tweaks
var resizeTimer;
$(window).resize(function() {
clearTimeout(resizeTimer);
resizeTimer = setTimeout(fixSpy, 200);
});
});
就这样。不漂亮,但是绝对可以。我上面的HTML可能需要一些调整。
如果您将元素动态添加到导航栏,则在插入fixSpy()
后需要调用它们。或者,您可以通过fixSpy()
计时器调用setInterval(...)
来始终运行。
Scrollspy设置目标列表/初始化后的偏移量。如果您调整屏幕大小,则scrollspy不会再次初始化。您将重新加载页面以重新计算偏移量。
您提到的“累积”偏移量实际上是由相同偏移量列表组成的,这些偏移量具有不同的内容高度。
也可能会用$(window).resize()
触发此重新加载,请注意某些浏览器会触发两次,请参见https://stackoverflow.com/a/4298653/1596547以获取解决方案:
var id;
$(window).resize(function()
{
clearTimeout(id);
id = setTimeout($('body').scrollspy({ target: '' }), 500);
});
请注意http://getbootstrap.com/javascript/#scrollspy上的文档告诉您类似的内容:
“当使用scrollspy结合添加或删除DOM中的元素,则需要调用刷新方法“
通过以上操作,您将获得类似的内容:
var id;
$(window).resize(function()
{
clearTimeout(id);
id = setTimeout($('[data-spy="scroll"]').each(function () {var $spy = $(this).scrollspy('refresh'}), 500);
});
NOTE:scollspy插件使用jQuery的scrollTop()函数进行计算。因此,也请阅读以下内容:http://blog.jonathanargentiero.com/?p=134。
我知道最初的问题要求BS3,但是我没有找到BS4的正确而简单的答案。因此,我现在附上最适合我的解决方案。
从BS4开始,配置位置已更改。如果您正在寻找正确的位置以直接更改offset
。它是:$('body').data('bs.scrollspy')._config.offset
。另外,如果您希望直接更改生效。然后呼叫$('body').scrollspy('refresh');
。现在,偏移量由scrollspy尊重。
基于这种方法,我写了一个小片段,可以帮助您针对特定的导航容器(例如BS4导航栏)动态调整偏移量。
var initScrollSpy = function() {
var navContainer = '#mainNav'; // your navigation container
// initial bind of scrollspy
var bindScrollSpy = function() {
$('body').scrollspy({
target: navContainer,
offset: getOffset() // determine your offset
});
}
// get your offset dynamically
var getOffset = function() {
return $(navContainer).outerHeight();
};
// update the offset but only if the container size changed
var updateOffset = function() {
var cfg = $('body').data('bs.scrollspy')._config;
if(cfg.offset != getOffset()){
cfg.offset = getOffset();
$('body').scrollspy('refresh');
}
}
bindScrollSpy(); // bind scrollspy
$(window).resize(updateOffset); // react on resize event
$(".collapse").on('shown.bs.collapse', updateOffset); // react on BS4 menu shown event (only on mobile). You might omit this line if your navigation has no change in height when opened on mobile
};
initScrollSpy(); // finally call snippet
我在代码中附加了代码段的说明。但是通常我会像平常一样绑定scrollspy偏移量。此外,我们有两个事件。一种对窗口调整大小有反应,另一种对导航栏有反应。对于这两种情况,我都会检查偏移量值是否与所需的偏移量不同,然后直接在scrollspy中更新它,就是这样。