¿Cómo hacer que la navegación de Twitter-Bootstrap muestre un enlace activo?

106

No entiendo cómo Twitter Bootstrap hace enlaces activos para la navegación. Si tengo una navegación regular como esta (con ruby ​​on rails enlazando):

<ul class="nav">
  <li class="active"> <a href="/link">Link</a> </li>
  <li class=""> <a href="/link">Link</a> </li>
  <li class=""> <a href="/link">Link</a> </li>        
</ul>

¿Cómo lo mantengo activo en función del enlace en el que se hace clic?

AprendizajeRoR
fuente
1
FYI: uso el active_link_to gem y especifico {: wrap_class =>: li}. Esto creará: <li class = 'active'> ... </li> cuando REQUEST_URI coincida con el valor HREF ...
Justin E

Respuestas:

95

Acabo de responder a la misma pregunta aquí Twitter Bootstrap Pills with Rails 3.2.2

<ul class="nav">
  <li class="<%= 'active' if params[:controller] == 'controller1' %>"> <a href="/link">Link</a> </li>
  <li class="<%= 'active' if params[:controller] == 'controller2' %>"> <a href="/link">Link</a> </li>
  <li class="<%= 'active' if params[:controller] == 'controller3' %>"> <a href="/link">Link</a> </li>        
</ul>
Pierre
fuente
21
Creo que la idea es correcta aquí, pero ir directamente al hash de params parece una mala idea. Asimismo, para repetir el mismo código una y otra vez. Recomendaría al menos usar current_page? para verificar el controlador / acción actual, y también movería el código a un ayudante para evitar la repetición del código.
Dustin Frazier
2
Me pregunto cómo escribo lo mismo en haml. Convertir a haml no me funciona. O tal vez me equivoque en alguna parte
calentador de banco
14
Implementación de HAML%li{:class => "#{'active' if current_page?(root_path)}"}=link_to "Home", root_path
Brian
¿Existe una forma elegante de hacer que esto funcione con friendly_id gem sin hacer solicitudes de base de datos?
Engin Erdogan
6
Rails docs recomienda el uso de controller_namey action_namehelpers en lugar de acceder a ellos desde el hash de params.
Alexander Suraphel
171

Puede usar algo como (muy similar a lo que mencionó @phil, pero un poco más corto):

<ul class="nav">
  <li class="<%= 'active' if current_page?(root_path) %>"><%= link_to "Home", root_path %></li>
  <li class="<%= 'active' if current_page?(about_path) %>"><%= link_to "About", about_path %></li>
  <li class="<%= 'active' if current_page?(contact_path) %>"><%= link_to "Contact", contact_path %></li>
</ul>
yorch
fuente
10
no funciona si tienes subnavegación. La ruta cambia pero estás en el mismo tramo ... ¿tiene sentido?
Jakob Dam Jensen
3
sí, correcto, si desea resaltar un elemento del menú sin importar el método que esté ejecutando dentro del mismo controlador, puede usar la solución @Pierre:'active' if params[:controller] == 'controller1'
yorch
¡Sí, esa es la forma más elegante de hacerlo! Gracias :)
squiter
2
¿Cómo puedo agregar más rutas o una ruta específica como user_*_pathen <%= 'active' if current_page?(root_path) %>?
Ismoh
1
¿Cómo agregaría más de una ruta para activar el elemento del menú? Por ejemplo, si tiene varios elementos en un menú desplegable que son componentes del mismo elemento del menú y desea activar el elemento del menú cuando se encuentra en cualquiera de las páginas que se encuentran en el menú desplegable. Háganos saber lo antes posible.
msc
47

https://github.com/twg/active_link_to

<%= active_link_to 'Users', users_path, :wrap_tag => :li %>

#=> <li class="active"><a href="https://stackoverflow.com/users">Users</a></li>

Hesham
fuente
7
Quiéralo. ¿Por qué reescribir la rueda?
Lightyrs
Este debería ser realmente el camino a seguir ... A menos que no desee incorporar otra dependencia.
Mark G.
33

Usé un ayudante para implementar esto al estilo de los ayudantes de formulario de Rails.

En un ayudante (p app/helpers/ApplicationHelper.rb. Ej. ):

def nav_bar
  content_tag(:ul, class: "nav navbar-nav") do
    yield
  end
end

def nav_link(text, path)
  options = current_page?(path) ? { class: "active" } : {}
  content_tag(:li, options) do
    link_to text, path
  end
end

Luego, en una vista (por ejemplo app/views/layouts/application.html.erb):

<%= nav_bar do %>
  <%= nav_link 'Home', root_path %>
  <%= nav_link 'Posts', posts_path %>
  <%= nav_link 'Users', users_path %>
<% end %>

Este ejemplo produce (cuando está en la página de 'usuarios'):

<ul class="nav navbar-nav">
  <li><a href="/">Home</a></li>
  <li><a href="/posts">Posts</a></li>
  <li class="active"><a href="/users">Users</a></li>
