Rails 3'te nav'a "current" sınıfı eklemenin en iyi yolu


111

Gezinme menüsünde bazı statik sayfalarım var. Şu anda görüntülenen öğeye "geçerli" gibi bir sınıf eklemek istiyorum.

Bunu yapma şeklim, denetleyiciyi ve eylemi kontrol etmek için tonlarca yardımcı yöntem (her biri bir öğe için) eklemektir.

def current_root_class
  'class="current"' if controller_name == "homepage" && action_name == "index" 
end

<ul>
  <li <%= current_root_class %>><%= link_to "Home", root_path %>

Bunu yapmanın daha iyi bir yolu var mı? Şu anki yolum çok aptalca ......

Yanıtlar:


56

Burada gerçekten bir cevap değil, çünkü ben de seninle aynı şekilde kullanıyorum. Birden çok denetleyiciyi veya eylemi test etmek için yardımcı yöntemler tanımladım:

Application_helper.rb içinde

  def controller?(*controller)
    controller.include?(params[:controller])
  end

  def action?(*action)
    action.include?(params[:action])
  end

Ardından if controller?("homepage") && action?("index", "show")görünümlerinizde veya diğer yardımcı yöntemleri kullanabilirsiniz…


Farklı denetleyiciler / eylemler tarafından işlenen ancak aynı menü öğesinde bazı sayfalar olduğunda, yolunuz en uygunudur, değil mi? Daha fazla avantajla karşılaştın mı ~?
PeterWong

Sözdiziminin özlü olması dışında daha fazla avantaj yok. Başka birinin daha iyi bir çözümü olup olmadığını merak ediyorum.
Yannis

Bu yöntemi büyük bir başarıyla yaptım. Bu kodu görünüme eklendi: <% = link_to "Kullanıcılar", users_path, class: (controller? ("Users")? 'Selected': nil)%> Hem / users hem de / users / new için gerçekten düzgün çalışıyor .
Andreas

1
bir gelişme muhtemelen params yerine controller_nameve olabiliraction_name
Francesco Belladonna

Aferin. Bunu basit tutmayı düşünmedim ama bu çok güzel ölçekleniyor. +1
newdark-it

290

Bir yardımcı yaptım nav_link:

def nav_link(link_text, link_path)
  class_name = current_page?(link_path) ? 'current' : ''

  content_tag(:li, :class => class_name) do
    link_to link_text, link_path
  end
end

gibi kullanılır:

nav_link 'Home', root_path

gibi HTML üretecek

<li class="current"><a href="/">Home</a></li>


41
Sınıf_adı = geçerli_sayfa değiştirilsin mi? (Bağlantı_yolu)? 'current': sınıf etiketinin mevcut sayfada değilken gösterilmesini istemiyorsanız sıfır
Matthew Hui

1
Açılır listelerde kullanılan iç içe geçmiş listeler için bunu nasıl değiştirirsiniz?
doremi

9
DRY as a Desert
Orlando

1
Extra_classes = nil, id = nil ve ardından content_tag content_tag (: li, class: [class_name, extra_classes], id: id) içine birkaç ekstra argüman ekledim, böylece öğelere kendi sınıflarınızı ve id'lerinizi de ekleyebilirsiniz :)
Jon

72

Sınıfı current_page?atamanız gerekip gerekmediğini belirlemek için yardımcıyı kullanın "current". Örneğin:

<%= 'active' if current_page?(home_about_path) %>

: Ayrıca Bir yol (seçenekler karma sadece), örneğin geçebilir Not current_page?(root_path).


3
Bunu sorgu parametrelerini yok saymanın bir yolu var mı?
Mohamad

@Mohamad, bunu yapabilirsin: current_page? (Denetleyici: 'kullanıcılar', eylem: 'dizin')
nilid

26

İşi yapmak için application_helper.rb (Rails 3) içindeki bu nav_link (metin, bağlantı) işlevini kullanıyorum ve benim için önyükleme twitter 2.0 gezinme çubuğu bağlantılarını alıyor.

def nav_link(text, link)
    recognized = Rails.application.routes.recognize_path(link)
    if recognized[:controller] == params[:controller] && recognized[:action] == params[:action]
        content_tag(:li, :class => "active") do
            link_to( text, link)
        end
    else
        content_tag(:li) do
            link_to( text, link)
        end
    end
