我正在尝试让Bootstrap的scrollspy在响应式网站上可靠地工作,其中顶部导航栏的高度根据媒体/浏览器的宽度而变化。因此,我没有对data-offset
属性上的偏移量进行硬编码,而是通过Javascript初始化动态设置它,如下所示:
$('body').scrollspy({ offset: 70, target: '#nav' });
对于宽布局(即Bootstrap -lg),它可以正常工作,但对于较窄的布局,似乎存在“累积”偏移。换句话说,它适用于第一部分,但随后需要增加像素来激活以下部分(例如,下一部分为90px,第三部分为110px等)。
我尝试直接操作scrollspy对象,如下所示: How do I set the offset for ScrollSpy in Bootstrap?但无济于事。
有人可以推荐在响应式网站中实施scrollspy的规范方法,其中偏移量会根据媒体宽度而变化吗?
其他信息:
我刚刚分析了两个场景中的scrollspy对象,结果发现当通过data-
属性而不是通过JS初始化时,偏移列表是不同的。看起来当我通过JS初始化它时,偏移数组会在一些BS响应调整发生之前填充,因此高度不同。在所有响应式内容运行后,如何触发scrollspy的初始化? BS调整布局后是否有钩子/回调? JS是否涉及或者是CSS处理的所有响应式内容?
答案 0 :(得分:17)
不幸的是,当第一次调用data-*
函数时,jQuery只会引入$().data(...)
个属性。并且scrollspy
仅在初始化时读取选项一次。 scrollspy的refresh
函数不会重新加载任何选项。在同一元素上再次调用$(..).scrollspy(...)
将忽略任何新数据选项(使用先前初始化的值)。
然而,scrollspy 将选项值存储在键'bs.scrollspy'
下的元素数据中。因此,您可以更改该数据密钥中的options.offset
字段。
为了考虑动态变化的导航栏高度以及需要更改scrollspy偏移值,您可以将以下示例用于可变高度固定顶部导航栏。
以下是一些事情。
window.load
事件触发后),并以导航栏当前高度的偏移量开始(也将主体的padding-top
值调整为与导航栏高度相同)。padding-top
,并调整scrollspy 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(...)
以便一直运行。
答案 1 :(得分:2)
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);
});
注意:scollspy插件使用jQuery的scrollTop()函数进行计算。所以也请阅读:http://blog.jonathanargentiero.com/?p=134。
答案 2 :(得分:0)
我知道最初的问题要求BS3,但是我没有找到BS4的正确且简单的答案。因此,我现在附上最适合我的解决方案。
从BS4开始,配置位置已更改。如果您正在寻找正确的位置以直接即时更改offset
。它是:$('body').data('bs.scrollspy')._config.offset
。另外,如果您希望直接更改生效。之后致电$('body').scrollspy('refresh');
。现在,offsetspy会考虑偏移量。
基于这种方法,我写了一个小片段,可以帮助您针对特定的导航容器(例如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中更新它。