Twitter Bootstrap - Onglets - L'URL ne change pas

109

J'utilise Twitter Bootstrap et ses "onglets".

J'ai le code suivant:

<ul class="nav nav-tabs">
    <li class="active"><a data-toggle="tab" href="#add">add</a></li>
    <li><a data-toggle="tab" href="#edit" >edit</a></li>
    <li><a data-toggle="tab" href="#delete" >delete</a></li>
</ul>

Les onglets fonctionnent correctement, mais dans l'URL n'est pas ajouté les #add, #edit, #delete.

Lorsque je supprime data-togglel'URL change, mais les onglets ne fonctionnent pas.

Des solutions pour cela?

Ivanka Todorova
la source
1
Plugin qui corrige ceci: github.com/timabell/jquery.stickytabs
Tim Abell
C'est une question similaire à stackoverflow.com/q/18999501/873282
koppor

Réponses:

269

Essayez ce code. Il ajoute l'onglet href à l'url + ouvre l'onglet en fonction du hachage lors du chargement de la page:

$(function(){
  var hash = window.location.hash;
  hash && $('ul.nav a[href="' + hash + '"]').tab('show');

  $('.nav-tabs a').click(function (e) {
    $(this).tab('show');
    var scrollmem = $('body').scrollTop() || $('html').scrollTop();
    window.location.hash = this.hash;
    $('html,body').scrollTop(scrollmem);
  });
});
tomaszbak
la source
1
Cela fonctionne très bien. +1. Mais quelle est la raison de "hash && $ .." du sélecteur est show tab, mais que signifie "hash &&". Merci
richardhell
4
&&signifie ANDque si la gauche de cela équivaut à vrai ( hashn'est pas 0, nul ou vide) et la droite équivaut à vrai, alors faites quelque chose, mais la ligne se termine par un ;donc il n'y a rien à faire avant ;et peu importe si un tab est affiché ou non et peu importe ce qui .tab('show')revient, il essaiera toujours. Lors de l'évaluation de la logique de cette manière, si la première partie de l'équation (avant &&) est fausse, il n'est pas nécessaire de continuer l'évaluation, donc l'onglet ne sera pas affiché. Vous pouvez obtenir le même effet comme ceci:if(hash){ $('ul.nav a[href="' + hash + '"]').tab('show'); }
vahanpwns
1
TL; DR: a && b;signifie essayer aet seulement si c'est vrai, essayez b. Les chaînes sont vraies si elles ne sont pas vides.
vahanpwns le
8
Comment pourrais-je faire en sorte qu'il recharge simplement la page en haut lorsque j'utilise l'url "#"? À l'heure actuelle, il fait défiler jusqu'à l'endroit où les onglets commencent. Je voudrais juste faire défiler vers le haut jusqu'à la page réelle
kibaekr
1
fonctionne bien mais a dû remplacer "$ ('. nav-tabs a'). click (" par "$ ('# navtabs a'). on ('shown.bs.tabs," on Bootstrap 3
Zzirconium
49

Trois composants sont nécessaires pour une solution complète:

  1. Afficher l'onglet correct lorsque la page est chargée s'il y a un hachage dans l'URL.
  2. Modification du hachage dans l'URL lorsque l'onglet est modifié.
  3. Changez l'onglet lorsque le hachage change dans l'URL (boutons Précédent / Suivant) et assurez-vous que le premier onglet est correctement cyclé.

Je ne pense pas que les commentaires ici, ni la réponse acceptée, traitent tous ces scénarios.

Comme il y a un peu d'implication, je pense que c'est plus intéressant en tant que petit plugin jQuery: https://github.com/aidanlister/jquery-stickytabs

Vous pouvez appeler le plugin comme ceci:

$('.nav-tabs').stickyTabs();

J'ai fait un article de blog pour cela, http://aidanlister.com/2014/03/persisting-the-tab-state-in-bootstrap/

Aidan
la source
Je lui ai donné son propre dépôt git: github.com/timabell/jquery.stickytabs - merci beaucoup pour le plugin, fonctionne un régal.
Tim Abell
+1 pour cette solution car elle fonctionne également sur la navigation précédente / suivante, ce que la solution @tomaszback 'ne fait pas. Merci!
bitfidget
C'est génial et fonctionne bien, mais pas lorsque je charge la page avec un hachage dans l'URL. Je vais continuer à fouiller pour m'assurer que c'est quelque chose que j'ai mal fait (très probable). Cependant, je vais lui donner un +1
MattBoothDev
27

L'utilisation data-toggle="tab" demande au plugin de gérer les onglets, qui en le faisant appelle preventDefaultl'événement ( code sur github ).

Vous pouvez utiliser votre propre activation d'onglet et laisser l'événement passer:

$('.nav-tabs a').click(function (e) {
    // No e.preventDefault() here
    $(this).tab('show');
});

Et vous devez supprimer l'attribut data-toggle="tab"

Consultez la doc si vous avez des doutes.

Sherbrow
la source
11

Comme vos éléments d'ancrage modifient déjà le hachage de l'url, écouter l' événement onhashchange est une autre bonne option. Comme @flori l'a déjà mentionné, cette méthode fonctionne bien avec le bouton de retour du navigateur.

var tabs$ = $(".nav-tabs a");

$( window ).on("hashchange", function() {
    var hash = window.location.hash, // get current hash
        menu_item$ = tabs$.filter('[href="' + hash + '"]'); // get the menu element

    menu_item$.tab("show"); // call bootstrap to show the tab
}).trigger("hashchange");

Enfin, le déclenchement de l'événement juste après avoir défini l'auditeur aidera également à afficher le bon onglet lors du chargement de la page.

halilb
la source
3

Ma solution à votre problème:

Ajoutez d'abord un nouvel data-valueattribut à chaque alien, comme ceci:

<ul class="nav nav-tabs">
    <li class="active">
        <a data-toggle="tab" href="#tab-add" data-value="#add">add</a>
    </li>
    <li>
        <a data-toggle="tab" href="#tab-edit" data-value="#edit">edit</a>
    </li>
    <li>
        <a data-toggle="tab" href="#tab-delete" data-value="#delete">delete</a>
    </li>
</ul>

Deuxièmement, changez les identifiants des onglets, par exemple de addà tab-add, mettez également à jour hrefs pour inclure le tab-préfixe:

<div class="tab-content">
    <div class="tab-pane" id="tab-add">Add panel</div>
    <div class="tab-pane" id="tab-edit">Edit panel</div>
    <div class="tab-pane" id="tab-delete">Panel panel</div>
</div>

Et enfin le code js:

<script type="text/javascript">
    $(function () {
        var navTabs = $('.nav-tabs a');
        var hash = window.location.hash;
        hash && navTabs.filter('[data-value="' + hash + '"]').tab('show');

        navTabs.on('shown', function (e) {
            var newhash = $(e.target).attr('data-value');
            window.location.hash = newhash;
        });
    })
</script>

Voici jsFiddle - mais cela ne fonctionne pas à cause de l'iframe utilisé par jsFiddle, mais vous pouvez lire la source de ma solution.

psulek
la source
3

Même problème avec CakePHP avec Bootstrap 3 Tabs, plus quand j'envoie avec une URL externe et une ancre, il saute à la section perdant mon menu, après examen de nombreuses solutions ont fait ceci ...

merci à: http://ck.kennt-wayne.de/2012/dec/twitter-bootstrap-how-to-fix-tabs

$(document).ready(function()
 {  
//Redirecciona al tab, usando un prefijo al cargar por primera vez, al usar redirect en cake #_Pagos    
//Redirecciona al tab, usando #Pagos
/* Automagically jump on good tab based on anchor; for page reloads or links */
 if(location.hash) 
  {
     $('a[href=' + location.hash + ']').tab('show');         
  }


//Para evitar el bajar al nivel del tab, (al mostrarse el tab subimos)
$('a[data-toggle="tab"]').on('shown.bs.tab', function(e) 
{
    location.hash = $(e.target).attr('href').substr(1);
    scrollTo(0,0);      
});



//Actualiza el URL con el anchor o ancla del tab al darle clic
 /* Update hash based on tab, basically restores browser default behavior to
 fix bootstrap tabs */
$(document.body).on("click", "a[data-toggle]", function(event) 
  {
    location.hash = this.getAttribute("href");
  });


//Redirecciona al tab, al usar los botones de regresar y avanzar del navegador.
/* on history back activate the tab of the location hash if exists or the default tab if no hash exists */   
$(window).on('popstate', function() 
{
  //Si se accesa al menu, se regresa al tab del perfil (activo default), fixed conflict with menu
  //var anchor = location.hash || $("a[data-toggle=tab]").first().attr("href");
  var anchor = location.hash;
  $('a[href=' + anchor + ']').tab('show');

});   

});//Fin OnReady
Henry Gabriel González Montejo
la source
2

Il existe également un moyen simple de réagir aux changements de hachage (par exemple, le bouton de retour). Ajoutez simplement un écouteur d'événement hashchange à la solution tomaszbak:

$(function(){
  // Change tab on load
  var hash = window.location.hash;
  hash && $('ul.nav a[href="' + hash + '"]').tab('show');

  $('.nav-tabs a').click(function (e) {
    $(this).tab('show');
    var scrollmem = $('body').scrollTop();
    window.location.hash = this.hash;
    $('html,body').scrollTop(scrollmem);
  });

  // Change tab on hashchange
  window.addEventListener('hashchange', function() {
    var changedHash = window.location.hash;
    changedHash && $('ul.nav a[href="' + changedHash + '"]').tab('show');
  }, false);
});
Flori
la source
1

J'utilise Bootstrap 3.3. * Et aucune des solutions ci-dessus ne m'a aidé, même marqué comme réponse un. Je viens d'ajouter le script ci-dessous et j'ai travaillé.

$(function(){
    var hash = document.location.hash;
    if (hash) {
       $('.navbar-nav a[href="' + hash + '"]').tab('show');
    }
    $('a[data-toggle="tab"]').on('click', function (e) {
       history.pushState(null, null, $(this).attr('href'));
    });
});

J'espère que cela vous aide.

Abhimanyu
la source
0

Le plus simple, en supposant que vous utilisez le document data-toggle="tab" syntaxe décrite ici :

$(document).on('shown.bs.tab', function(event) {
  window.location.hash = $(event.target).attr('href');
});
Fred
la source
Cela modifie l'URL mais ne peut pas y aller lorsque vous cliquez sur un lien pour ouvrir un onglet spécifique
Khrys
0

Pour ceux qui utilisent Ruby on Rails ou tout autre script côté serveur, vous souhaiterez utiliser l' anchoroption sur les chemins. En effet, une fois la page chargée, le hachage d'URL n'est pas disponible. Vous voudrez fournir le bon onglet via votre lien ou la soumission de formulaire.

<%= form_for @foo, url: foo_path(@foo, anchor: dom_id(foo)) do |f| %>
# Or
<%= link_to 'Foo', foo_path(@foo, anchor: dom_id(foo)) %>

Si vous utilisez un préfixe pour empêcher la fenêtre de sauter à l'ID:

<%= form_for @foo, url: foo_path(@foo, anchor: "bar_#{dom_id(foo)}") do |f| %>

Ensuite, vous CoffeeScript:

  hash = document.location.hash
  prefix = 'bar_'
  $('.nav-tabs a[href=' + hash.replace(prefix, '') + ']').tab 'show' if hash
  $('.nav-tabs a').on 'shown.bs.tab', (e) ->
    window.location.hash = e.target.hash.replace '#', '#' + prefix

Ou JavaScript:

var hash, prefix;

hash = document.location.hash;
prefix = 'bar_';

if (hash) {
  $('.nav-tabs a[href=' + hash.replace(prefix, '') + ']').tab('show');
}

$('.nav-tabs a').on('shown.bs.tab', function(e) {
  window.location.hash = e.target.hash.replace('#', '#' + prefix);
});

Cela devrait fonctionner dans Bootstrap 3.

Mohamad
la source
0

Merci à @tomaszbak pour la solution originale cependant, puisque mes modifications ont été rejetées et que je ne peux pas encore commenter son message, je vais laisser ma version légèrement améliorée et plus lisible ici.

Il fait essentiellement la même chose, mais corrige le problème de compatibilité entre navigateurs que j'avais avec le sien.

$(document).ready(function(){
   // go to hash on window load
   var hash = window.location.hash;
   if (hash) {
       $('ul.nav a[href="' + hash + '"]').tab('show');
   }
   // change hash on click
   $('.nav-tabs a').click(function (e) {
       $(this).tab('show');
       if($('html').scrollTop()){
           var scrollmem = $('html').scrollTop(); // get scrollbar position (firefox)
       }else{
           var scrollmem = $('body').scrollTop(); // get scrollbar position (chrome)
       }
       window.location.hash = this.hash;
       $('html,body').scrollTop(scrollmem); // set scrollbar position
   });
});
Fuxy
la source
Rejeté ne fonctionnait pas pour moi (c'était peut-être juste la version Firefox). Quoi qu'il en soit, j'ai modifié var scrollmem = $ ('body'). ScrollTop () || $ ('html'). scrollTop (); Merci!
tomaszbak
1
Oui. Parlez-moi du moment où vous avez dit que je me suis rendu compte que c'était un navigateur et que je suis rapidement entré dans Chrome pour m'en assurer. J'aurais bien aimé qu'il y ait un moyen de commenter les avis d'édition.
Fuxy
0

Voici une option history.pushStatequi vous permet d'utiliser l'historique de votre navigateur pour revenir à un onglet précédent

  $(document).ready(function() {
  // add a hash to the URL when the user clicks on a tab
  $('a[data-toggle="tab"]').on('click', function(e) {
    history.pushState(null, null, $(this).attr('href'));
  });
  // navigate to a tab when the history changes
  window.addEventListener("popstate", function(e) {
    var activeTab = $('[href=' + location.hash + ']');
    if (activeTab.length) {
      activeTab.tab('show');
    } else {
      $('.nav-tabs a:first').tab('show');
    }
  });
});
Adam Hey
la source
0

Aucun de ces éléments n'a fonctionné pour moi, alors voici comment j'ai fait fonctionner le mien:

  1. Ajouter class="tab-link"à tous les liens nécessitant cette fonctionnalité
  2. Ajoutez le code suivant à votre javascript:
    window.addEventListener
    (
        «popstate»,
        fonction (événement)
        {
            tab_change ();
        }
    );

    fonction tab_change ()
    {
        var hash = window.location.hash;
        hash && $ ('ul.nav a [href = "' + hash + '"]') .tab ('show');

        $ ('.tab-link') .cliquez
        (
            fonction (e)
            {
                $ (this) .tab ('montrer');

                var scrollmem = $ ('corps') .scrollTop () || $ ('html') .scrollTop ();
                window.location.hash = this.hash;
                $ ('html, corps') .scrollTop (scrollmem);

                $ ('ul.nav-tabs a [href = "' + window.location.hash + '"]') .tab ('show');
            }
        );
    }

Simonl
la source
0

J'ai compris qu'OP disait utiliser JQuery mais vous pouvez simplement utiliser vanilla JS pour le faire:

document.querySelectorAll('ul.nav a.nav-link').forEach(link => {
    link.onclick = () => window.history.pushState(null, null, link.attributes.href.value);
});
RousseauAlexandre
la source
-2

Cela corrige également un onglet extrêmement obscur qu'un href ne se déclenche pas lors de l'utilisation de jquery et bootstrap

<script src="//ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script> 

<script type="text/javascript">
$('.nav-tabs a').click(function (e) {
    // No e.preventDefault() here.
    $(this).tab('show');
});
</script>

<script src="//netdna.bootstrapcdn.com/twitter-bootstrap/2.2.1/js/bootstrap.min.js"></script>
Rayon
la source
5
-1 Je ne vois pas comment cette réponse ajoute de la valeur aux réponses déjà précédentes données il y a 3 mois avec exactement le même code dans la réponse. Donc pas une réponse utile à mon humble avis.
Non