Cara mendapatkan nilai offset data dinamis untuk metode imbuhan Bootstrap 3

Saya ingin menggunakan metode Affix yang dijelaskan dalam dokumentasi Bootstraps (http://getbootstrap.com/javascript/#affix), namun bilah navigasi yang ingin saya perbaiki di bagian atas halaman setelah digulir ke sana dapat memiliki nilai offset yang berbeda tergantung pada konten di atasnya.

Berikut ini contoh bilah navigasi:

<div class="navbar navbar-default" data-spy="affix" data-offset-top="200">
  <ul class="nav navbar-nav">
    <li class="active"><a href="/id#">Link</a></li>
    <li><a href="/id#">Link 1</a></li>
    <li><a href="/id#">Link 2</a></li>
  </ul>
</div>

Seperti yang Anda lihat, data-offset-top saat ini disetel pada 200. Ini berfungsi dengan baik jika konten di atas berukuran 200 piksel, namun konten di atas bersifat dinamis sehingga ketinggian di atas bilah navigasi ini tidak selalu sama. Bagaimana cara membuat nilai untuk data-offset-top menjadi dinamis?

Saya kira saya harus menggunakan cara javascript untuk melakukannya tetapi saya tidak yakin.


person bigmike7801    schedule 09.09.2013    source sumber
comment
Saya memerlukan cara untuk menghitung ulang nilai pada pengubahan ukuran halaman dan juga menambahkan penahan spasi agar pembubuhan berjalan lancar, misalnya. tidak ada halaman yang melompat ketika isinya ditempel. Solusinya -› stackoverflow.com/a/47429990/996010   -  person Hrvoje Golcic    schedule 22.11.2017


Jawaban (7)


Anda bisa menggunakan jQuery untuk mendapatkan tinggi konten dinamis di atas navbar. Misalnya:

$('#nav').affix({
      offset: {
        top: $('header').height()
      }
}); 

Demo yang berfungsi: http://bootply.com/69848

Dalam beberapa kasus, offset.bottom juga harus dihitung untuk menentukan kapan harus "melepaskan" elemen. Berikut contoh affix-bottom

person Zim    schedule 09.09.2013
comment
gunakan .outerHeight() alih-alih .height() untuk menyertakan batas dan bantalan - person Alicia; 07.08.2016

Saya benar-benar frustrasi dengan cara kerjanya, setiap kali melakukan perhitungan khusus dan membuat offset dari ketinggian elemen di atas imbuhan yang diinginkan.

Inilah imbuhan yang terbaik.

Afiks boostrap normal tidak memperhitungkan posisi teratas offset alami item, Anda harus meneruskannya secara manual sebagai atribut. Ini menangani hal itu, dan memperhitungkan perubahan atas offset pada pengubahan ukuran jendela.

var $attribute = $('[data-smart-affix]');
$attribute.each(function(){
  $(this).affix({
    offset: {
      top: $(this).offset().top,
    }
  })
})
$(window).on("resize", function(){
  $attribute.each(function(){
    $(this).data('bs.affix').options.offset.top = $(this).offset().top
  })
})

Saya juga memposting ini di tinjauan kode.

Jangan lupa untuk menambahkan atribut data-smart-affix pada elemen imbuhan Anda

Coba kode contoh ini: https://jsfiddle.net/NabiKAZ/qyrauogw/
( Dalam contoh ini, tinggi bagian merah mungkin 100px atau 200px atau 300px dalam perbedaan lebar jendela, Jadi perlu perbedaan data-offset-top saat digulir.)

person ThomasReggi    schedule 19.03.2015
comment
kamu adalah pahlawanku! Terima kasih kawan.. PS untuk yang lain: Saat menggunakan kode ini, jangan lupa menambahkan atribut data-smart-affix ke elemen affix Anda. ;) - person Mike; 12.08.2015
comment
Jawaban Terbaik! bagus sekali. ini membantu saya memperbaiki masalah saya - person Bogdan Le; 14.10.2015
comment
Ada bug dalam kode Anda, harap gunakan $(this).data('bs.affix').options.offset.top alih-alih $(this).data('bs.affix').options.offset. Bolehkah saya menyarankan untuk menggunakan [data-offset-top-dynamic daripada [data-smart-affix] - person Hrvoje Golcic; 15.11.2017

Data-smart-affix ThomasReggi tidak berfungsi untuk saya dalam beberapa kasus sudut (saat mengubah ukuran dokumen, atau ketika kolom yang ditempel terlalu tinggi). Tapi itu memberi saya ide sederhana: Tambahkan elemen kosong sebelum konten yang ditempelkan, dan gunakan itu untuk mendapatkan offset. Berfungsi dengan baik saat diubah ukurannya.

Saat saya melakukannya, saya juga mengatur lebar elemen menjadi lebar alami di induk aslinya. Inilah solusi saya:

$('[data-affix-after]').each( function() {
  var elem = $(this);
  var parent_panel = elem.parent();
  var prev = $( elem.data('affix-after') );

  if( prev.length != 1 ) {
    /* Create a new element immediately before. */
    prev = elem.before( '<div></div>' ).prev();
  }

  var resizeFn = function() {
      /* Set the width to it's natural width in the parent. */
      var sideBarNavWidth = parent_panel.width()
          - parseInt(elem.css('paddingLeft'))
          - parseInt(elem.css('paddingRight'))
          - parseInt(elem.css('marginLeft'))
          - parseInt(elem.css('marginRight'))
          - parseInt(elem.css('borderLeftWidth'))
          - parseInt(elem.css('borderRightWidth'));
      elem.css('width', sideBarNavWidth);

      elem.affix({
          offset: {
              top: prev.offset().top + prev.outerHeight(true),
              bottom: $('body>footer').outerHeight(true)
          }
      });
  };

  resizeFn();
  $(window).resize(resizeFn);
});

HTML yang menyertainya adalah:

<div id='before-affix'></div><!-- leave this empty -->
<div data-affix-after='#before-affix'>
    Put content to affix here.
</div>

or

<div data-affix-after='#create'><!-- any ID that doesn't exist -->
    Put content to affix here.
</div>

CSS yang diperlukan adalah:

.affix { top: 0px },
.affix-bottom { position: absolute; }

Jika Anda ingin menonaktifkan imbuhan (misalnya saat kolom kanan ditumpuk), gunakan CSS:

.affix, .affix-bottom { position: static; }

di dalam kueri media yang sesuai.

GI

person gi1242    schedule 04.09.2015

Saya menyarankan Anda untuk menambahkan pembungkus di sekitar div yang ditempel - untuk menghindari "scroll jump" dengan navbar yang ditempel. Thomas memposting solusi yang bagus, tetapi tidak menyertakan spasi setelah imbuhan dan tidak berfungsi di versi boostrap 2.x yang harus saya gunakan. Jadi saya memutuskan untuk menulis implementasi imbuhan yang benar-benar baru. Tidak perlu boostrap, cukup jquery. Ini javascript pertama saya, jadi mohon ampun :) tapi mungkin ini akan membantu seseorang. Itu selalu menyenangkan untuk memiliki solusi tanpa bootstrap

