Pestañas Bootstrap de Twitter: vaya a la pestaña específica en la página Recargar o hipervínculo

358

Estoy desarrollando una página web en la que estoy usando el Framework Bootstrap de Twitter y sus Bootstrap Tabs JS . Funciona muy bien, excepto por algunos problemas menores, uno de los cuales es que no sé cómo ir directamente a una pestaña específica desde un enlace externo. Por ejemplo:

<a href="facility.php#home">Home</a>
<a href="facility.php#notes">Notes</a>

debe ir a la pestaña Inicio y a la pestaña Notas respectivamente cuando se hace clic en los enlaces desde una página externa

mraliks
fuente
49
¡Desearía que esto fuera construido!
Damon
55
Esta pregunta también se ha planteado aquí: github.com/twitter/bootstrap/issues/2415 (y tiene un par de soluciones allí).
Ztyx
esto me ayudó -> stackoverflow.com/questions/12131273/…
JGilmartin
1
El enlace actualizado al problema de bootstrap es github.com/twbs/bootstrap/issues/2415
bmihelac
3
Complemento que soluciona esto: github.com/timabell/jquery.stickytabs
Tim Abell

Respuestas:

603

Aquí está mi solución al problema, quizás un poco tarde. Pero tal vez podría ayudar a otros:

// Javascript to enable link to tab
var url = document.location.toString();
if (url.match('#')) {
    $('.nav-tabs a[href="#' + url.split('#')[1] + '"]').tab('show');
} 

