Cách tốt nhất để thêm lớp “hiện tại” vào điều hướng trong Rails 3


111

Tôi có một số trang tĩnh trong menu điều hướng. Tôi muốn thêm một lớp như "hiện tại" vào mục hiện đang hiển thị.

Cách tôi đang làm là thêm hàng tấn phương thức trợ giúp (mỗi phương thức cho một mục) để kiểm tra bộ điều khiển và hành động.

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

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

Có cách nào tốt hơn để làm như vậy không !? Cách làm hiện tại của tôi thật ngu ngốc ......

Câu trả lời:


56

Không thực sự là một câu trả lời ở đây, bởi vì tôi đang sử dụng khá giống với bạn. Tôi vừa xác định các phương thức trợ giúp để kiểm tra nhiều bộ điều khiển hoặc hành động:

Trong application_helper.rb

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

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

Sau đó, bạn có thể sử dụng if controller?("homepage") && action?("index", "show")trong dạng xem của mình hoặc các phương pháp trợ giúp khác…


Cách của bạn phù hợp nhất khi có một số trang được xử lý bởi các bộ điều khiển / hành động khác nhau nhưng trong cùng một mục menu, phải không? Bạn đã gặp nhiều thuận lợi hơn chưa ~?
PeterWong

Không có lợi thế nào ngoại trừ sự ngắn gọn của cú pháp. Tôi tò mò muốn xem liệu ai đó có giải pháp tốt hơn không.
Yannis

Tôi đã làm phương pháp này với thành công lớn. Đã thêm mã này vào chế độ xem: <% = link_to "Users", users_path, class: (controller? ("Users")? 'Select': nil)%> Thực sự gọn gàng vì nó hoạt động cho cả / người dùng và / người dùng / mới .
Andreas

1
một sự cải tiến có thể được controller_nameaction_namethay vì params lẽ
Francesco Belladonna

Làm tốt. Tôi đã không nghĩ đến việc giữ nó đơn giản nhưng quy mô này rất đẹp. +1
newdark-it

290

Tôi đã gọi một người trợ giúp 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

được sử dụng như:

nav_link 'Home', root_path

sẽ tạo ra HTML như

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

3
Điều này hoạt động tuyệt vời với twitter ootstrap nếu bạn đang sử dụng twitter bootstrap navbar twitter.github.com/bootstrap/examples/hero.html
Lee McAlilly 29/02/12

41
Thay đổi thành class_name = current_page? (Link_path)? 'hiện tại': nil nếu bạn không muốn tag lớp để hiển thị khi không phải trên trang hiện tại
Matthew Hui

1
Bạn sẽ sửa đổi điều này như thế nào cho các danh sách lồng nhau được sử dụng trong trình đơn thả xuống?
doremi

9
KHÔ như sa mạc
Orlando

1
Tôi đã thêm một vài đối số bổ sung extra_classes = nil, id = nil sau đó bên trong content_tag content_tag (: li, class: [class_name, extra_classes], id: id) để bạn cũng có thể thêm các lớp và id của riêng mình vào các phần tử :)
Jon

72

Sử dụng trình current_page?trợ giúp để xác định xem bạn có nên chỉ định "current"lớp học hay không . Ví dụ:

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

Lưu ý: Bạn cũng có thể vượt qua một con đường (không chỉ là một hash của tùy chọn), ví dụ: current_page?(root_path).


3
Có cách nào để làm điều này để bỏ qua các tham số truy vấn không?
Mohamad

@Mohamad, bạn có thể làm điều này: current_page? (Controller: 'users', action: 'index')
nilid

26

Tôi sử dụng hàm nav_link (văn bản, liên kết) này trong application_helper.rb (Rails 3) để hoàn thành công việc và nó cuộn các liên kết thanh điều hướng bootstrap twitter 2.0 cho tôi.

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

Thí dụ:

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

Điều này có thể được đơn giản hóa bằng cách sử dụng current_page?phương pháp này, như trong các câu trả lời khác.
Teemu Leisti

10

Cách tôi đã làm là thêm một hàm trợ giúp trong application_helper

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

Sau đó, trong điều hướng,

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

Thao tác này kiểm tra đường dẫn liên kết đối với trang hiện tại và trả về lớp hiện tại của bạn hoặc một chuỗi trống.

Tôi đã không thử nghiệm điều này kỹ lưỡng và tôi rất mới với RoR (chuyển qua PHP sau một thập kỷ) vì vậy nếu điều này có một lỗ hổng lớn, tôi rất muốn nghe nó.

Ít nhất với cách này bạn chỉ cần 1 chức năng trợ giúp và một lệnh gọi đơn giản trong mỗi liên kết.


