9

メディア/ブラウザの幅に応じてトップ ナビゲーション バーの高さが変化するレスポンシブ サイトで Bootstrap の scrollspy を確実に動作させようとしています。したがって、属性のオフセットをハードコーディングする代わりに、次のdata-offsetように Javascript の初期化を通じて動的に設定しています。

$('body').scrollspy({ offset: 70, target: '#nav' });

幅の広いレイアウト (つまり、Bootstrap -lg) では問題なく動作しますが、幅の狭いレイアウトでは、「累積」オフセットが有効になっているようです。つまり、最初のセクションでは問題なく動作しますが、次のセクションをアクティブにするためにピクセルを増やす必要があります (たとえば、次のセクションでは 90px、3 番目のセクションでは 110px など)。

この回答に記載されているように、scrollspy オブジェクトを直接操作してみました: Bootstrap で ScrollSpy のオフセットを設定するにはどうすればよいですか? しかし、役に立たない。

オフセットがメディアの幅に応じて変化するレスポンシブ サイトで scrollspy を実装する標準的な方法を誰かが推奨できますか?

追加情報:

両方のシナリオで scrollspy オブジェクトを分析したところ、data-属性のみを介して初期化された場合と JS を介して初期化された場合で、オフセットのリストが異なることがわかりました。JS を介して初期化すると、BS 応答調整が発生する前にオフセット配列が設定され、高さが異なるようです。すべてのレスポンシブが実行された後、 scrollspy の初期化をトリガーするにはどうすればよいですか? BS がレイアウトの調整を完了した後、フック/コールバックはありますか? JS も関係していますか、それともすべてのレスポンシブ機能は CSS によって処理されていますか?

4

3 に答える 3

18

残念ながら、jQuery は関数が初めて呼び出されたdata-*ときに一度だけ属性を取得します。$().data(...)またscrollspy、初期化時に一度だけオプションを読み取ります。scrollspyのrefresh機能は、どのオプションもリロードしません。同じ要素を再度呼び出す$(..).scrollspy(...)と、新しいデータ オプションが無視されます (以前に初期化された値が使用されます)。

ただし、scrollspyオプション値をキーの下の要素データに保存します'bs.scrollspy'。したがって、options.offsetそのデータキー内のフィールドを変更できます。

動的に変化する navbar の高さと scrollspy オフセット値を変更する必要性を考慮して、可変高さの固定トップ navbar に次の例を使用できます。

以下は、いくつかのことを行います。

  • (イベントが発生した後) javascript を介して scrollspy を初期化window.loadし、navbar の現在の高さのオフセットから開始します (また、本体のpadding-top値を navbar の高さと同じになるように調整します)。
  • サイズ変更イベントが監視され、本体padding-topが調整され、スクロールスパイoffsetがそれに合わせて微調整されます。次にrefresh、アンカー オフセットを再計算するために a が実行されます。

HTML

<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>

JavaScript

$(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 には微調整が必​​要な場合があります。

navbar に要素を動的に追加する場合は、要素fixSpy()が挿入された後に呼び出す必要があります。または、タイマーをfixSpy()介して呼び出して、常に実行することもできます。setInterval(...)

于 2014-01-12T06:41:17.463 に答える
2

Scrollspy は、初期化後にターゲット/オフセットのリストを設定します。画面のサイズを変更しても、scrollspy は再度初期化されません。オフセットを再計算するには、ページをリロードする必要があります。

あなたが実際に言及している「累積」オフセットは、コンテンツの高さが異なるオフセットの同じリストが原因です。

$(window).resize()一部のブラウザがこれを 2 回起動することに注意して、このリロードをトリガーすることもできます。解決策については、https ://stackoverflow.com/a/4298653/1596547 を参照してください。

var id; 

$(window).resize(function() 
{
    clearTimeout(id);
    id = setTimeout($('body').scrollspy({ target: '' }), 500);
});

http://getbootstrap.com/javascript/#scrollspyのドキュメントにも同様のことが書かれていることに注意してください。

"DOM からの要素の追加または削除と一緒に scrollspy を使用する場合、refresh メソッドを呼び出す必要があります"

上記を使用すると、次のようなものが得られます。

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 .

于 2013-08-15T11:37:52.977 に答える
1

元の質問がBS3を求めていることは承知していますが、BS4の正確で簡単な答えが見つかりませんでした. したがって、私は今、私にとって完璧に機能するソリューションを添付しています。

BS4 の時点で、構成の場所が変更されました。正しいスポットを探している場合は、その場で直接変更しoffsetます。ここにあります: $('body').data('bs.scrollspy')._config.offset. さらに、直接変更を有効にしたい場合。$('body').scrollspy('refresh');後で電話する。scrollspy がオフセットを尊重するようになりました。

このアプローチに基づいて、特定のナビゲーション コンテナー (BS4 navbar など) に対してオフセットを動的に調整するのに役立つ小さなスニペットを作成しました。

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 オフセットをバインドします。さらに、2 つのイベントがあります。ウィンドウのサイズ変更に反応するものと、完全に表示されたナビゲーションバーに反応するもの。両方のイベントの場合、オフセット値が目的の値と異なるかどうかを確認し、scrollspy 内で直接更新します。それだけです。

于 2020-02-23T12:28:19.927 に答える