</ul>
Daniel
fuente
¡Esto es genial! ¡Gracias!
Krzysztof Witczak
Me gusta esta idea, sin embargo, agregaría un tercer argumento a la función nav_link llamado html = {} que luego se pasa a link_to. De esa manera, puede pasar un hash html a nav_link de la misma manera que usaría link_to normalmente.
Ryan Friedman
22

Use esto en su lugar para seleccionar el enlace activo en la navegación según la ruta actual sin el código del servidor:

    $(document).ready(function () {
        $('a[href="' + this.location.pathname + '"]').parent().addClass('active');
    });
Christian Landgren
fuente
2
Esta es la mejor solución porque también funciona con menús desplegables, e incluyo la línea $('li.active').closest('.dropdown').addClass('active');para resaltar el menú principal también.
Seralto
¿Cómo cambiarlo para solicitar subpáginas también? como example.com/home funcionará. Necesito que el enlace "Inicio" esté activo en el caso de example.com/home/page también.
athultuttu
11

He tenido éxito usando la lógica y ( &&) en haml :

%ul.nav
  %li{class: current_page?(events_path) && 'active'}
    = link_to "Events", events_path
  %li{class: current_page?(about_path) && 'active'}
    = link_to "About Us", about_path
Meltemi
fuente
5

Para cada enlace:

<% if current_page?(home_path) -%><li class="active"><% else -%><li><% end -%>
  <%= link_to 'Home', home_path %>
</li>

o incluso

<li <% if current_page?(home_path) -%>class="active"<% end -%>>
  <%= link_to 'Home', home_path %>
</li>
phil pirozhkov
fuente
3

No estoy seguro de si está preguntando cómo se usa el CSS de arranque de Twitter o el lado de los rieles. Asumo el lado de los rieles.

si es así, consulte el #link_to_ifmétodo o el #link_to_unless_currentmétodo

cpjolicoeur
fuente
3

Hoy tuve la misma pregunta / problema pero con otro enfoque para la solución. Creo una función auxiliar en application_helper.rb:

def navMainAktiv(actionName)
    if params[:action] == actionName    
    "active"
    end
end

y el enlace se ve así:

<li class="<%= navMainAktiv('about')%>"><%= link_to "About", about_path %></li>

Se puede reemplazar params[:action]con params[:controller]y configurar el nombre del controlador en el enlace.

la fuerza
fuente
2

Yo uso esto para cada uno li:

<li><%= link_to_unless_current('Home', root_path) { link_to('Home', root_path, class: 'active') } %></li>

andreofthecape
fuente
La clase debe estar programada para linoa
Christopher Oezbek
2

Puede definir un método auxiliar en application_helper.rb

def create_link(text, path)
  class_name = current_page?(path) ? 'active' : ''

  content_tag(:li, class: class_name) do
    link_to text, path
  end
end

Ahora puedes usar like:

create_link 'xyz', any_path que se traduciría como

<li class="active">
  <a href="/any">xyz</a>
</li>

¡Espero eso ayude!

Dusht
fuente
1

Debería hacerlo usted mismo manipulando las clases CSS. Es decir, si un usuario hace clic en algún enlace, entonces haga algo (acción de destino), establezca el enlace anterior inactivo y el nuevo enlace activo.

Si sus enlaces lo llevan al servidor (es decir, hace que la página se recargue), entonces puede representar el enlace activo correctamente en el servidor. De lo contrario, si está haciendo algunas cosas del lado del cliente (cambiar paneles de pestañas o lo que sea), debe usar javascript.

Sergio Tulentsev
fuente
1

podría usar tabulous para los enlaces

artículo aquí sobre cómo combinar tabulous con twitter bootstrap y rails 3.x

Stephenmurdoch
fuente
1

Escribí un método de ayuda simple usando build in view helper current_page?cuando puede especificar un classnombre personalizado en html_optionshash.

def active_link_to(name = nil, options = nil, html_options = nil, &block)
  active_class = html_options[:active] || "active"
  html_options.delete(:active)
  html_options[:class] = "#{html_options[:class]} #{active_class}" if current_page?(options)
  link_to(name, options, html_options, &block)
end

Ejemplos (cuando está en root_pathruta):

<%= active_link_to "Main", root_path %>
# <a href="/" class="active">Main</a>

<%= active_link_to "Main", root_path, class: "bordered" %>
# <a href="/" class="bordered active">Main</a>

<%= active_link_to "Main", root_path, class: "bordered", active: "disabled" %>
# <a href="/" class="bordered disabled">Main</a>
Cintrzyk
fuente
1

Muchas de las respuestas aquí tienen cosas que funcionarán o respuestas parciales. Combiné un montón de cosas para hacer este método auxiliar de rieles que uso:

# helper to make bootstrap3 nav-pill <li>'s with links in them, that have
# proper 'active' class if active. 
#
# the current pill will have 'active' tag on the <li>
#
# html_options param will apply to <li>, not <a>. 
#
# can pass block which will be given to `link_to` as normal. 
def bootstrap_pill_link_to(label, link_params, html_options = {})
  current = current_page?(link_params)

  if current
    html_options[:class] ||= ""
    html_options[:class] << " active "
  end

  content_tag(:li, html_options) do
    link_to(label, link_params)
  end      