1
Chỉ là một vấn đề. Tôi đã sử dụng request.path thay vì request_uri (request_uri không hoạt động, có thể sự cố phiên bản đường ray?). Câu trả lời của bạn là sạch sẽ và thanh lịch theo ý kiến ​​của tôi.
Tony

6

Để xây dựng câu trả lời của @Skilldrick ...

Nếu bạn thêm mã này vào application.js, nó sẽ đảm bảo rằng bất kỳ menu thả xuống nào có trẻ em đang hoạt động cũng sẽ được đánh dấu là đang hoạt động ...

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

Để tóm tắt lại mã hỗ trợ> Thêm người trợ giúp có tên nav_link:

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

được sử dụng như:

nav_link_to 'Home', root_path

sẽ tạo ra HTML như

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

4

Tôi nghĩ cách tốt nhất là

application_helper.rb:

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

trong menu:

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

để trống lớp "" như vậy có ổn không?
Harsha MV

Đúng. Có thể trông lạ nếu bạn xem nguồn thấy một loạt các thuộc tính lớp trống, nhưng đó là HTML hợp lệ.
kobaltz

Bạn có thể sử dụng <%= content_tag(:li, "Click me", class: is_active('controller', 'action')) %>, nó sẽ không in một thuộc tính lớp cho nil. apidock.com/rails/ActionView/Helpers/TagHelper/content_tag
neonmate

4

Tôi biết đó là một câu trả lời lỗi thời, nhưng bạn có thể dễ dàng bỏ qua tất cả các bước kiểm tra trang hiện tại này bằng cách sử dụng trình bao bọc của trình trợ giúp link_to, được gọi là gem active_link_to , nó hoạt động chính xác những gì bạn muốn, thêm một lớp hoạt động vào liên kết trang hiện tại


4

Đây là ví dụ đầy đủ về cách thêm một lớp đang hoạt động trên trang menu bootstrap ở dạng xem rails.

    <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

Tôi sử dụng một viên ngọc tuyệt vời có tên là Tabs on Rails .


1
Cám ơn vì sự gợi ý. Vì điều hướng của tôi quá đơn giản và chỉ có một cái với ít vật phẩm, viên đá quý có thể sẽ bị quá tải.
PeterWong

3

Tôi có một phiên bản nav_link ngắn gọn hơn hoạt động chính xác như link_to, nhưng được tùy chỉnh để xuất ra thẻ bao bọc li.

Đặt phần sau vào application_helper.rb của bạn

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

Nếu bạn nhìn vào đoạn mã trên và so sánh nó với mã link_to trong url_helper.rb, điểm khác biệt duy nhất là nó sẽ kiểm tra xem url có phải là trang hiện tại hay không và thêm lớp "active" vào một thẻ bao bọc li. Điều này là do tôi đang sử dụng trình trợ giúp nav_link với thành phần nav của Twitter Bootstrap thích liên kết được bọc bên trong thẻ li và lớp "hoạt động" được áp dụng cho li bên ngoài.

Điều thú vị về đoạn mã trên là nó cho phép bạn chuyển một khối vào hàm, giống như bạn có thể làm với link_to.

Ví dụ: một danh sách điều hướng bootstrap với các biểu tượng sẽ giống như sau:

Mảnh khảnh:

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

Đầu ra:

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

Ngoài ra, giống như trình trợ giúp link_to, bạn có thể chuyển các tùy chọn HTML vào nav_link, tùy chọn này sẽ được áp dụng cho thẻ.

Ví dụ về việc chuyển tiêu đề cho anchor:

Mảnh khảnh:

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

Đầu ra:

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

Tuyệt vời. Đối với tôi, đây là lựa chọn khả thi nhất chính xác vì nó cho phép các khối. Cảm ơn rất nhiều!
Kasperi

3

Đối với cá nhân tôi, tôi đã sử dụng kết hợp các câu trả lời ở đây

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

Tôi đang sử dụng css materialize và cách của tôi để làm cho các danh mục chính có thể thu gọn là sử dụng mã bên dưới

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

hy vọng nó sẽ giúp ai đó


quên về điều này. Cảm ơn vì đã đăng bài này như một lời nhắc nhở.
newdark-it

2

Các current_page?phương pháp không phải là đủ linh hoạt đối với tôi (giả sử bạn đặt một bộ điều khiển nhưng không phải là một hành động, sau đó nó sẽ chỉ trả lại đúng vào action index của bộ điều khiển), vì vậy tôi đã thực hiện này dựa trên các câu trả lời khác:

  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

Thí dụ:

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

Cảm ơn bạn vì câu trả lời. Tôi nghĩ bạn cũng tương tự như câu trả lời được chấp nhận thực tế :)
PeterWong