end

Misal:

<%=nav_link("About Us", about_path) %>

Bu current_page?, diğer cevaplarda olduğu gibi , yöntem kullanılarak basitleştirilebilir .
Teemu Leisti

10

Bunu yapma şeklim, application_helper'a bir yardımcı işlev eklemektir.

def current_class?(test_path)
  return 'current' if request.request_uri == test_path
  ''
end

Sonra nav'da,

<%= link_to 'Home', root_path, :class => current_class?(root_path) %>

Bu, bağlantı yolunu geçerli sayfa uri'sine göre test eder ve geçerli sınıfınızı veya boş bir dizeyi döndürür.

Bunu tam olarak test etmedim ve RoR konusunda çok yeniyim (on yıldan sonra PHP ile geçiş yapıyorum), bu yüzden eğer bu büyük bir kusur varsa duymak isterim.

En azından bu şekilde sadece 1 yardımcı fonksiyona ve her bağlantıda basit bir çağrıya ihtiyacınız var.


1
Sadece bir sorun. Request_uri yerine request.path kullandım (request_uri çalışmıyordu, belki raylar sürüm problemi?). Cevabınız bence temiz ve zarif.
Tony

6

@ Skilldrick'in cevabını geliştirmek için ...

Bu kodu application.js'ye eklerseniz, etkin çocuklara sahip tüm açılır menülerin de etkin olarak işaretlenmesini sağlar ...

$('.active').closest('li.dropdown').addClass('active');

Destekleyici kodu özetlemek için> nav_link adlı bir yardımcı ekleyin:

def nav_link_to(link_text, link_path)
  class_name = current_page?(link_path) ? 'active' : ''

  content_tag(:li, :class => class_name) do
    link_to link_text, link_path
  end
end

gibi kullanılır:

nav_link_to 'Home', root_path

gibi HTML üretecek

<li class="active"><a href="/">Home</a></li>

4

Bence en iyi yol

application_helper.rb:

def is_active(controller, action)       
  params[:action] == action && params[:controller] == controller ? "active" : nil        
end

Ve menüde:

<li class="<%= is_active('controller', 'action') %>">

Böyle boş bir sınıf "" bırakabilir miyim?
Harsha MV

Evet. Kaynağın bir grup boş sınıf özelliği gördüğünü görürseniz garip görünebilir, ancak bu geçerli HTML'dir.
kobaltz

Kullanabilirsiniz, <%= content_tag(:li, "Click me", class: is_active('controller', 'action')) %>sıfır için bir sınıf niteliği yazdırmaz. apidock.com/rails/ActionView/Helpers/TagHelper/content_tag
neonmate

4

Bunun tarihli bir cevap olduğunu biliyorum, ancak tüm bu geçerli sayfa kontrolünü, active_link_to gem adlı bir link_to yardımcı sarmalayıcı kullanarak kolayca göz ardı edebilirsiniz , tam olarak istediğiniz gibi çalışır, mevcut sayfa bağlantısına aktif bir sınıf ekler


4

Raylar görünümünde bootstrap menü sayfasına aktif bir sınıfın nasıl ekleneceğine dair tam bir örnek.

    <li class="<%= 'active' if current_page?(root_path) %>"><%= link_to 'Home', controller: "welcome" %></li>
    <li class="<%= 'active' if current_page?(about_path) %>"><%= link_to 'About us', about_path %></li>
   <li class="<%= 'active' if current_page?(contact_path) %>"><%= link_to 'Contact us', contact_path %></li>

3

Tabs on Rails adlı harika bir mücevher kullanıyorum .


1
Önerin için teşekkürler. Navigasyonum çok basit olduğundan ve küçük eşyalara sahip yalnızca bir tane olduğundan, mücevher muhtemelen aşırı güçlenecektir.
PeterWong

3

Tam olarak link_to gibi çalışan, ancak bir sarmalama li etiketi çıkarmak için özelleştirilmiş daha kısa bir nav_link sürümüne sahibim.

Aşağıdakileri application_helper.rb dosyanıza koyun