// Change hash for page-reload
$('.nav-tabs a').on('shown.bs.tab', function (e) {
    window.location.hash = e.target.hash;
})
Dubbe
fuente
83
Agregaría 1 línea adicional más window.scrollTo(0, 0);para asegurarme de que la ventana siempre se desplace hacia arriba
Trung Lê
1
$ ('. nav-tabs a [href * = #' + url.split ('#') [1] + ']'). tab ('show'); // Con un * es más seguro ya que de lo contrario solo coincide con el primer # ...
mattangriffel
1
En línea que funcionó para mí: window.location.hash && $ ('li a [href = "' + window.location.hash + '"]'). Tab ('show'). Trigger ("click");
Dean Meehan
10
Aquí hay una demostración de Bootstrap 3: bootply.com/render/VQqzOawoYc#tab2 y el código fuente
Zim
2
Después de jQuery actualización a 1,11 desde 1,09 consigo este error: Syntax error, unrecognized expression: .nav-tabs a[href=#tab-2]. Resuelto usando stackoverflow.com/questions/12131273/…
Pietro Z.
213

ACTUALIZAR

Para Bootstrap 3, cambie .on('shown', ...)a.on('shown.bs.tab', ....)


Esto se basa en la respuesta @dubbe y esta respuesta SO aceptada . Maneja el problema con window.scrollTo(0,0)no funcionar correctamente. El problema es que cuando reemplaza el hash de url en la pestaña que se muestra, el navegador se desplazará a ese hash ya que es un elemento en la página. Para evitar esto, agregue un prefijo para que el hash no haga referencia a un elemento de página real

// Javascript to enable link to tab
var hash = document.location.hash;
var prefix = "tab_";
if (hash) {
    $('.nav-tabs a[href="'+hash.replace(prefix,"")+'"]').tab('show');
} 

// Change hash for page-reload
$('.nav-tabs a').on('shown', function (e) {
    window.location.hash = e.target.hash.replace("#", "#" + prefix);
});

Ejemplo de uso

Si tiene un panel de pestañas con id = "mytab", debe colocar su enlace de esta manera:

<a href="yoursite.com/#tab_mytab">Go to Specific Tab </a>
pez volador
fuente
1
¿Habría una manera simple de hacer referencia a marcadores que se encuentran en una pestaña específica? Tengo cinco pestañas en mi página y debajo de ellas tengo varios marcadores. Lo que me gustaría es hacer que estos marcadores se puedan vincular desde fuera de la pestaña.
nize
@nize si creas un jsfiddle con lo que intentas hacer, intentaré echar un vistazo.
flynfish
1
Aquí hay una demostración de Bootlpy para Bootstrap 3: bootply.com/render/VQqzOawoYc#tab2 y el código fuente
Zim
En el ejemplo anterior faltan las comillas dobles en href. la línea 5 debería ser:$('.nav-tabs a[href="'+hash.replace(prefix,"")+'"]').tab('show');
Ponyboy
Funciona para mí, excepto que tuve que eliminar la última barra diagonal (antes del #) en 'yoursite.com/anotherpage/#tab_mytab'; de lo contrario, causó estragos con la carga de la página.
Alexander
52

puede activar un clickevento en el enlace de la pestaña correspondiente:

$(document).ready(function(){

  if(window.location.hash != "") {
      $('a[href="' + window.location.hash + '"]').click()
  }

});
Marian Theisen
fuente
¡Gracias por el consejo! Esto funcionó muy bien con un pequeño problema. Actualizar la página no lo llevaría a la pestaña correcta. Al presionar Ctrl + F5 lo haría. Modifiqué el código a lo siguiente: `$ (document) .ready (function () {function getUrlVars () {var vars = {}; var parts = window.location.href.replace (/ [? &] + ([ ^ = &] +) = ([^ &] *) / gi, función (m, clave, valor) {vars [clave] = valor;}); return vars;} var action = getUrlVars () ["action" ]; if (action! = "") {$ ('a [href = "#' + action + '"]'). click ()};}); `
mraliks
44

Esta es una implementación mejorada de la solución de Dubbe que evita el desplazamiento.

// Javascript to enable link to tab
var url = document.location.toString();
if (url.match('#')) {
    $('.nav-tabs a[href="#'+url.split('#')[1]+'"]').tab('show') ;
} 

// With HTML5 history API, we can easily prevent scrolling!
$('.nav-tabs a').on('shown.bs.tab', function (e) {
    if(history.pushState) {
        history.pushState(null, null, e.target.hash); 
    } else {
        window.location.hash = e.target.hash; //Polyfill for old browsers
    }
})
Demircan Celebi
fuente
21

Si bien la solución JavaScript proporcionada puede funcionar, tomé una forma ligeramente diferente que no requiere JavaScript adicional, pero sí requiere lógica en su opinión. Crea un enlace con un parámetro de URL estándar, como:

<a href = "http://link.to.yourpage?activeTab=home">My Link</a>

Luego simplemente detecta el valor de activeTab para escribir 'class = "active"' en el apropiado <li>

Pseudocódigo (implementar en consecuencia en su idioma). Tenga en cuenta que he configurado la pestaña 'inicio' como activa predeterminada si no se proporciona ningún parámetro en este ejemplo.

$activetabhome = (params.activeTab is null or params.activeTab == 'home') ? 'class="active"' : '';
$activetabprofile = (params.activeTab == 'profile') ? 'class="active"' : '';

<li $activetabhome><a href="#home">Home</a></li>
<li $activetabprofile><a href="#profile">Profile</a></li>
Peter
fuente
Prefiero su solución a la solución JS debido a una simple razón es que JS location.hash saltaría a la ID que hace que la posición del cursor suba y baje.
Trung Lê
Prefiero esta solución De hecho, creé nuevas rutas para pestañas y volví a generar la vista configurando la clase activa en consecuencia. Esto evita el dolor de cabeza del cambio de tamaño de la página, el hash de url y el desplazamiento de la página todos juntos.
Vijay Meena
10

No soy un gran admirador de si ... más; Así que tomé un enfoque más simple.

$(document).ready(function(event) {
    $('ul.nav.nav-tabs a:first').tab('show'); // Select first tab
    $('ul.nav.nav-tabs a[href="'+ window.location.hash+ '"]').tab('show'); // Select tab by name if provided in location hash
    $('ul.nav.nav-tabs a[data-toggle="tab"]').on('shown', function (event) {    // Update the location hash to current tab
        window.location.hash= event.target.hash;
    })
});
  1. Elija una pestaña predeterminada (generalmente la primera)
  2. Cambie a tab (si tal elemento está realmente presente; deje que jQuery lo maneje); No pasa nada si se especifica un hash incorrecto
  3. [Opcional] Actualice el hash si se elige otra pestaña manualmente

No aborda el desplazamiento al hash solicitado; pero debe ello?

visitasb
fuente
8

Esto funciona en Bootstrap 3 y mejora las 2 respuestas principales de dubbe y flynfish al integrar también la respuesta de GarciaWebDev (que permite parámetros de URL después del hash y es directamente de los autores de Bootstrap en el rastreador de problemas de github):

// Javascript to enable link to tab
var hash = document.location.hash;
var prefix = "tab_";

if (hash) {
    hash = hash.replace(prefix,'');
    var hashPieces = hash.split('?');
    activeTab = $('.nav-tabs a[href=' + hashPieces[0] + ']');
    activeTab && activeTab.tab('show');
} 

// Change hash for page-reload
$('.nav-tabs a').on('shown', function (e) {
    window.location.hash = e.target.hash.replace("#", "#" + prefix);
});
greggdavis
fuente
1
esto no funciona en Bootstrap 3, 'shown'debería ser de 'shown.bs.tab'acuerdo con los documentos: getbootstrap.com/javascript/#tabs-events . Estoy desconcertado sobre por qué, pero cuando intenté editar tu publicación, fue rechazada ...
YPCrumble
6

Este código selecciona la pestaña derecha según el #hash y agrega el #hash correcto cuando se hace clic en una pestaña. (esto usa jquery)

En Coffeescript:

$(document).ready ->
    if location.hash != ''
        $('a[href="'+location.hash+'"]').tab('show')

    $('a[data-toggle="tab"]').on 'shown', (e) ->
        location.hash = $(e.target).attr('href').substr(1)

o en JS:

$(document).ready(function() {
    if (location.hash !== '') $('a[href="' + location.hash + '"]').tab('show');
    return $('a[data-toggle="tab"]').on('shown', function(e) {
      return location.hash = $(e.target).attr('href').substr(1);
    });
});
Sucrenoir
fuente
asegúrese de poner esto después de que jquery se haya cargado. Lo estaba colocando en el medio de una página (era un lugar fácil para insertarlo para probar) y no funcionó. Ponerlo después de cargar jquery funciona muy bien.
Ron
6

Aprovechando la solución de Demircan Celebi; Quería que la pestaña se abriera al modificar la url y la pestaña abierta sin tener que volver a cargar la página desde el servidor.

<script type="text/javascript">
    $(function() {
        openTabHash(); // for the initial page load
        window.addEventListener("hashchange", openTabHash, false); // for later changes to url
    });


    function openTabHash()
    {
        console.log('openTabHash');
        // Javascript to enable link to tab
        var url = document.location.toString();
        if (url.match('#')) {
            $('.nav-tabs a[href="#'+url.split('#')[1]+'"]').tab('show') ;
        } 

        // With HTML5 history API, we can easily prevent scrolling!
        $('.nav-tabs a').on('shown.bs.tab', function (e) {
            if(history.pushState) {
                history.pushState(null, null, e.target.hash); 
            } else {
                window.location.hash = e.target.hash; //Polyfill for old browsers
            }
        })
    }
</script>
Gavin
fuente
5

@flynfish + @Ztyx solución que uso para pestañas anidadas:

    handleTabLinks();

    function handleTabLinks() {
        if(window.location.hash == '') {
            window.location.hash = window.location.hash + '#_';
        }
        var hash = window.location.hash.split('#')[1];
        var prefix = '_';
        var hpieces = hash.split('/');
        for (var i=0;i<hpieces.length;i++) {
            var domelid = hpieces[i].replace(prefix,'');
            var domitem = $('a[href=#' + domelid + '][data-toggle=tab]');
            if (domitem.length > 0) {
                domitem.tab('show');
            }
        }
        $('a[data-toggle=tab]').on('shown', function (e) {
            if ($(this).hasClass('nested')) {
                var nested = window.location.hash.split('/');
                window.location.hash = nested[0] + '/' + e.target.hash.split('#')[1];
            } else {
                window.location.hash = e.target.hash.replace('#', '#' + prefix);
            }
        });
    }

los niños deben tener class = "anidado"

Artem Kashin
fuente
5

Se me ocurrió una solución que usa el URL hash o localStorage dependiendo de la disponibilidad de este último con el siguiente código:

$(function(){
    $(document).on('shown.bs.tab', 'a[data-toggle="tab"]', function (e) {
        localStorage.setItem('activeTab', $(e.target).attr('href'));
    })

    var hash = window.location.hash;
    var activeTab = localStorage.getItem('activeTab');

    if(hash){
          $('#project-tabs  a[href="' + hash + '"]').tab('show');   
    }else if (activeTab){
        $('#project-tabs a[href="' + activeTab + '"]').tab('show');
    }
});
Vaibhav
fuente
4

Te sugiero que uses el código proporcionado por los autores de Bootstrap en su rastreador de problemas en GitHub :

var hash = location.hash
  , hashPieces = hash.split('?')
  , activeTab = $('[href=' + hashPieces[0] + ']');
activeTab && activeTab.tab('show');

Puede encontrar en el enlace del problema más información sobre por qué no decidieron apoyar eso.

Alejandro García Iglesias
fuente
4

Intenté un par de formas discutidas anteriormente y terminé con la siguiente solución de trabajo, solo copie y pegue en su editor para probar. Para probar simplemente cambie el hash a la bandeja de entrada, a la bandeja de salida, a componer en la url y presione la tecla Intro.

<html>
    <head>
        <link type='text/css' rel='stylesheet' href='https://maxcdn.bootstrapcdn.com/bootstrap/3.0.0/css/bootstrap.min.css' />
        <script src="https://code.jquery.com/jquery-2.2.0.min.js"></script>
        <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.0.0/js/bootstrap.min.js"></script>
    </head>
    <body>
        <div class="container body-content">
            <ul class="nav nav-tabs">
                <li class="active"><a data-toggle="tab" href="#inbox">Inbox</a></li>
                <li><a data-toggle="tab" href="#outbox">Outbox</a></li>
                <li><a data-toggle="tab" href="#compose">Compose</a></li>
            </ul>
            <div class="tab-content">
                <div id="inbox" class="tab-pane fade in active">
                    Inbox Content
                </div>
                <div id="outbox" class="tab-pane fade">
                    Outbox Content
                </div>
                <div id="compose" class="tab-pane fade">
                    Compose Content
                </div>
            </div>
        </div>
        <script>
            $(function () {
                var hash = window.location.hash;
                hash && $('ul.nav a[href="' + hash + '"]').tab('show');
            });
        </script>
    </body>
</html>

Espero que esto te ahorre tiempo.

Abhimanyu
fuente
3

Esto es lo que hice, realmente simple, y siempre que sus enlaces de pestañas tengan una ID asociada, puede obtener el atributo href y pasarlo a la función que muestra el contenido de la pestaña:

<script type="text/javascript">
        jQuery(document).ready(function() {
            var hash = document.location.hash;
            var prefix = "tab_";
            if (hash) {
                var tab = jQuery(hash.replace(prefix,"")).attr('href');
                jQuery('.nav-tabs a[href='+tab+']').tab('show');
            }
        });
        </script>

Luego, en su URL, puede agregar el hash como algo así como: # tab_tab1, la parte 'tab_' se elimina del hash en sí para que la ID del enlace de la pestaña real en las pestañas de navegación (tabid1) se coloque después de esto, por lo que su url se vería algo así como: www.midominio.com/index.php#tab_tabid1.

Esto funciona perfecto para mí y espero que ayude a alguien más :-)

Derek Buntin
fuente
2

Esta es mi solución para manejar pestañas anidadas. Acabo de agregar una función para verificar si la pestaña activa tiene una pestaña principal para ser activada. Esta es la función:

function activateParentTab(tab) {
    $('.tab-pane').each(function() {
        var cur_tab = $(this);
        if ( $(this).find('#' + tab).length > 0 ) {
            $('.nav-tabs a[href=#'+ cur_tab.attr('id') +']').tab('show');
            return false;
        }
    });
}

Y se puede llamar así (según la solución de @ flynfish):

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

// Change hash for page-reload
$('.nav-tabs a').on('shown', function (e) {
    window.location.hash = e.target.hash.replace("#", "#" + prefix);
});

Esta solución me funciona bastante bien en este momento. Espero que esto pueda ser útil para otra persona;)

