Twitter Bootstrap - Schede - L'URL non cambia


109

Sto usando Twitter Bootstrap e le sue "schede".

Ho il codice seguente:

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

Le schede funzionano correttamente, ma nell'URL non viene aggiunto #add, #edit, #delete.

Quando rimuovo data-togglel'URL cambia, ma le schede non funzionano.

Qualche soluzione per questo?


1
Plugin che risolve questo problema: github.com/timabell/jquery.stickytabs
Tim Abell

Questa è una domanda simile a stackoverflow.com/q/18999501/873282
koppor

Risposte:


269

Prova questo codice. Aggiunge la scheda href a url + apre la scheda in base all'hash al caricamento della pagina:

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

1
Funziona molto bene. +1. Ma qual è la ragione di "hash && $ .." dal selettore è la scheda mostra, ma cosa significa "hash &&". Grazie
richardhell

4
&&significa ANDquindi se la sinistra di ciò corrisponde a vero ( hashnon è 0, nullo o vuoto) e la destra equivale a vero allora fai qualcosa, tuttavia la linea finisce con a ;quindi non c'è niente da fare prima ;e non importa se a la scheda viene visualizzata o meno e non importa cosa .tab('show')ritorna, proverà comunque. Quando si valuta la logica in questo modo, se la prima parte dell'equazione (prima &&) è falsa, non è necessario continuare a valutare, quindi la scheda non verrà visualizzata. Potresti ottenere lo stesso effetto in questo modo:if(hash){ $('ul.nav a[href="' + hash + '"]').tab('show'); }
vahanpwn

1
TL; DR: a && b;significa provare ae solo se è vero, provare b. Le stringhe sono vere se non sono vuote.
vahanpwn il

8
Come posso fare in modo che ricarichi la pagina in alto quando uso l'URL "#"? In questo momento scorre verso il basso fino al punto in cui iniziano le schede. Vorrei solo scorrere in alto fino alla pagina effettiva
kibaekr

1
funziona bene ma ha dovuto sostituire "$ ('. nav-tabs a'). click (" by "$ ('# navtabs a'). on ('shown.bs.tabs," on Bootstrap 3
Zzirconium

49

Ci sono tre componenti necessari per una soluzione completa:

  1. Mostra la scheda corretta quando la pagina viene caricata se c'è un hash nell'URL.
  2. Modifica dell'hash nell'URL quando viene modificata la scheda.
  3. Modificare la scheda quando l'hash cambia nell'URL (pulsanti indietro / avanti) e assicurarsi che la prima scheda venga visualizzata correttamente.

Non credo che nessuno dei commenti qui, né la risposta accettata, gestiscano tutti questi scenari.

Dato che è coinvolto un po ', penso che sia il più accurato come piccolo plugin jQuery: https://github.com/aidanlister/jquery-stickytabs

Puoi chiamare il plugin in questo modo:

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

Ho scritto un post sul blog per questo, http://aidanlister.com/2014/03/persisting-the-tab-state-in-bootstrap/


Gli ho dato il suo repository git: github.com/timabell/jquery.stickytabs - molte grazie per il plugin, funziona a meraviglia.
Tim Abell

+1 per questa soluzione in quanto funziona anche durante la navigazione indietro / successiva che la soluzione @tomaszback non fa. Grazie!
bitfidget

È fantastico e funziona bene, ma non quando carico la pagina con un hash nell'URL. Continuerò a scavare per assicurarmi che sia qualcosa che ho fatto di sbagliato (molto probabile). Tuttavia, darò un +1
MattBoothDev

27

Using data-toggle="tab" chiede al plugin di gestire le schede, che mentre lo fa chiama preventDefaultl'evento ( codice su GitHub ).

Puoi utilizzare l'attivazione della tua scheda e lasciare che l'evento si svolga:

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

E devi rimuovere l'attributo data-toggle="tab"

Controlla il documento se hai dubbi.


11

Poiché i tuoi elementi di ancoraggio cambiano già l'hash dell'URL , l'ascolto dell'evento onhashchange è un'altra buona opzione. Come già menzionato da @flori, questo metodo funziona bene con il pulsante Indietro del browser.

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");