def nav_link(*args, &block)
    if block_given?
      options      = args.first || {}
      html_options = args.second
      nav_link(capture(&block), options, html_options)
    else
      name         = args[0]
      options      = args[1] || {}
      html_options = args[2]

      html_options = convert_options_to_data_attributes(options, html_options)
      url = url_for(options)

      class_name = current_page?(url) ? 'active' : nil

      href = html_options['href']
      tag_options = tag_options(html_options)

      href_attr = "href=\"#{ERB::Util.html_escape(url)}\"" unless href
      "<li class=\"#{class_name}\"><a #{href_attr}#{tag_options}>#{ERB::Util.html_escape(name || url)}</a></li>".html_safe
    end
  end

Yukarıdaki koda bakarsanız ve onu url_helper.rb'deki link_to koduyla karşılaştırırsanız, tek fark, url'nin geçerli sayfa olup olmadığını kontrol etmesi ve "aktif" sınıfını bir sarma li etiketine eklemesidir. Bunun nedeni, bağlantıların li etiketleri içine sarılmasını ve dış li'ye uygulanan "active" sınıfını tercih eden Twitter Bootstrap nav bileşeni ile nav_link yardımcısını kullanıyorum .

Yukarıdaki kodun güzel yanı, tıpkı link_to ile yapabileceğiniz gibi, fonksiyona bir blok girmenize izin vermesidir.

Örneğin, simgeler içeren bir önyükleme gezinme listesi şöyle görünür:

İnce:

ul.nav.nav-list
  =nav_link root_path do
    i.icon-home
    |  Home
  =nav_link "#" do
    i.icon-user
    |  Users

Çıktı:

<ul class="nav nav-list">
  <li class="active">
    <a href="/">
      <i class="icon-home"/>
      Home
    </a>
  </li>
  <li>
    <a href="#">
      <i class="icon-users"/>
      Users
    </a>
  </li>
</ul>

Ek olarak, tıpkı link_to yardımcısı gibi, HTML seçeneklerini nav_link'e aktarabilirsiniz, bu da bir etikete uygulanacaktır.

Çapa için bir başlık geçirme örneği:

İnce:

ul.nav.nav-list
  =nav_link root_path, title:"Home" do
    i.icon-home
    |  Home
  =nav_link "#", title:"Users" do
    i.icon-user
    |  Users

Çıktı:

<ul class="nav nav-list">
  <li class="active">
    <a href="/" title="Home">
      <i class="icon-home"/>
      Home
    </a>
  </li>
  <li>
    <a href="#" title="Users">
      <i class="icon-users"/>
      Users
    </a>
  </li>
</ul>

Muhteşem. Benim için bu en uygun seçenekti çünkü bloklara izin veriyor. Çok teşekkürler!
Kasperi

3

Şahsen benim için burada bir cevap kombinasyonu kullandım

<li class="<%= 'active' if current_page?(inventory_index_path) %>"><a href="#">Menu</a></li>

Materialize css kullanıyorum ve ana kategorileri daraltılabilir yapma yöntemim aşağıdaki kodu kullanmak.

$('.active').closest(".collapsible.collapsible-accordion")
            .find(".collapsible-header")
            .click();

umarım birine yardımcı olur


bunu unuttum. Bunu hatırlatma olarak gönderdiğiniz için teşekkürler.
newdark-it

2

current_page?Diğer cevaplar dayanarak bu hale getirdik böylece yöntem, benim için yeterince esnek (eğer o zaman sadece kontrolörün endeksi eylemi gerçek dönersiniz, bir kontrolör ancak bir eylem set demek) değil:

  def nav_link_to(link_text, link_path, checks=nil)
    active = false
    if not checks.nil?
      active = true
      checks.each do |check,v|
        if not v.include? params[check]
          active = false
          break
        end
      end
    end

    return content_tag :li, :class => (active ? 'active' : '') do
      link_to link_text, link_path
    end
  end

Misal:

nav_link_to "Pages", pages_url, :controller => 'pages'

Cevabınız için teşekkür ederim. Sanırım sizinki kabul edilen cevaba benziyor :)
PeterWong

Bu sorunu yaşadığımdan beri bu cevaba Google aracılığıyla rastladım, bu yüzden bununla karşılaşan herkese yardım
edebileceğimi düşündüm

2

