วิธีรับค่าชดเชยข้อมูลแบบไดนามิกสำหรับวิธีการต่อท้าย Bootstrap 3

ฉันต้องการใช้วิธีการ Affix ที่อธิบายไว้ในเอกสาร Bootstraps (http://getbootstrap.com/javascript/#affix) อย่างไรก็ตามแถบนำทางที่ฉันต้องการแก้ไขที่ด้านบนของหน้าหลังจากที่เลื่อนไปที่แถบนั้นสามารถมีค่าออฟเซ็ตที่แตกต่างกันได้ ขึ้นอยู่กับเนื้อหาด้านบน

นี่คือตัวอย่างของแถบนำทาง:

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

อย่างที่คุณเห็น ปัจจุบัน data-offset-top ตั้งค่าไว้ที่ 200 ซึ่งใช้ได้ผลดีหากเนื้อหาด้านบนมีความสูง 200px แต่เนื้อหาด้านบนเป็นไดนามิก ดังนั้น ความสูงเหนือแถบนำทางจึงไม่เท่ากันเสมอไป ฉันจะทำให้หุบเขาสำหรับ data-offset-top เป็นแบบไดนามิกได้อย่างไร

ฉันเดาว่าฉันจะต้องใช้วิธีการจาวาสคริปต์ แต่ฉันไม่แน่ใจ


person bigmike7801    schedule 09.09.2013    source แหล่งที่มา
comment
ฉันต้องการวิธีคำนวณค่าในการปรับขนาดหน้าอีกครั้งและเพิ่มที่ยึดพื้นที่เพื่อให้การติดทำงานได้อย่างราบรื่นเช่น ไม่มีการกระโดดหน้าเมื่อเนื้อหาติดอยู่ วิธีแก้ไข -> stackoverflow.com/a/47429990/996010   -  person Hrvoje Golcic    schedule 22.11.2017


คำตอบ (7)


คุณสามารถใช้ jQuery เพื่อรับความสูงของเนื้อหาแบบไดนามิกที่สูงกว่า navbar ตัวอย่างเช่น:

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

การสาธิตการทำงาน: http://bootply.com/69848

ในบางกรณี จะต้องคำนวณ offset.bottom เพื่อกำหนดเวลาที่จะ "ยกเลิกการตรึง" องค์ประกอบ นี่คือตัวอย่างของ affix-bottom

person Zim    schedule 09.09.2013
comment
ใช้ .outerHeight() แทน .height() เพื่อรวมเส้นขอบและช่องว่างภายใน - person Alicia; 07.08.2016

ฉันรู้สึกหงุดหงิดอย่างยิ่งกับวิธีการทำงานนี้ ทุกครั้งที่ทำการคำนวณแบบกำหนดเองและสร้างการชดเชยจากความสูงขององค์ประกอบที่อยู่เหนือส่วนเสริมที่ต้องการ

นี่คือการติดที่ดีที่สุด

ส่วนเสริมบูสแตรปปกติจะไม่นำรายการตำแหน่งบนสุดที่ชดเชยตามธรรมชาติมาพิจารณา คุณต้องส่งผ่านเป็นแอตทริบิวต์ด้วยตนเอง สิ่งนี้จะดูแลสิ่งนั้นและคำนึงถึงการเปลี่ยนแปลงด้านบนสุดของการปรับขนาดหน้าต่าง

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

ฉันยังโพสต์สิ่งนี้ในการตรวจสอบโค้ดด้วย

อย่าลืมเพิ่มแอตทริบิวต์ data-smart-affix ให้กับองค์ประกอบ affix ของคุณ

ลองใช้โค้ดตัวอย่างนี้: https://jsfiddle.net/NabiKAZ/qyrauogw/
( ในตัวอย่างนี้ ความสูงของส่วนสีแดงอาจเป็น 100px หรือ 200px หรือ 300px ในความกว้างของหน้าต่าง ดังนั้นจึงต้องแตกต่าง data-offset-top เมื่อเลื่อน)

person ThomasReggi    schedule 19.03.2015
comment
คุณคือฮีโร่ของฉัน! ขอบคุณเพื่อน .. ป.ล. สำหรับคนอื่นๆ: เมื่อใช้โค้ดนี้ อย่าลืมเพิ่มแอตทริบิวต์ data-smart-affix ให้กับองค์ประกอบ affix ของคุณ ;) - person Mike; 12.08.2015
comment
คำตอบที่ดีที่สุด! ทำได้ดีมาก สิ่งนี้ช่วยฉันแก้ไขปัญหาได้ - person Bogdan Le; 14.10.2015
comment
มีข้อบกพร่องในโค้ดของคุณ โปรดใช้ $(this).data('bs.affix').options.offset.top แทน $(this).data('bs.affix').options.offset ฉันขอแนะนำให้ใช้ [data-offset-top-dynamic แทน [data-smart-affix] - person Hrvoje Golcic; 15.11.2017

data-smart-affix ของ ThomasReggi ไม่ได้ผลสำหรับฉันในบางกรณี (เมื่อปรับขนาดเอกสาร หรือเมื่อคอลัมน์ที่ติดอยู่สูงเกินไป) แต่มันให้แนวคิดง่ายๆ แก่ฉัน: เพิ่มองค์ประกอบว่างก่อนเนื้อหาที่ติดอยู่ และใช้สิ่งนั้นเพื่อชดเชย ทำงานได้ดีเมื่อปรับขนาด

ขณะที่ฉันอยู่ที่นั่น ฉันยังตั้งค่าความกว้างขององค์ประกอบให้เป็นความกว้างตามธรรมชาติในพาเรนต์ดั้งเดิม นี่คือวิธีแก้ปัญหาของฉัน:

$('[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 ที่มาพร้อมกับมันคือ:

<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 ที่จำเป็นคือ:

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

หากคุณต้องการปิดการใช้งานส่วนต่อท้าย (เช่น เมื่อคอลัมน์ด้านขวาซ้อนกัน) ให้ใช้ CSS:

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

ภายในแบบสอบถามสื่อที่เหมาะสม

GI

person gi1242    schedule 04.09.2015

ฉันขอแนะนำให้คุณเพิ่ม wrapper รอบ div ที่ติดอยู่ - เพื่อหลีกเลี่ยง "scroll jump" ที่มี navbar ที่ติดอยู่ Thomas โพสต์วิธีแก้ปัญหาที่ดี แต่ไม่รวมช่องว่างที่ยุบหลังการติด และมันไม่ทำงานในเวอร์ชัน boostrap 2.x ที่ฉันต้องใช้ ดังนั้นฉันจึงตัดสินใจเขียนการนำส่วนต่อท้ายไปใช้ใหม่ทั้งหมด มันไม่จำเป็นต้องมี boostrap แค่ jquery นี่เป็นจาวาสคริปต์แรกของฉัน ดังนั้นโปรดเมตตา :) แต่บางทีมันอาจช่วยใครซักคนได้ เป็นเรื่องดีเสมอที่มีวิธีแก้ปัญหาโดยไม่ต้องบูตสแตรป

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();
   });

});

