Twitter Bootstrap - Zakładki - URL się nie zmienia


109

Używam Twitter Bootstrap i jego „zakładek”.

Mam następujący kod:

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

Karty działają poprawnie, ale w adresie URL nie jest dodawany #add, #edit, #delete.

Kiedy data-toggleusuwam zmiany adresu URL, ale karty nie działają.

Jakieś rozwiązania?


1
Wtyczka, która rozwiązuje ten problem
Tim Abell

To jest podobne pytanie, co stackoverflow.com/q/18999501/873282
koppor

Odpowiedzi:


269

Wypróbuj ten kod. Dodaje tab href do url + otwiera kartę na podstawie skrótu po załadowaniu strony:

$(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
Działa bardzo dobrze. +1. Ale co jest powodem wstawienia „hash && $ ..” z selektora to show tab, ale co oznacza „hash &&”. Dziękuję
richardhell

4
&&oznacza ANDwięc, że jeśli lewa strona to prawda ( hashnie jest 0, zero lub pusta), a prawa równa się prawdzie, zrób coś, jednak linia kończy się na, ;więc nie ma nic do zrobienia wcześniej ;i nie ma znaczenia, czy Karta jest wyświetlana lub nie i nie ma znaczenia, co .tab('show')zwróci, nadal będzie próbować. Podczas obliczania logiki w ten sposób, jeśli pierwsza część równania (przed &&) jest fałszywa, nie ma potrzeby dalszego oceniania, więc karta nie zostanie wyświetlona. Możesz osiągnąć ten sam efekt w następujący sposób:if(hash){ $('ul.nav a[href="' + hash + '"]').tab('show'); }
vahanpwns

1
TL; DR: a && b;oznacza spróbować ai tylko wtedy, gdy jest to prawda, spróbuj b. Ciągi znaków są prawdziwe, jeśli nie są puste.
vahanpwns

8
Jak mam to zrobić, aby po prostu przeładowywała stronę u góry, gdy używam adresu URL „#”? W tej chwili przewija się w dół do miejsca, w którym zaczynają się zakładki. Chciałbym tylko przewinąć na górę do aktualnej strony
kibaekr

1
działa dobrze, ale musiał zastąpić "$ ('. nav-tabs a'). click (" by "$ ('# navtabs a'). on ('shown.bs.tabs," on Bootstrap 3
Zzirconium,

49

Kompletne rozwiązanie wymaga trzech elementów:

  1. Pokaż poprawną kartę po załadowaniu strony, jeśli adres URL zawiera hash.
  2. Zmiana skrótu w adresie URL po zmianie karty.
  3. Zmień kartę, gdy hash zmienia się w adresie URL (przyciski Wstecz / Dalej) i upewnij się, że pierwsza karta jest poprawnie przełączana.

Nie sądzę, aby którykolwiek z poniższych komentarzy ani zaakceptowana odpowiedź dotyczyły wszystkich tych scenariuszy.

Ponieważ jest trochę w to zaangażowany, myślę, że jest najładniejszy jako mała wtyczka jQuery: https://github.com/aidanlister/jquery-stickytabs

Możesz zadzwonić do wtyczki w następujący sposób:

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

Napisałem w tym celu wpis na blogu, http://aidanlister.com/2014/03/persisting-the-tab-state-in-bootstrap/


Dałem mu własne repozytorium git: github.com/timabell/jquery.stickytabs - wielkie dzięki za wtyczkę, działa świetnie .
Tim Abell

+1 dla tego rozwiązania, ponieważ działa również podczas przeglądania wstecz / następnego, czego rozwiązanie @tomaszback 'nie działa. Dzięki!
bitfidget

To jest świetne i działa dobrze, ale nie wtedy, gdy ładuję stronę z hashem w adresie URL. Będzie szukał dalej, aby upewnić się, że zrobiłem coś złego (bardzo prawdopodobne). Jednak dam mu +1
MattBoothDev

27

Użycie data-toggle="tab" prosi wtyczkę o obsługę zakładek, która podczas wykonywania wywołuje preventDefaultzdarzenie ( kod na github ).

Możesz użyć własnej aktywacji karty i pozwolić wydarzeniu przejść:

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

Musisz usunąć atrybut data-toggle="tab"

Sprawdź dokument, jeśli masz wątpliwości.


11

Ponieważ elementy zakotwiczenia już zmieniają skrót adresu URL, kolejną dobrą opcją jest nasłuchiwanie zdarzenia onhashchange . Jak już wspomniałem @flori, ta metoda działa dobrze z przyciskiem Wstecz przeglądarki.

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

Wreszcie, wyzwolenie zdarzenia zaraz po zdefiniowaniu odbiornika pomoże również wyświetlić odpowiednią kartę podczas ładowania strony.


3

Moje rozwiązanie twojego problemu:

Najpierw dodaj nowy data-valueatrybut do każdego alinku, na przykład:

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

Po drugie, zmień identyfikatory zakładek, np. Z addna tab-add, zaktualizuj także href, aby zawierały tab-przedrostek:

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

I na koniec kod 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>

Oto jsFiddle - ale nie działa z powodu iframe używanego przez jsFiddle, ale możesz przeczytać źródło mojego rozwiązania.


3

Ten sam problem z CakePHP z zakładkami Bootstrap 3, a kiedy wysyłam z zewnętrznym adresem URL i kotwicą, przeskakuje do sekcji tracącej menu, po przejrzeniu wielu rozwiązań sprawiło, że ...

dzięki: 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

Istnieje również prosty sposób reagowania na zmiany skrótu (np. Przycisk Wstecz). Po prostu dodaj detektor zdarzeń hashchange do rozwiązania 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

Używam Bootstrap 3.3. * I żadne z powyższych rozwiązań mi nie pomogło, nawet oznaczone jako odpowiedź. Właśnie dodałem poniższy skrypt i działałem.

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

Mam nadzieję, że to ci pomoże.


0

Najprostsze, zakładając, że używasz udokumentowanej data-toggle="tab"składni opisanej tutaj :

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

To zmienia adres URL, ale nie można tam przejść po kliknięciu linku, aby otworzyć określoną kartę
Khrys

0

Dla tych, którzy używają Ruby on Rails lub jakiegokolwiek innego skryptu po stronie serwera, będziesz chciał użyć anchoropcji na ścieżkach. Dzieje się tak, ponieważ po załadowaniu strony nie ma dostępnego skrótu adresu URL. Będziesz chciał podać właściwą kartę za pośrednictwem łącza lub przesłanego formularza.

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

Jeśli używasz prefiksu, aby zapobiec przeskakiwaniu okna do id:

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

Następnie 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

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

To powinno działać w Bootstrap 3.


0

Dzięki @tomaszbak za oryginalne rozwiązanie, jednak ponieważ moje zmiany zostały odrzucone i nie mogę komentować jego postu, zostawię tutaj moją nieco poprawioną i bardziej czytelną wersję.

Zasadniczo robi to samo, ale jeśli rozwiązuje problem ze zgodnością z różnymi przeglądarkami, który miałem z jego.

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

Odrzucona nie działała dla mnie (może to była tylko wersja Firefox). W każdym razie dokonałem zmiany na var scrollmem = $ ('body'). ScrollTop () || $ ('html'). scrollTop (); Dzięki!
tomaszbak

1
Tak. Opowiedz mi o tym w chwili, gdy powiedziałeś, że zdałem sobie sprawę, że to przeglądarka i szybko przeszedłem do Chrome, aby się upewnić. Chciałbym, żeby istniał sposób komentowania recenzji edycji.
Fuxy

0

Oto opcja za pomocą, history.pushStatedzięki której możesz użyć historii przeglądarki, aby wrócić do poprzedniej karty

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

Żadne z powyższych nie działało dla mnie, więc oto mój sposób, w jaki mój działa:

  1. Dodaj class="tab-link"do wszystkich łączy, które wymagają tej funkcji
  2. Dodaj następujący kod do swojego javascript:
    window.addEventListener
    (
        'popstate',
        funkcja (zdarzenie)
        {
            tab_change ();
        }
    );

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

        $ ('.tab-link') .click
        (
            funkcja (e)
            {
                $ (this) .tab ('show');

                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

Zrozumiałem, że OP powiedział, że używa JQuery, ale możesz po prostu użyć vanilla JS, aby to zrobić:

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

-2

Naprawia to również bardzo mało znaną kartę a href, która nie jest uruchamiana podczas używania jquery i 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 Nie widzę, jak ta odpowiedź wnosi jakąkolwiek wartość do wcześniejszych odpowiedzi udzielonych 3 miesiące temu z dokładnie tym samym kodem w odpowiedzi. Dlatego moim skromnym zdaniem nie jest to użyteczna odpowiedź.
Nie
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.