it-swarm.com.ru

Как получить динамические значения смещения данных для аффиксного метода 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="#">Link</a></li>
    <li><a href="#">Link 1</a></li>
    <li><a href="#">Link 2</a></li>
  </ul>
</div>

Как вы можете видеть, data-offset-top в настоящее время установлен на 200. Это прекрасно работает, если содержимое выше 200px в высоту, но содержимое выше является динамическим и поэтому высота над этой панелью навигации не всегда одинакова. Как я могу сделать вейл для data-offset-top динамичным?

Я предполагаю, что мне придется использовать способ javascript, но я не уверен.

31
bigmike7801

Вы можете использовать jQuery, чтобы получить динамическую высоту содержимого над navbar. Например:

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

Рабочая демонстрация: http://bootply.com/69848

В некоторых случаях, offset.bottom также должен быть рассчитан, чтобы определить, когда «отсоединять» элемент. Вот пример аффикса-дна

44
Zim

Я был совершенно разочарован тем, как это работает, каждый раз выполняя некоторые пользовательские вычисления и создавая смещение по высоте элементов над желаемым аффиксом. 

Вот аффикс в лучшем виде.

Обычный аффикс Boostrap не учитывает верхнее положение с естественным смещением элементов, вы должны вручную передать его как атрибут. Это заботится об этом и учитывает изменение вершины смещения при изменении размера окна.

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 при прокрутке.)

21
ThomasReggi

Умный аффикс 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>

или же

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

внутри соответствующего медиа-запроса.

Солдат

3
gi1242

Я предлагаю вам добавить обертку вокруг прикрепленного div - чтобы избежать «прокрутки прыжка» с прикрепленной навигационной панелью. Томас опубликовал отличное решение, но оно не включает в себя сжатое пространство после аффикса, и оно не работает в версии 2.x boostrap, которую я должен использовать. Поэтому я решил написать совершенно новую реализацию аффикса. Это не нуждается в Boostrap, просто JQuery. Это мой первый javascript, поэтому, пожалуйста, помилуйте :), но, возможно, это кому-нибудь поможет. Всегда приятно иметь решение без начальной загрузки

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/

1
pixelofficer

У меня было много проблем с этим ранее, и по какой-то причине я не мог получить ни одно из решений, предложенных другими людьми для работы. Я относительно новичок в 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, что для некоторых должно работать :)

0
Patrick Menard

Skelly выше это правильно, и нет лучшего способа сделать это. Единственное возможное решение с "нативной" начальной загрузкой - это присоединение параметров аффикса с помощью вызова JavaScript (как упомянуто выше в https://stackoverflow.com/a/18702972/2546679 ).

Особенно not возможно использовать атрибут data-offset для достижения того же эффекта (даже если это будет намного удобнее, и даже если документация для Affix на http://getbootstrap.com/2.3.2 /javascript.html#affix вселяет надежду, что это можно сделать).

Так можно написать 

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

но одному нельзя разрешено писать, например:

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

Причина в том, что атрибуты данных анализируются через API-интерфейс JQuery .data(), который позволяет анализировать только чистые значения JSON, см. https://api.jquery.com/data/ .

0
haui

Спасибо ThomasReggi за идею. Но может быть правильнее написать:

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

для тех, кто, как я, тоже нужен нижний показатель, который писал бы аналогично.

Кстати, я также думаю, что обернуть его в декоратор на основе setTimeout (что-то вроде debounce).

0
discodanser