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


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


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

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>

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

});

¡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
    }
})

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>

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?



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

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

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>


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"


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

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.


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.


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


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


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

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


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!).


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

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.


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í


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.

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.