Infine, l'attivazione dell'evento subito dopo aver definito il listener aiuterà anche a mostrare la scheda destra al caricamento della pagina.


3

La mia soluzione al tuo problema:

Per prima cosa aggiungi un nuovo data-valueattributo a ogni alink, in questo modo:

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

In secondo luogo, cambia gli ID delle schede, ad esempio da adda tab-add, aggiorna anche hrefs per includere il tab-prefisso:

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

E infine il codice 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>

Ecco jsFiddle , ma non funziona a causa dell'iframe utilizzato da jsFiddle, ma puoi leggere l'origine della mia soluzione.


3

Stesso problema con CakePHP con Bootstrap 3 Tabs, inoltre quando invio con URL esterno e ancoraggio, salta alla sezione che perde il mio menu, dopo aver esaminato molte soluzioni hanno reso questo ...

grazie a: 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

2

C'è anche un modo semplice per reagire ai cambiamenti di hash (es. Pulsante Indietro). Aggiungi semplicemente un listener di eventi hashchange alla soluzione 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);
});

1

Sto usando Bootstrap 3.3. * E nessuna delle soluzioni precedenti mi ha aiutato, nemmeno contrassegnata come risposta uno. Ho appena aggiunto lo script di seguito e ho lavorato.

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

Spero che questo ti aiuti.


0

Molto semplice, supponendo che tu stia utilizzando la data-toggle="tab"sintassi documentata descritta qui :

$(document).on('shown.bs.tab', function(event) {
  window.location.hash = $(event.target).attr('href');
});

Questo cambia l'URL ma non può andare lì quando si fa clic su un collegamento per aprire una scheda specifica
Khrys

0

Per coloro che utilizzano Ruby on Rails o qualsiasi altro script lato server, ti consigliamo di utilizzare l' anchoropzione sui percorsi. Questo perché una volta caricata la pagina, non è disponibile l'hash dell'URL. Dovrai fornire la scheda corretta tramite il tuo link o l'invio del modulo.

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

Se stai usando un prefisso per evitare che la finestra salti sull'id:

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

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

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

Questo dovrebbe funzionare in Bootstrap 3.


0

Grazie a @tomaszbak per la soluzione originale, tuttavia, poiché le mie modifiche sono state rifiutate e non sono in grado di commentare il suo post, lascerò qui la mia versione leggermente migliorata e più leggibile.

Fondamentalmente fa la stessa cosa, ma se risolve il problema di compatibilità tra browser che ho avuto con il suo.

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

Rifiutato non funzionava per me (forse era solo la versione di Firefox). Ad ogni modo, ho apportato modifiche a var scrollmem = $ ('body'). ScrollTop () || $ ( 'html') scrollTop ().; Grazie!
tomaszbak

1
Sì. Dimmelo nel momento in cui hai detto che mi ero reso conto che era una cosa del browser e sono entrato rapidamente in Chrome per assicurarmene. Vorrei sicuramente che ci fosse un modo per commentare le recensioni di modifica.
Fuxy

0

Ecco un'opzione history.pushStateche consente di utilizzare la cronologia del browser per tornare a una scheda precedente

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

0

Nessuno dei precedenti ha funzionato per me, quindi ecco come ho fatto funzionare il mio:

  1. Aggiungi class="tab-link"a tutti i link che richiedono questa funzionalità
  2. Aggiungi il seguente codice al tuo javascript:
    window.addEventListener
    (
        'Popstate',
        funzione (evento)
        {
            tab_change ();
        }
    );

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

        $ ('.tab-link'). fare clic
        (
            funzione (e)
            {
                $ (questo) .tab ('mostra');

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

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


0

Ho capito che OP ha detto usando JQuery ma puoi semplicemente usare JS vanilla per farlo:

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

-2

Questo risolve anche una scheda estremamente oscura che un href non si attiva quando si usa jquery e 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>

5
-1 Non vedo come questa risposta aggiunga alcun valore alle risposte già precedenti fornite 3 mesi fa con lo stesso identico codice nella risposta. Quindi non è una risposta utile a mio modesto parere.
No
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.