Como obter a navegação do Twitter-Bootstrap para mostrar o link ativo?

106

Não estou entendendo como o Twitter Bootstrap ativa links para a navegação. Se eu tiver uma navegação regular como esta (com link Ruby on Rails):

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

Como faço para mantê-lo ativo com base no link clicado?

LearningRoR
fonte
1
Para sua informação: Eu uso a gem active_link_to e especifico {: wrap_class =>: li}. Isso criará: <li class = 'active'> ... </li> quando REQUEST_URI corresponder ao valor HREF ...
Justin E

Respostas:

95

Acabei de responder a mesma pergunta aqui 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
fonte
21
Acho que a ideia está correta aqui, mas ir diretamente para o hash params parece uma má ideia. Da mesma forma, para repetir o mesmo código indefinidamente. Eu recomendaria pelo menos usar o current_page? para verificar o controlador / ação atual, e também moveria o código para um auxiliar para evitar a repetição do código.
Dustin Frazier
2
Eu me pergunto como faço para escrever o mesmo no haml. Converter para haml não funciona para mim. Ou talvez eu esteja errado em algum lugar
benchwarmer
14
Implementação de HAML%li{:class => "#{'active' if current_page?(root_path)}"}=link_to "Home", root_path
Brian
Existe uma maneira elegante de fazer isso funcionar com a gem friendly_id sem fazer solicitações de banco de dados?
Engin Erdogan,
6
A documentação do Rails recomenda o uso de controller_namee action_namehelpers ao invés de acessá-los a partir do hash params.
Alexander Suraphel
171

Você pode usar algo como (muito semelhante ao que @phil mencionou, mas um pouco mais curto):

<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
fonte
10
não funciona se você tiver subnavegação. O caminho muda, mas você está na mesma seção .. faz sentido?
Jakob Dam Jensen
3
sim, correto, se você quiser destacar um item de menu, não importa qual método você está executando dentro do mesmo controlador, você pode usar a solução @Pierre:'active' if params[:controller] == 'controller1'
yorch
Sim, essa é a maneira mais elegante de fazer isso! Obrigado :)
squiter
2
Como posso adicionar mais caminhos ou um caminho específico como user_*_pathem <%= 'active' if current_page?(root_path) %>?
Ismoh
1
Como você adicionaria mais de um caminho para tornar o item de menu ativo? Por exemplo, se você tiver vários itens em uma lista suspensa que são componentes do mesmo item de menu e gostaria de tornar o item de menu ativo quando estiver em qualquer uma das páginas encontradas no menu suspenso? Informe-nos o mais rápido possível.
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
fonte
7
Adoro. Por que reescrever a roda?
lightyrs
Esse realmente deve ser o caminho a seguir ... A menos que você não queira puxar outra dependência.
Mark G.
33

Eu usei um helper para implementar isso no estilo dos helpers de formulário do Rails.

Em um ajudante (por exemplo app/helpers/ApplicationHelper.rb):

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

