Twitter bootstrap Bootstrap 3.0 scrollspy响应偏移量

Twitter bootstrap Bootstrap 3.0 scrollspy响应偏移量,twitter-bootstrap,responsive-design,twitter-bootstrap-3,scrollspy,Twitter Bootstrap,Responsive Design,Twitter Bootstrap 3,Scrollspy,我试图让Bootstrap的scrollspy在一个响应迅速的站点上可靠地工作,在这个站点上,顶部导航栏的高度会根据媒体/浏览器的宽度而变化。因此,我不是在数据偏移量属性上硬编码偏移量,而是通过Javascript初始化动态设置它,如下所示: $('body').scrollspy({ offset: 70, target: '#nav' }); 对于宽布局(即Bootstrap-lg),它可以正常工作,但对于窄布局,似乎存在一个“累积”偏移。换句话说,它在第一部分工作正常,但随后需要增加像素

我试图让Bootstrap的scrollspy在一个响应迅速的站点上可靠地工作,在这个站点上,顶部导航栏的高度会根据媒体/浏览器的宽度而变化。因此,我不是在
数据偏移量
属性上硬编码偏移量,而是通过Javascript初始化动态设置它,如下所示:

$('body').scrollspy({ offset: 70, target: '#nav' });
对于宽布局(即Bootstrap-lg),它可以正常工作,但对于窄布局,似乎存在一个“累积”偏移。换句话说,它在第一部分工作正常,但随后需要增加像素来激活以下部分(例如,下一部分为90px,第三部分为110px,等等)

我尝试直接操纵scrollspy对象,如回答中所述: 但是没有用

有人能推荐一种在响应站点中实现scrollspy的规范方法吗?在响应站点中,偏移量根据媒体宽度而变化

其他信息:


我刚刚分析了这两种情况下的scrollspy对象,结果表明,仅通过
data-
属性初始化偏移量列表与通过JS初始化偏移量列表是不同的。似乎当我通过JS初始化它时,偏移量数组在一些BS响应调整发生之前被填充,因此高度不同。在所有响应的东西运行之后,如何触发scrollspy的初始化?BS完成布局调整后是否有钩子/回调?JS甚至参与了吗?或者所有响应的东西都是由CSS处理的吗?

Scrollspy在初始化后设置一个目标/偏移量列表。如果调整屏幕大小,scrollspy不会再次初始化。您必须重新加载页面以重新计算偏移量

您提到的“累积”偏移实际上是由具有不同内容高度的相同偏移列表引起的

To还可以使用
$(窗口)触发此重新加载。resize()
注意,某些浏览器会触发此操作两次,请参阅以获取解决方案:

var id; 

$(window).resize(function() 
{
    clearTimeout(id);
    id = setTimeout($('body').scrollspy({ target: '' }), 500);
});
请注意,上的文档会告诉您类似的内容:

“将scrollspy与添加或删除 元素,则需要调用刷新方法“

通过以上步骤,您将得到如下结果:

var id; 

$(window).resize(function() 
{
    clearTimeout(id);
    id = setTimeout($('[data-spy="scroll"]').each(function () {var $spy = $(this).scrollspy('refresh'}), 500);
});

注意:scollspy插件使用jQuery的scrollTop()函数进行计算。因此,也请阅读以下内容:

不幸的是,当第一次调用
$().data(…)
函数时,jQuery只拉入
数据-*
属性一次。和
scrollspy
初始化时仅读取一次选项。scrollspy的
刷新
功能不会重新加载任何选项。在同一元素上再次调用
$(..).scrollspy(…)
会忽略任何新的数据选项(使用以前初始化的值)

但是,scrollspy将选项值存储在
键“bs.scrollspy”下的元素数据中。因此,您可以更改该数据键内的
选项.offset
字段

要考虑动态更改的导航栏高度以及更改scrollspy偏移值的需要,可以对可变高度固定顶部导航栏使用以下示例

下面做了一些事情

  • 它通过javascript初始化scrollspy(在
    窗口.load
    事件触发后),并以导航栏当前高度的偏移量开始(还将主体的
    padding top
    值调整为与导航栏高度相同)
  • 监视调整大小事件,调整主体的
    填充顶部
    ,并调整scrollspy
    偏移量
    。然后执行
    刷新
    ,以重新计算锚点偏移
HTML 就这样。不漂亮,但它确实有效。我上面的HTML可能需要一些调整


如果将元素动态添加到导航栏,则在插入元素后需要调用
fixSpy()
。或者您可以通过
setInterval(…)
计时器调用
fixSpy()
,使其一直运行。

我知道原来的问题要求BS3,但我没有找到BS4的正确且简单的答案。因此,我现在附上我的解决方案,这对我来说是完美的

从BS4开始,配置位置已更改。如果您正在搜索正确的点以直接动态更改
偏移量
。这里是:
$('body').data('bs.scrollspy')。\u config.offset
。此外,如果您希望直接更改生效。调用
$('body')。scrollspy('refresh')之后。现在scrollspy尊重偏移量

基于这种方法,我编写了一个小片段,可以帮助您为特定的导航容器(例如BS4导航栏)动态调整偏移量


我在代码中附上了对代码片段的解释。但一般来说,我会像平常一样绑定scrollspy偏移量。此外,我们还有两项活动。一个对窗口大小调整作出反应,另一个对导航栏完全显示作出反应。在这两个事件中,我检查偏移量值是否与所需的偏移量值不同,并直接在scrollspy中更新它,就是这样。

有趣的是,如果我让scrollspy从
数据-
属性初始化自己,它就可以正常工作。只有当我从Javascript中执行此操作时,我才能获得“累积”偏移效果。在某种程度上,从JS初始化scrollspy(如上面的代码片段)并不等同于让它从
数据-
属性中完成。还没有弄清楚原因。响应只由CSS处理(除非您在IE8中有
respond.js
,以确保兼容性)。您是否将js代码包装在document ready处理程序中?是的,我正在调用
$('body').scrollspy({…})
$(document).ready(function(){
)中的
$(document)<
<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);
    });
});
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