Tôi đã xem qua câu trả lời này thông qua Google kể từ khi tôi đã có vấn đề này, vì vậy tôi nghĩ rằng tôi muốn giúp đỡ tất cả mọi người đi qua này là tốt :)
unrelativity

2

Vâng! Kiểm tra bài viết này: Cách tốt hơn để thêm một lớp 'được chọn' vào các liên kết trong Rails

Thả nav_link_helper.rb vào app / helpers và nó có thể dễ dàng như sau:

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

Trình trợ giúp nav_link hoạt động giống như trình trợ giúp Rails link_to tiêu chuẩn, nhưng thêm một lớp 'đã chọn' vào liên kết của bạn (hoặc trình bao bọc của nó) nếu đáp ứng các tiêu chí nhất định. Theo mặc định, nếu url đích của liên kết giống với url của trang hiện tại, một lớp mặc định là 'đã chọn' sẽ được thêm vào liên kết.

Có một ý chính ở đây: https://gist.github.com/3279194

CẬP NHẬT: Đây hiện là một viên ngọc: http://rubygems.org/gems/nav_link_to


Cái này đẹp đấy. Tôi đã sử dụng và thêm một sửa đổi để hỗ trợ đặt tên lớp cho các phần tử không được chọn, cũng như một nhận xét trong ý chính.
Teemu Leisti

2

Tôi sử dụng một trình trợ giúp đơn giản như thế này cho các liên kết cấp cao nhất để /stories/my-storytrang làm nổi bật /storiesliên kết

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

Hãy để tôi chỉ ra giải pháp của tôi:

_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

Theo câu trả lời của Skilldrick , tôi sẽ thay đổi nó thành như sau:

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

để làm cho nó hữu ích hơn nhiều.


1

Phiên bản này dựa trên phiên bản của @ Skilldrick nhưng cho phép bạn thêm nội dung html.

Do đó, bạn có thể làm:

nav_link "A Page", a_page_path

nhưng cũng:

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

hoặc bất kỳ nội dung html nào khác (bạn có thể thêm một biểu tượng chẳng hạn).

Đây là người trợ giúp:

  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

Tôi nghĩ rằng tôi đã nghĩ ra một giải pháp đơn giản có thể hữu ích cho nhiều trường hợp sử dụng. Điều này cho phép tôi:

  • Hỗ trợ không chỉ văn bản thuần túy mà còn hỗ trợ HTML bên trong link_to(ví dụ: thêm biểu tượng bên trong liên kết)
  • Chỉ thêm một vài dòng mã vào application_helper.rb
  • Nối activevào toàn bộ tên lớp của phần tử liên kết thay vì nó là lớp duy nhất.

Vì vậy, hãy thêm cái này vào 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

Và trên mẫu của bạn, bạn có thể có một cái gì đó như thế này:

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

Phần thưởng, bạn có thể chỉ định hoặc không a class_namevà sử dụng nó như thế này:<div class="<%= current_page?(root_path) %>">

Cảm ơn các câu trả lời 1 , 2 trước đó và các nguồn .


0

tất cả những thứ này hoạt động với các thanh điều hướng đơn giản, nhưng còn menu phụ thả xuống thì sao? khi một menu phụ được chọn, mục menu trên cùng phải được đặt thành 'hiện tại' trong trường hợp này tabs_on_rails tôi là giải pháp


0

Đây là cách tôi giải quyết trong dự án hiện tại của mình.

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

Sau đó..

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

0

Cách dễ dàng của tôi -

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

Cảm ơn.


0

Nếu bạn cũng muốn hỗ trợ tùy chọn html băm trong chế độ xem. Ví dụ: nếu bạn muốn gọi nó bằng lớp hoặc id CSS khác, bạn có thể xác định hàm trợ giúp như thế này.

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

Vì vậy, trong chế độ xem, hãy gọi trình trợ giúp này giống như cách bạn gọi link_to helper

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

0

Tạo một phương thức ApplicationHelpernhư bên dưới.

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

Bây giờ hãy sử dụng nó trong các trường hợp sử dụng dưới đây.

1. Đối với tất cả các hành động của bất kỳ bộ điều khiển cụ thể nào

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

2. Đối với tất cả các hành động của nhiều bộ điều khiển (có dấu phẩy được phân tách)

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

3. Đối với hành động cụ thể của bất kỳ bộ điều khiển cụ thể nào

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

4. Đối với hành động cụ thể của nhiều bộ điều khiển (được phân tách bằng dấu phẩy)

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

5. Đối với một số hành động cụ thể của bất kỳ bộ điều khiển cụ thể nào

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

6. Đối với một số hành động cụ thể của nhiều bộ điều khiển (được phân tách bằng dấu phẩy)

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

Hy vọng nó giúp

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.