web-dev-qa-db-fra.com

Comment obtenir des valeurs de décalage de données dynamiques pour la méthode Bootstrap 3 affix

J'aimerais utiliser la méthode Affix décrite dans la documentation Bootstraps ( http://getbootstrap.com/javascript/#affix ), mais la barre de navigation que je souhaite corriger se trouve en haut de la page après le défilement. peut avoir différentes valeurs de décalage en fonction du contenu situé au-dessus de celui-ci.

Voici un exemple de la barre de navigation:

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

Comme vous pouvez le constater, le data-offset-top est actuellement défini sur 200. Cela fonctionne correctement si le contenu ci-dessus a une hauteur de 200px, mais que le contenu ci-dessus est dynamique et que la hauteur au-dessus de cette barre de navigation n'est pas toujours la même. Comment puis-je rendre la valeur de data-offset-top dynamique?

J'imagine que je vais devoir utiliser la méthode javascript, mais je suis tout à fait sûr.

31
bigmike7801

Vous pouvez utiliser jQuery pour obtenir une hauteur de contenu dynamique supérieure à navbar. Par exemple:

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

Démo de travail: http://bootply.com/69848

Dans certains cas, offset.bottom doit également être calculé pour déterminer quand "désapposer" l'élément. Voici un exemple d'affix-bottom

44
Zim

J'étais absolument frustré par la façon dont cela fonctionne, effectuant chaque fois des calculs personnalisés et la construction du décalage en fonction de la hauteur des éléments au-dessus de l'affixe souhaité. 

Voici l'affixe à son meilleur.

L'affixe normal de boostrap ne prend pas en compte la position de tête de l'offset naturel, vous devez le transmettre manuellement en tant qu'attribut. Cela s’occupe de cela, et tient compte de la modification du haut de l’offset lors du redimensionnement de la fenêtre.

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

J'ai aussi posté ceci sur code review .

N'oubliez pas d'ajouter l'attribut data-smart-affix à votre élément affixe

Essayez cet exemple de code: https://jsfiddle.net/NabiKAZ/qyrauogw/
(Dans cet exemple, la hauteur de la section rouge peut être 100px ou 200px ou 300px en largeur de fenêtre, il faut donc différencier data-offset-top lorsqu’il fait défiler.)

21
ThomasReggi

L'afficheur de données intelligent de Thomas Reggi ne fonctionnait pas dans certains cas (lors du redimensionnement du document ou lorsque la colonne apposée était trop haute) Mais cela m’a donné une idée simple: ajoutez un élément vide avant le contenu apposé et utilisez-le pour obtenir le décalage. Fonctionne bien lorsque redimensionné.

Pendant que j'y étais, j'ai également défini la largeur de l'élément comme étant sa largeur naturelle dans le parent d'origine. Voici ma solution:

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

Le HTML qui va avec est:

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

ou

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

Le CSS requis est:

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

Si vous souhaitez désactiver l'affixe (par exemple, lorsque la colonne de droite est empilée), utilisez le CSS:

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

dans la requête média appropriée.

GI

3
gi1242

Je vous suggère d’ajouter du wrapper autour de div attaché - pour éviter le "saut de défilement" avec la barre de navigation apposée. Thomas a posté une solution intéressante, mais elle n'inclut pas d'espace collé après affix et ne fonctionne pas dans la version 2.x boostrap que je dois utiliser. J'ai donc décidé d'écrire complètement une nouvelle implémentation d'affix. Il n’a pas besoin d’être boosté, juste jquery. C'est mon premier javascript, alors, s'il vous plaît, ayez pitié de nous :) mais cela aidera peut-être quelqu'un. C'est toujours agréable d'avoir une solution sans 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();
   });

});

Vous pouvez trouver un exemple ici: http://jsfiddle.net/3ss7fk92/

1
pixelofficer

J'ai eu beaucoup de problèmes avec cela plus tôt, et pour une raison quelconque, je ne pouvais obtenir aucune des solutions suggérées par d'autres personnes. Bootstrap et JQuery étant relativement nouveaux pour moi, je faisais probablement quelque chose d'étrange que je ne comprenais pas. Quoi qu’il en soit, j’ai trouvé une solution qui fonctionne vraiment bien, même si elle n’utilise pas à proprement parler la fonctionnalité affixe telle que l’entend Bootstrap. J'ai gardé mes CSS #thisElement.affix {top: desiredFixedPosition;} intactes, mais je me suis débarrassé des attributs data-spy et data-offset-top de la balise HTML de # thisElement. J'ai ensuite codé ceci dans 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);
}

Pour autant que j'ai testé, cela fonctionne quel que soit le redimensionnement ou le défilement de la page, et si vous faites preuve de créativité dans la façon dont vous l'appelez dans la fonction $(document).ready(), vous pourriez même laisser le menu rester à la bonne position pendant les animations en hauteur. Comme indiqué, ce n'est pas techniquement une solution entièrement "approuvée par Bootstrap", mais elle s'intègre suffisamment bien dans un site Bootstrap pour que cela fonctionne pour certains :)

0
Patrick Menard

Skelly ci-dessus est juste et il n'y a pas de meilleur moyen de le faire. La seule solution possible avec un amorçage "natif" consiste à attacher les options d'affixe à un appel JavaScript (comme indiqué plus haut dans https://stackoverflow.com/a/18702972/2546679 ).

Il est particulièrement non possible d'utiliser l'attribut data-offset pour obtenir le même effet (même si cela serait beaucoup plus pratique et même si la documentation de Affix sur http://getbootstrap.com/2.3.2 /javascript.html#affix soulève l’espoir que l’on pourrait le faire).

Donc on peut écrire 

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

mais on est pas autorisé à écrire, par exemple:

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

La raison en est que les attributs de données sont analysés via l'API JQuery .data() qui autorise uniquement l'analyse des valeurs JSON pures. Voir https://api.jquery.com/data/ .

0
haui

Thnx ThomasReggi pour une idée. Mais peut-être plus correct d'écrire:

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

pour ceux qui, comme moi, avaient également besoin d'une valeur inférieure qui écrirait de manière analogique.

BTW aussi je pense envelopper dans un décorateur basé sur setTimeout (un peu comme rebounce).

0
discodanser