คุณสามารถดูตัวอย่างได้ที่นี่: http://jsfiddle.net/3ss7fk92/

person pixelofficer    schedule 16.04.2015

Skelly ด้านบนนั้นถูกต้องและไม่มีวิธีใดที่จะดีไปกว่าการทำเช่นนั้น วิธีแก้ปัญหาเดียวที่เป็นไปได้สำหรับบูตสแตรป "ดั้งเดิม" คือการแนบตัวเลือกส่วนต่อท้ายด้วยการเรียก JavaScript (ดังที่กล่าวไว้ข้างต้นใน https://stackoverflow.com/a/18702972/2546679)

โดยเฉพาะอย่างยิ่ง ไม่ เป็นไปได้ที่จะใช้แอตทริบิวต์ data-offset เพื่อให้บรรลุผลแบบเดียวกัน (แม้ว่าจะสะดวกกว่ามากก็ตาม และแม้ว่าเอกสารประกอบสำหรับ Affix ที่ http://getbootstrap).com/2.3.2/javascript.html#affix ทำให้เกิดความหวังว่าจะทำเช่นนั้นได้)

จึงสามารถเขียนได้

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

แต่สิ่งหนึ่งที่ ไม่ ได้รับอนุญาตให้เขียน เช่น:

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

เหตุผลก็คือแอตทริบิวต์ข้อมูลถูกแยกวิเคราะห์ผ่าน JQuery .data() API ซึ่งอนุญาตให้แยกวิเคราะห์ค่า JSON ล้วนๆ เท่านั้น โปรดดูที่ https://api.jquery.com/data/

person haui    schedule 14.06.2015
comment
คำตอบของคุณไม่ใช่แบบไดนามิก แต่เป็นแบบคงที่ - person bigmike7801; 14.06.2015
comment
ใช่ - นี่ไม่ใช่คำตอบแบบสแตนด์อโลน แต่เป็นภาคผนวกของคำตอบของ Skelly (ซึ่งฉันไม่ได้รับอนุญาตให้แสดงความคิดเห็น) ฉันแค่พยายามชี้แจงว่าการพยายามแสดงการคำนวณส่วนต่อท้ายแบบไดนามิกโดยไม่ต้องใช้ JavaScript ที่กำหนดเองบนเพจนั้นไร้จุดหมาย - สิ่งที่ฉันได้ลองมาหลายชั่วโมง - รวมถึงการดีบักรูทีน bootstrap และ JQuery - person haui; 15.06.2015

ขอบคุณ ThomasReggi สำหรับแนวคิด แต่อาจจะเขียนได้ถูกต้องกว่า:

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

สำหรับผู้ที่ชอบฉันที่ต้องการค่าต่ำสุดที่จะเขียนแบบอะนาล็อกเช่นกัน

BTW ฉันคิดว่าห่อมันไว้ในมัณฑนากรตาม setTimeout (ค่อนข้างคล้ายกับ debounce)

person discodanser    schedule 20.09.2015

ก่อนหน้านี้ฉันมีปัญหามากมายกับเรื่องนี้ และด้วยเหตุผลบางอย่าง ฉันไม่สามารถรับวิธีแก้ปัญหาที่คนอื่นแนะนำให้ใช้งานได้ ฉันค่อนข้างใหม่กับ Bootstrap และ JQuery ดังนั้นฉันจึงอาจทำบางอย่างที่แปลกประหลาดที่ฉันไม่สามารถเข้าใจได้ ไม่ว่าฉันจะพบวิธีแก้ปัญหาที่ใช้งานได้ดีแม้ว่าจะไม่ได้พูดอย่างเคร่งครัดให้ใช้ฟังก์ชันการทำงานของส่วนเสริมตามที่ Bootstrap ตั้งใจก็ตาม ฉันเก็บ #thisElement.affix {top: desiredFixedPosition;} CSS ไว้ครบถ้วน แต่ได้ลบแอตทริบิวต์ data-spy และ data-offset-top ออกจากแท็ก HTML ของ #thisElement แล้ว ฉันฮาร์ดโค้ดสิ่งนี้ใน 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);
}

เท่าที่ฉันได้ทดสอบ วิธีนี้ได้ผลไม่ว่าคุณจะปรับขนาดหน้าหรือเลื่อนมากแค่ไหน และหากคุณมีความคิดสร้างสรรค์ในการเรียกมันในฟังก์ชัน $(document).ready() คุณยังสามารถให้เมนูอยู่ในตำแหน่งที่ถูกต้องระหว่างการแสดงภาพเคลื่อนไหวที่มีความสูงได้ ตามที่ระบุไว้นี่ไม่ใช่โซลูชัน "ได้รับการอนุมัติ Bootstrap" ในทางเทคนิคอย่างสมบูรณ์ แต่จะรวมเข้ากับไซต์ Bootstrap ได้ดีพอที่จะใช้งานได้สำหรับบางคน :)

person Patrick Menard    schedule 18.10.2017