Stefano Marra
fuente
2

Tuve que modificar algunos bits para que esto funcione para mí. Estoy usando Bootstrap 3 y jQuery 2

// Javascript to enable link to tab
var hash = document.location.hash;
var prefix = "!";
if (hash) {
    hash = hash.replace(prefix,'');
    var hashPieces = hash.split('?');
    activeTab = $('[role="tablist"] a[href=' + hashPieces[0] + ']');
    activeTab && activeTab.tab('show');
}

// Change hash for page-reload
$('[role="tablist"] a').on('shown.bs.tab', function (e) {
    window.location.hash = e.target.hash.replace("#", "#" + prefix);
});
ruifn
fuente
Gran respuesta, excepto que tuve que reemplazar el "!" prefijo con "tab_". De lo contrario funcionó perfectamente.
koziez
2

Simplemente inserte este código en su 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();
    window.location.hash = this.hash;
    $('html,body').scrollTop(scrollmem);
  });
});

Amin Gholibeigian
fuente
1

Acabo de tener este problema, pero necesitaba manejar múltiples niveles de pestañas. El código es bastante feo (ver comentarios), pero hace su trabajo: https://gist.github.com/JensRantil/4721860 Esperemos que alguien más lo encuentre útil (¡y siéntase libre de proponer mejores soluciones!).