end

Se podría hacer aún más elegante con la verificación de argumentos para admitir &blockel enlace_a, etc.

jrochkind
fuente
1

Ya hay muchas respuestas, pero esto es lo que escribí para que Bootstrap Icons funcione con un enlace activo. Espero que ayude a alguien

Este ayudante te dará:

  1. elemento li con enlace que contiene texto personalizado
  2. Icono Bootstrap3 opcional
  3. se activará cuando estés en la página correcta

Pon esto en tu application_helper.rb

def nav_link(link_text, link_path, icon='')
  class_name = current_page?(link_path) ? 'active' : ''
  icon_class = "glyphicon glyphicon-" + icon

  content_tag(:li, :class => class_name) do
    (class_name == '') ? (link_to content_tag(:span, " "+link_text, class: icon_class), link_path)
    : (link_to content_tag(:span, " "+link_text, class: icon_class), '#')
  end
end

Y usa el enlace:

<%= nav_link 'Home', root_path, 'home'  %>

El último argumento es opcional: agregará un icono al enlace. Utilice nombres de iconos de glifos. Si desea un icono sin texto:

    <%= nav_link '', root_path, 'home'  %>
Lukasz Muzyka
fuente
1

Esto es lo que hice:

Creé un ViewsHelper y lo incluí en ApplicationController:

include ViewsHelper

Dentro de ViewsHelper creé un método simple como este:

def page_state(path)
  current_page?(path) ? 'active' : ''
end

En mi opinión, hago esto:

<li class="<%= page_state(foobar_path) %>"><%= link_to 'Foobars', foobar_path %></li>
Nick Res
fuente
0

Parece que necesita implementar un sistema de navegación. Si es complejo, puede volverse bastante feo y bastante rápido.

En este caso, es posible que desee utilizar un complemento que pueda manejar eso. Puede usar navigasmic o navegación simple (recomendaría navigasmic porque mantiene la capa principal en una vista, donde pertenece, y no en alguna configuración)

Andrei S
fuente
0

Código más corto 

Se trata de los elementos de la lista de navegación secundaria y de navegación secundaria. Puede pasar una matriz a una sola ruta y se ocupará de ambos.

application_helper

# Active page method
def ap(p:);'active' if p.class == Array ? p.map{|m| current_page? m}.any? : (current_page? p) end

ver (html.erb)

<ul class="nav navbar-nav">
  <li class="<%= ap p: home_path %>">Home</li>
  <li class="<%= ap p: account_path %>">Account</li>

  <li class="dropdown <%= ap p: [users_path, new_user_path] %>">
    <a href="#" class="dropdown-toggle" data-toggle="dropdown">Users</a>
    <ul class="dropdown-menu" role="menu">
      <li class="<%= ap p: users_path %>">Users</li>
      <li class="<%= ap p: new_user_path %>">Add user</li>
    </ul>
  </li>
</ul>
cb24
fuente
0

Usando ruby ​​en Sinatra ..

Estoy usando el tema Bootstrap bare, aquí está el código de barra de navegación de muestra. Tenga en cuenta el nombre de clase del elemento -> .nav - ya que se hace referencia a esto en el script java.

/ Collect the nav links, forms, and other content for toggling
    #bs-example-navbar-collapse-1.collapse.navbar-collapse
      %ul.nav.navbar-nav
        %li
          %a{:href => "/demo/one"} Page One
        %li
          %a{:href => "/demo/two"} Page Two
        %li
          %a{:href => "/demo/three"} Page Three

en la página de vista (o parcial) agregue esto: javascript, esto debe ejecutarse cada vez que se carga la página.

fragmento de vista haml ->

- content_for :javascript do
  :javascript
      $(function () {
          $.each($('.nav').find('li'), function() {
              $(this).toggleClass('active',
                  $(this).find('a').attr('href') == window.location.pathname);
          });
      });

En el depurador de JavaScript, asegúrese de que el valor del atributo 'href' coincida con window.location.pathname. Esto es ligeramente diferente a la solución de @Zitrax que me ayudó a solucionar mi problema.

Rishi
fuente
0

Básico, sin ayuda

<%= content_tag(:li, class: ('active' if request.path == '/contact')) do %>
    <%= link_to 'Contact', '/contact' %>
<% end %>

Yo uso esto porque tengo más de una clase -

<%= content_tag(:li, class: (request.path == '/contact' ? 'active black' : 'black')) do %>
    <%= link_to 'Contact', '/contact' %>
<% end %>
scottkekoa
fuente
1
Esto también funcionará para cualquier navegación secundaria ... simplemente use la ruta de solicitud principal en el enlace secundario.
scottkekoa
0
  def active_navigation?(controllers_name, actions_name)
   'active' if controllers_name.include?(controller_name) && actions_name.include?(action_name)
  end

Delgado

li class=(active_navigation?(['events'], ['index', 'show'])) = link_to t('navbar.events'), events_path
Nazar Hlynskyi
fuente