Twitter Bootstrap - Abas - URL não muda

109

Estou usando o Twitter Bootstrap e suas "guias".

Eu tenho o seguinte código:

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

As guias funcionam corretamente, mas no URL não é adicionado o #add, #edit, #delete.

Quando eu removo data-toggleo URL muda, mas as guias não funcionam.

Alguma solução para isso?

Ivanka Todorova
fonte
1
Plug-in que corrige isso: github.com/timabell/jquery.stickytabs
Tim Abell
Esta é uma pergunta semelhante a stackoverflow.com/q/18999501/873282
koppor

Respostas:

269

Experimente este código. Ele adiciona a guia href ao url + abre a guia com base no hash no carregamento da página:

$(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
fonte
1
Funcionou muito bem. +1. Mas qual é a razão de "hash && $ .." do seletor é mostrar guia, mas o que significa "hash &&". Obrigado
richardhell
4
&&significa ANDque se a esquerda disso hashfor igual a verdadeiro ( não é 0, nulo ou vazio) e a direita for igual a verdadeiro, então faça algo, porém a linha termina com um, ;então não há nada a fazer antes ;e não importa se um guia é mostrado ou não e não importa o que .tab('show')retorna, ele ainda tentará. Ao avaliar a lógica desta forma, se a primeira parte da equação (antes &&) for falsa, não há necessidade de continuar avaliando, portanto a guia não será exibida. Você pode obter o mesmo efeito desta forma:if(hash){ $('ul.nav a[href="' + hash + '"]').tab('show'); }
vahanpwns
1
TL; DR: a && b;significa tentar ae, apenas se for verdade, tente b. As strings são verdadeiras se não estiverem vazias.
vahanpwns
8
Como eu faria para que apenas recarregasse a página no topo quando eu usar o url "#"? Agora, ele rola para baixo até onde as guias começam. Gostaria apenas de rolar para cima para a página real
kibaekr
1
funciona bem, mas teve que substituir "$ ('. nav-tabs a'). click (" por "$ ('# navtabs a'). on ('shown.bs.tabs," no Bootstrap 3
Zzirconium
49

Existem três componentes necessários para uma solução completa:

  1. Mostra a guia correta quando a página é carregada, se houver um hash no URL.
  2. Alterar o hash no URL quando a guia é alterada.
  3. Altere a guia quando o hash mudar na URL (botões voltar / avançar) e certifique-se de que a primeira guia seja alternada corretamente.

Não creio que nenhum dos comentários aqui, nem a resposta aceita, dê conta de todos esses cenários.

Como há bastante coisa envolvida, acho que é mais legal como um pequeno plugin jQuery: https://github.com/aidanlister/jquery-stickytabs

Você pode chamar o plug-in assim:

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

Fiz uma postagem no blog sobre isso, http://aidanlister.com/2014/03/persisting-the-tab-state-in-bootstrap/

Aidan
fonte
Dei a ele seu próprio repositório git: github.com/timabell/jquery.stickytabs - muito obrigado pelo plugin, funciona muito bem.
Tim Abell de
+1 para esta solução, pois também funciona na navegação posterior / próxima, o que a solução @tomaszback 'não funciona. Obrigado!
bitfidget
Isso é ótimo e funciona bem, mas não quando carrego a página com um hash na URL. Continuarei vasculhando para ter certeza de que fiz algo errado (altamente provável). No entanto, vou dar um +1
MattBoothDev
27

Usando data-toggle="tab" pede ao plugin para lidar com as abas, que ao fazer isso chama preventDefaulto evento ( código no github ).

Você pode usar a ativação de sua própria guia e deixar o evento prosseguir:

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

E você deve remover o atributo data-toggle="tab"

Verifique o doc se tiver dúvidas.

Sherbrow
fonte
11

Como seus elementos âncora já mudam o hash do url, ouvir o evento onhashchange é outra boa opção. Como @flori já mencionou, esse método funciona bem com o botão Voltar do navegador.

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

Por fim, acionar o evento logo após definir o ouvinte também ajudará a mostrar a guia correta no carregamento da página.

halilb
fonte
3

Minha solução para o seu problema:

Primeiro, adicione um novo data-valueatributo a cada alink, como este:

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

Em segundo lugar, altere os ids das guias, por exemplo, de addpara tab-add, atualize também hrefs para incluir o tab-prefixo:

<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 finalmente o código 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>

Aqui está o jsFiddle - mas não funciona por causa do iframe usado pelo jsFiddle, mas você pode ler a fonte da minha solução.

psulek
fonte
3

Mesmo problema com o CakePHP com Bootstrap 3 Tabs, mais quando eu envio com URL externa e âncora, ele salta para a seção perdendo meu menu, após revisar várias soluções feitas isso ...

obrigado 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
Henry Gabriel González Montejo
fonte
2

Também existe uma maneira simples de reagir às alterações de hash (por exemplo, botão Voltar). Basta adicionar um ouvinte de evento hashchange à solução 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
fonte
1

Estou usando o Bootstrap 3.3. * E nenhuma das soluções acima me ajudou, mesmo marcada como resposta um. Acabei de adicionar o script abaixo e funcionou.

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

Espero que isso ajude você.

Abhimanyu
fonte
0

Mais simples, supondo que você esteja usando a data-toggle="tab"sintaxe documentada descrita aqui :

$(document).on('shown.bs.tab', function(event) {
  window.location.hash = $(event.target).attr('href');
});
Fred
fonte
Isso muda o URL, mas não pode ir para lá ao clicar em um link para abrir uma guia específica
Khrys
0

Para aqueles que usam Ruby on Rails ou qualquer outro script do lado do servidor, você vai querer usar a anchoropção de caminhos. Isso ocorre porque, uma vez que a página carrega, ela não tem o hash de URL disponível. Você deve fornecer a guia correta por meio de seu link ou envio de formulário.

<%= 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 você estiver usando um prefixo para evitar que a janela pule para o id:

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

Então você 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);
});