Ztyx
fuente
1

Combinando partes de otras respuestas, aquí hay una solución que puede abrir muchos niveles de pestañas anidadas:

// opens all tabs down to the specified tab
var hash = location.hash.split('?')[0];
if(hash) {
  var $link = $('[href=' + hash + ']');
  var parents = $link.parents('.tab-pane').get();
  $(parents.reverse()).each(function() {
    $('[href=#' + this.id + ']').tab('show') ;
  });
  $link.tab('show');
}
cweston
fuente
solo funciona en 2 niveles de anidamiento, el 3er nivel causa problemas.
Nicholas Hamilton
Acabo de probar esto en tres niveles de pestañas, y parece estar funcionando para mí. ¿Estás seguro de que esto no es un problema con tu implementación? ¿Qué "problema" estás experimentando?
cweston
Cualquier pestaña en el primer nivel y el segundo nivel funciona bien, sin embargo, en el tercer nivel, al actualizar la página (o al enviar el formulario), cuando la página se vuelve a abrir, se enfoca en la primera pestaña en el segundo nivel.
Nicholas Hamilton
Así que funcionó bien (había un error tipográfico menor en mi código), sin embargo, después de la corrección de errores tipográficos, solo con $('.nav-tabs li a').click( function(e) { history.pushState( null, null, $(this).attr('href') );});el JavaScript encima de su código.
Nicholas Hamilton
1