Evet! Bu makaleye göz atın: Raylardaki Bağlantılara 'seçilmiş' bir Sınıf Eklemenin Daha İyi Bir Yolu

Nav_link_helper.rb'yi uygulama / yardımcılara bırakın ve şu kadar kolay olabilir:

<%= nav_link 'My_Page', 'http://example.com/page' %>

Nav_link yardımcısı, standart Rails link_to yardımcısı gibi çalışır, ancak belirli kriterler karşılanırsa bağlantınıza (veya onun sarmalayıcısına) bir 'seçili' sınıf ekler. Varsayılan olarak, bağlantının hedef url'si geçerli sayfanın url'si ile aynı url ise, bağlantıya varsayılan bir 'seçili' sınıfı eklenir.

Burada bir özet var: https://gist.github.com/3279194

GÜNCELLEME: Bu artık bir mücevher: http://rubygems.org/gems/nav_link_to


Bu güzel. Kullanmaya başladım ve seçilmemiş öğelere bir sınıf adı vermeyi desteklemek için, yine özünde bir yorum olarak bir değişiklik ekledim.
Teemu Leisti

2

Üst düzey bağlantılar için bunun gibi basit bir yardımcı kullanıyorum, böylece /stories/my-storysayfanın /storiesbağlantıyı vurgulaması

def nav_link text, url

  active = (url == request.fullpath || (url != '/' && request.fullpath[0..(url.size-1)] == url))

  "<li#{ active ? " class='selected'" : '' }><a href='#{url}'>#{text}</a></li>".html_safe

end

2

Çözümümü göstermeme izin verin:

_header.html.erb :

  <ul class="nav">
    <%= nav_tabs(@tabs) %> 
  </ul>

application_helper.rb :

 def nav_tabs(tabs=[])
    html = []
    tabs.each do |tab| 
      html << (content_tag :li, :class => ("current-page" if request.fullpath.split(/[\??]/)[0] == tab[:path]) do
        link_to tab[:path] do
          content_tag(:i, '', :class => tab[:icon]) +
          tag(:br) +
          "#{tab[:name]}"
        end
      end)        
    end

    html.join.html_safe
  end

application_controller.rb :

before_filter :set_navigation_tabs

private
def set_navigation_tabs
  @tabs = 
    if current_user && manager?
      [
        { :name => "Home", :icon => "icon-home", :path => home_index_path },
        { :name => "Portfolio", :icon => "icon-camera", :path => portfolio_home_index_path },
        { :name => "Contact", :icon => "icon-envelope-alt", :path => contact_home_index_path }
      ]
    elsif current_user && client?
      ...
    end

1

Göre Skilldrick tarafından cevap , ben aşağıdakilere bunu değiştireceğiz:

def nav_link(*args, &block)
  is_active = current_page?(args[0]) || current_page?(args[1])
  class_name = is_active ? 'active' : nil

  content_tag(:li, class: class_name) do
    link_to *args, &block
  end
end

çok daha kullanışlı hale getirmek için.


1

Bu sürüm @ Skilldrick'in sürümüne dayanmaktadır ancak html içeriği eklemenize izin verir.

Böylece şunları yapabilirsiniz:

nav_link "A Page", a_page_path

Ayrıca:

nav_link a_page_path do
  <strong>A Page</strong>
end

veya başka herhangi bir html içeriği (örneğin bir simge ekleyebilirsiniz).

İşte yardımcı:

  def nav_link(name = nil, options = nil, html_options = nil, &block)
    html_options, options, name = options, name, block if block_given?
    options ||= {}

    html_options = convert_options_to_data_attributes(options, html_options)

    url = url_for(options)
    html_options['href'] ||= url

    class_name = current_page?(url) ? 'current' : ''
    content_tag(:li, :class => class_name) do  
      content_tag(:a, name || url, html_options, &block)
    end
  end

1

Sanırım pek çok kullanım durumu için faydalı olabilecek basit bir çözüm buldum. Bu bana şunları sağlar:

  • Yalnızca düz metni değil, HTML'yi de destekleyin link_to(örneğin, bağlantının içine bir simge ekleyin)
  • Yalnızca birkaç satır kod ekleyin application_helper.rb
  • activeTek sınıf olmak yerine bağlantı öğesinin tüm sınıf adına ekleyin .