Então, em uma vista (por exemplo 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 exemplo produz (quando na página 'usuários'):

<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
fonte
Isso é ótimo! Obrigado!
Krzysztof Witczak
Gosto dessa ideia, mas adicionaria um terceiro argumento à função nav_link chamado html = {} que é então passado para link_to. Dessa forma, você pode passar um hash html para nav_link da mesma forma que usaria link_to normalmente.
Ryan Friedman
22

Em vez disso, use para selecionar o link ativo no nav com base na rota atual sem o código do servidor:

    $(document).ready(function () {
        $('a[href="' + this.location.pathname + '"]').parent().addClass('active');
    });
Christian Landgren
fonte
2
Esta é a melhor solução porque também funciona com menus suspensos e incluo a linha $('li.active').closest('.dropdown').addClass('active');para destacar o menu principal também.
Seralto
como alterá-lo para se inscrever em subpáginas também? como example.com/home funcionará. Preciso que o link "Home" esteja ativo no caso de example.com/home/page também.
athultuttu
11

Tive sucesso usando o lógico e ( &&) em 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
fonte
5

Para cada link:

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

ou mesmo

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

não tenho certeza se você está perguntando sobre como o css de bootstrap do twitter é usado, ou o lado rails. Estou assumindo o lado dos trilhos.

se sim, verifique o #link_to_ifmétodo ou o #link_to_unless_currentmétodo

cpjolicoeur
fonte
3

Hoje tive a mesma dúvida / problema mas com outra abordagem para a solução. Eu crio uma função auxiliar em application_helper.rb:

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

e o link se parece com este:

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

Você pode substituir params[:action]com params[:controller]e definir o nome do controlador no link.

a força
fonte
2

Eu uso isso para cada um li:

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

andreofthecape
fonte
A aula precisa ser definida para linãoa
Christopher Oezbek
2

Você pode definir um método auxiliar em 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

Agora você pode usar como:

create_link 'xyz', any_path que renderizaria como

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

Espero que ajude!

Dusht
fonte
1

Você deve fazer isso manipulando classes CSS. Ou seja, se um usuário clicar em algum link, então faça algo (ação de destino), defina o link anterior inativo e o novo link ativo.

Se seus links o levarem ao servidor (ou seja, fazer a página recarregar), você poderá apenas renderizar o link ativo corretamente no servidor. Caso contrário, se você estiver fazendo alguma coisa do lado do cliente (alternando painéis de guia ou qualquer outra coisa), você terá que usar javascript.

Sergio Tulentsev
fonte
1

você poderia usar tabulous para os links

artigo aqui sobre como combinar tabulous com twitter bootstrap e rails 3.x

Stephenmurdoch
fonte
1

Eu escrevi um método auxiliar simples usando build in view helper current_page?quando você pode especificar o classnome personalizado em 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

Exemplos (quando você está na root_pathrota):

<%= 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
fonte
1

Muitas das respostas aqui têm coisas que funcionam, ou respostas parciais. Combinei um monte de coisas para fazer este método auxiliar do Rails 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

Pode ser ainda mais elaborado com a verificação de argumentos para suporte &blockno link_to etc.

Jrochkind
fonte
1

Muitas respostas já, mas aqui está o que escrevi para fazer os ícones do Bootstrap funcionarem com o link ativo. Espero que ajude alguém

Este ajudante lhe dará:

  1. elemento li com link contendo texto personalizado
  2. Ícone Opcional Bootstrap3
  3. ficará ativo quando você estiver na página certa

Coloque isso em seu 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

E use o link:

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

O último argumento é opcional - ele adicionará um ícone ao link. Use nomes de ícones de glifo. Se você quiser um ícone sem texto:

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

Aqui está o que eu fiz:

Eu criei um ViewsHelper e incluí no ApplicationController:

include ViewsHelper

Dentro do ViewsHelper, criei um método simples como este:

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

Na minha opinião, eu faço o seguinte:

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

Parece que você precisa implementar um sistema de navegação. Se for complexo, pode ficar muito feio e muito rápido.

Nesse caso, você pode querer usar um plugin que possa lidar com isso. Você pode usar navigasmic ou navegação simples (eu recomendo navigasmic porque mantém a camada principal em uma visualização, onde ela pertence, e não em alguma configuração)

Andrei S
fonte
0

Código mais curto 

Isso lida com AMBOS os elementos da lista de nav e sub nav. Você pode passar uma matriz por um único caminho e lidará com 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

visualizar (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
fonte
0

Usando rubi no Sinatra ..

Estou usando o tema básico de bootstrap, aqui está o código de navbar de exemplo. Observe o nome da classe do elemento -> .nav - como é referido no java script.

/ 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

na página de visualização (ou parcial) adicione: javascript, isso precisa ser executado toda vez que a página carrega.

haml view snippet ->

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

No depurador javascript, certifique-se de que o valor do atributo 'href' corresponda a window.location.pathname. Isso é um pouco diferente da solução da @Zitrax, que me ajudou a corrigir meu problema.

Rishi
fonte
0

Básico, sem auxiliar

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

Eu uso isso porque tenho mais de uma aula -

<%= content_tag(:li, class: (request.path == '/contact' ? 'active black' : 'black')) do %>
    <%= link_to 'Contact', '/contact' %>
<% end %>
Scottkekoa
fonte
1
Isso também funcionará para qualquer subnavegação ... basta usar o caminho da solicitação pai no sublink.
scottkekoa
0
  def active_navigation?(controllers_name, actions_name)
   'active' if controllers_name.include?(controller_name) && actions_name.include?(action_name)
  end

fino

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