Si le importa a alguien, el siguiente código es pequeño y funciona perfectamente, para obtener un único valor hash de la URL y mostrar que:

<script>
    window.onload = function () {
        let url = document.location.toString();
        let splitHash = url.split("#");
        document.getElementById(splitHash[1]).click();
    };
</script>

lo que hace es recuperar la identificación y dispara el evento click. Simple.

Sam
fuente
0

Hago algo así para enlaces con ajax #!#(por ejemplo, / test.com #! # Test3) pero puedes modificarlo como quieras

$(document).ready(function() {

       let hash = document.location.hash;
       let prefix = "!#";

       //change hash url on page reload
       if (hash) {
         $('.nav-tabs a[href=\"'+hash.replace(prefix,"")+'\"]').tab('show');
       } 

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

Ejemplo con una página simple en Github aquí

eudaimonia
fuente
0

Sé que este hilo es muy antiguo, pero dejaré aquí mi propia implementación:

$(function () {
  // some initialization code

  addTabBehavior()
})

// Initialize events and change tab on first page load.
function addTabBehavior() {
  $('.nav-tabs a').on('show.bs.tab', e => {
    window.location.hash = e.target.hash.replace('nav-', '')
  })

  $(window).on('popstate', e => {
    changeTab()
  })

  changeTab()
}

// Change the current tab and URL hash; if don't have any hash
// in URL, so activate the first tab and update the URL hash.
function changeTab() {
  const hash = getUrlHash()

  if (hash) {
    $(`.nav-tabs a[href="#nav-${hash}"]`).tab('show')
  } else {
    $('.nav-tabs a').first().tab('show')
  }
}

// Get the hash from URL. Ex: www.example.com/#tab1
function getUrlHash() {
  return window.location.hash.slice(1)
}

Tenga en cuenta que estoy usando un nav-prefijo de clase para navegar por los enlaces.

Renan Coelho
fuente