Isso deve funcionar no Bootstrap 3.

Mohamad
fonte
0

Obrigado a @tomaszbak pela solução original, entretanto, como minhas edições foram rejeitadas e não posso comentar sobre sua postagem, deixarei minha versão um pouco melhorada e mais legível aqui.

Ele faz basicamente a mesma coisa, mas se corrige o problema de compatibilidade entre navegadores que tive com o dele.

$(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
fonte
Rejeitado não estava funcionando para mim (talvez fosse apenas a versão do Firefox). De qualquer forma, alterei var scrollmem = $ ('body'). ScrollTop () || $ ('html'). scrollTop (); Obrigado!
tomaszbak
1
Sim. Conte-me sobre isso no momento em que você disse que percebi que era um navegador e rapidamente entrei no cromo para ter certeza. Eu realmente gostaria que houvesse uma maneira de comentar sobre as revisões de edição
Fuxy
0

Aqui está uma opção de usar history.pushStatepara que você possa usar o histórico do seu navegador para voltar a uma guia anterior

  $(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 Ei
fonte
0

Nenhuma das opções acima funcionou para mim, então aqui está como fiz o meu funcionar:

  1. Adicionar class="tab-link"a todos os links que precisam desta funcionalidade
  2. Adicione o seguinte código ao seu javascript:
    window.addEventListener
    (
        'popstate',
        função (evento)
        {
            tab_change ();
        }
    );

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

        $ ('.tab-link') .clique
        (
            função (e)
            {
                $ (este) .tab ('mostrar');

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

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

simonl
fonte
0

Eu entendi que o OP disse usando JQuery, mas você pode simplesmente usar o vanilla JS para fazer isso:

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

Isso também corrige uma guia extremamente obscura, um href que não dispara ao usar 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>
Raio
fonte
5
-1 Não vejo como esta resposta agrega qualquer valor às respostas já anteriores fornecidas há 3 meses com exatamente o mesmo código na resposta. Portanto, não é uma resposta útil em minha humilde opinião.
Não