function myaffix() {

var affixoffset = $('.navbar').offset().top

$('#nav-wrapper').height($(".navbar").height());

$(window).scroll(function () {

    if ($(window).scrollTop() <= affixoffset) {
        $('.navbar').removeClass('affix');
    } else {
        $('.navbar').addClass('affix');
    }
});

};

$(document).ready(function () {

   myaffix();

   $(window).on("resize", function () {
       myaffix();
   });

});

Anda dapat menemukan contohnya di sini: http://jsfiddle.net/3ss7fk92/

person pixelofficer    schedule 16.04.2015

Skelly di atas benar dan tidak ada cara yang lebih baik untuk melakukannya. Satu-satunya solusi yang mungkin dengan bootstrap "asli" adalah dengan melampirkan opsi imbuhan dengan panggilan JavaScript (seperti yang disebutkan di atas dalam https://stackoverflow.com/a/18702972/2546679).

Terutama tidak mungkin menggunakan atribut data-offset untuk mencapai efek yang sama (walaupun ini akan jauh lebih nyaman, dan meskipun dokumentasi untuk Affix di http://getbootstrap.com/2.3.2/javascript.html#affix menimbulkan harapan seseorang dapat melakukannya).

Jadi seseorang bisa menulis

data-offset='{"top":42}'

namun seseorang tidak diperbolehkan menulis, misalnya:

data-offset='{"top":$("#banner").height()}'

Alasannya adalah atribut data diurai melalui JQuery .data() API yang hanya memungkinkan nilai JSON murni untuk diurai, lihat https://api.jquery.com/data/.

person haui    schedule 14.06.2015
comment
Jawaban Anda tidak dinamis, hanya statis. - person bigmike7801; 14.06.2015
comment
Ya - ini bukan jawaban yang berdiri sendiri tetapi merupakan tambahan dari jawaban Skelly (di mana saya tidak diperbolehkan berkomentar). Saya baru saja mencoba mengklarifikasi bahwa tidak ada gunanya mencoba mengekspresikan perhitungan imbuhan dinamis tanpa menggunakan JavaScript khusus pada halaman - apa yang telah saya coba selama beberapa jam - termasuk men-debug rutinitas bootstrap dan JQuery. - person haui; 15.06.2015

Terima kasih ThomasReggi atas idenya. Namun mungkin lebih tepat jika ditulis:

$(this).data('bs.affix').options.offset.top = $(this).offset().top

bagi yang seperti saya yang membutuhkan nilai terbawah juga akan menulis secara analogis.

BTW juga menurut saya membungkusnya dengan dekorator berdasarkan setTimeout (agak seperti debounce).

person discodanser    schedule 20.09.2015

Saya mengalami banyak masalah dengan ini sebelumnya, dan karena alasan tertentu saya tidak bisa mendapatkan solusi apa pun yang disarankan orang lain agar berhasil. Saya relatif baru mengenal Bootstrap dan JQuery, jadi saya mungkin melakukan sesuatu yang aneh yang tidak saya pahami. Terlepas dari itu, saya menemukan solusi yang bekerja dengan sangat baik, meskipun solusi tersebut tidak sepenuhnya menggunakan fungsi imbuhan seperti yang diinginkan Bootstrap. Saya menjaga #thisElement.affix {top: desiredFixedPosition;} CSS saya tetap utuh, tetapi menghilangkan atribut data-spy dan data-offset-top dari tag HTML #thisElement. Saya kemudian membuat kode keras ini di JQuery:

var newAffix = function() {
    if($("otherElementsAboveThisElement").height() <= $(window).scrollTop()) {
        $("#thisElement").addClass("affix");
    } else {
        $("#thisElement").removeClass("affix");
    }
}

$(document).ready(function() {
    $(window).resize(newAffix);
    $(window).scroll(newAffix);
}

Sejauh yang saya uji, ini berfungsi terlepas dari seberapa banyak Anda mengubah ukuran halaman atau menggulir, dan jika Anda berkreasi dengan cara memanggilnya dalam fungsi $(document).ready() Anda bahkan dapat membuat menu tetap berada di posisi yang tepat selama animasi ketinggian. Seperti yang dinyatakan, secara teknis ini bukan solusi yang sepenuhnya "disetujui Bootstrap", tetapi ini terintegrasi dengan cukup baik ke dalam situs Bootstrap sehingga dapat berfungsi untuk beberapa orang :)

person Patrick Menard    schedule 18.10.2017