Bu yüzden şunu ekleyin application_helper.rb:

def active_class?(class_name = nil, path)
  class_name ||= ""
  class_name += " active" if current_page?(path)
  class_name.strip!
  return class_name
end

Ve şablonunuzda şuna benzer bir şeye sahip olabilirsiniz:

<div class="col-xs-3">
  <%= link_to root_path, :class => active_class?("btn btn-outline-primary", root_path) do %>
    <i class="fa fa-list-alt fa-fw"></i>
  <% end %>
</div>

Gibi ikramiye belirttikten veya bir edebilir class_nameve bu gibi kullanmak:<div class="<%= current_page?(root_path) %>">

Önceki cevaplar 1 , 2 ve kaynaklar için teşekkürler .


0

tüm bunlar basit gezinme çubuklarıyla çalışır, peki ya açılır alt menü? bir alt menü seçildiğinde, üst menü öğesi 'geçerli' hale getirilmelidir bu durumda tabs_on_rails bana çözüm olabilir


0

Mevcut projemde bu şekilde çözdüm.

def class_if_current_page(current_page = {}, *my_class)
    if current_page?(current_page)
      my_class.each do |klass|
        "#{klass} "
      end
    end
  end

Sonra..

li = link_to company_path 
    class: %w{ class_if_current_page( { status: "pending" }, "active" ), "company" } do  
      Current Company

0

Benim kolay yolum -

application.html.erb,

<div class="navbar">
    <div class="<%= @menu1_current %> first-item"><a href="/menu1"> MENU1 </a></div>
    <div class="<%= @menu2_current %>"><a href="/menu2"> MENU2 </a></div>
    <div class="<%= @menu3_current %>"><a href="/menu3"> MENU3 </a></div>
    <div class="<%= @menu4_current %> last-item"><a href="/menu4"> MENU4 </a></div>
</div>

main_controller.erb,

class MainController < ApplicationController
    def menu1
        @menu1_current = "current"
    end

    def menu2
        @menu2_current = "current"
    end

    def menu3
        @menu3_current = "current"
    end

    def menu4
        @menu4_current = "current"
    end
end

Teşekkürler.


0

Ayrıca görünümde html seçenekleri karmasını desteklemek istiyorsanız. Örneğin, başka bir CSS sınıfı veya kimliği ile çağırmak isterseniz, yardımcı işlevi bu şekilde tanımlayabilirsiniz.

def nav_link_to(text, url, options = {})
  options[:class] ||= ""
  options[:class] += " active"
  options[:class].strip!
  link_to text, url, options
end

Bu nedenle görünümde, bu yardımcıyı link_to helper olarak adlandırdığınız şekilde arayın

<%= nav_link_to "About", about_path, class: "my-css-class" %>

0

ApplicationHelperAşağıdaki gibi bir yöntem oluşturun .

def active controllers, action_names = nil
  class_name = controllers.split(",").any? { |c| controller.controller_name == c.strip } ? "active" : ""
  if class_name.present? && action_names.present?
    return action_names.split(",").any? { |an| controller.action_name == an.strip } ? "active" : ""
  end
  class_name
end

Şimdi, aşağıdaki kullanım durumları gibi görünümde kullanın.

1. Herhangi bir belirli kontrolörün tüm eylemleri için

<li class="<%= active('controller_name')%>">
....
</li>

2. Birçok denetleyicinin tüm eylemleri için (virgülle ayrılmış olarak)

<li class="<%= active('controller_name1,controller_name2')%>">
....
</li>

3. Herhangi bir belirli denetleyicinin belirli eylemi için

<li class="<%= active('controller_name', 'action_name')%>">
....
</li>

4. Birçok denetleyicinin belirli eylemi için (virgülle ayrılmış olarak)

<li class="<%= active('controller_name1,controller_name2', 'action_name')%>">
....
</li>

5. Herhangi bir belirli denetleyicinin bazı belirli eylemleri için

<li class="<%= active('controller_name', 'index, show')%>">
....
</li>

6. Birçok denetleyicinin bazı özel eylemleri için (virgülle ayrılmış olarak)

<li class="<%= active('controller_name1,controller_name2', 'index, show')%>">
....
</li>

Umarım yardımcı olur

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.