Найкращий спосіб додати «поточний» клас до навичок у Rails 3


111

У мене в навігаційному меню є кілька статичних сторінок. Я хочу додати такий клас, як "current", до елемента, який наразі відображається.

Я так роблю, щоб додати тонни допоміжних методів (кожен для одного предмета), щоб перевірити контролер та дії.

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

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

Чи є кращий спосіб зробити це !? Мій сучасний спосіб такий дурний ......

Відповіді:


56

Тут справді не відповідь, тому що я використовую зовсім так само, як і ви. Я щойно визначив допоміжні методи для тестування на кілька контролерів або дій:

У application_helper.rb

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

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

Тоді ви можете використовувати if controller?("homepage") && action?("index", "show")у своїх поглядах чи інші допоміжні методи ...


Ваш спосіб найкраще підходить, коли на деяких сторінках обробляються різні контролери / дії, але в одному пункті меню, правда? Чи стикалися ви з більшими перевагами ~?
PeterWong

Немає більшої переваги, крім лаконічності синтаксису. Мені цікаво побачити, чи є хтось інший кращого рішення.
Янніс

Я зробив цей метод з великим успіхом. Додано цей код до подання: <% = link_to "Користувачі", users_path, class: (контролер? ("Користувачі")? 'Вибрано': nil)%> Дійсно, що він працює як для / користувачів, так і для користувачів / нових .
Андреас

1
поліпшення може бути, controller_nameа action_nameзамість парамів, мабуть,
Франческо Беладонна

Молодці. Я не думав зберігати це просто, але ця шкала дуже гарно. +1
newdark-it

290

Я зробив помічника під назвою 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

використовується як:

nav_link 'Home', root_path

який створить HTML на зразок

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

3
Це чудово працює з twitter ootstrap, якщо ви використовуєте завантажувач twitter bootstrap navbar twitter.github.com/bootstrap/examples/hero.html
Lee McAlilly

41
Змінити на class_name = current_page? (Link_path)? 'current': нуль, якщо ви не хочете, щоб тег класу відображався, коли його немає на поточній сторінці
Matthew Hui

1
Як би ви змінили це для вкладених списків, що використовуються у спадному меню?
doremi

9
СУХАЙТЕ як пустеля
Орландо

1
Я додав кілька додаткових аргументів extra_classes = nil, id = nil тоді всередині content_tag content_tag (: li, class: [class_name, extra_classes], id: id), щоб ви могли додавати власні класи та id до елементів. :)
Джон

72

За допомогою current_page?помічника визначте, чи слід призначати "current"клас чи ні . Наприклад:

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

Зверніть увагу , ви також можете пройти шлях (не тільки хеш опцій), наприклад: current_page?(root_path).


3
Чи є спосіб отримати це, щоб ігнорувати параметри запитів?
Мохамад

@Mohamad, ти можеш це зробити: current_page? (Контролер: 'users', action: 'index')
nilid

26

Я використовую цю функцію nav_link (текст, посилання) в application_helper.rb (Rails 3), щоб виконати роботу, і вона перекочує мій завантажувальний twitter 2.0 навігаційний бар для мене.

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

Приклад:

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

Це можна спростити за допомогою current_page?методу, як і в інших відповідях.
Teemu Leisti

10

Те, що я це зробив, - це додати функцію помічника в application_helper

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

Потім у nav,

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

Це тестує шлях посилання на поточний uri сторінки та повертає або ваш поточний клас, або порожній рядок.

Я не перевіряв цього ретельно, і я дуже новачок у RoR (переміщення після десятиліття з PHP), тож якщо у цього є головний недолік, я б хотів це почути.

Принаймні таким чином вам потрібно лише 1 функція помічника та простий дзвінок у кожному посиланні.


1
Просто проблема. Я використовував request.path замість request_uri (request_uri не працював, можливо, проблема з версією rails?). На мою думку, ваша відповідь чиста і елегантна.
Тоні

6

Щоб створити відповідь @Skilldrick ...

Якщо ви додасте цей код у application.js, він переконається, що будь-які спадні меню з активними дітьми також будуть позначені як активні ...

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

Щоб повторно підказати підтримуючий код> Додайте помічник під назвою 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

використовується як:

nav_link_to 'Home', root_path

який створить HTML на зразок

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

4

Я думаю, що найкращий спосіб

application_helper.rb:

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

І в меню:

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

чи добре залишати порожній клас "" таким?
Харша М. В.

Так. Це може виглядати дивно, якщо ви переглядаєте джерело, яке бачить купу порожніх атрибутів класу, але це дійсний HTML.
кобальц

Ви можете використовувати <%= content_tag(:li, "Click me", class: is_active('controller', 'action')) %>, він не буде друкувати атрибут класу для nil. apidock.com/rails/ActionView/Helpers/TagHelper/content_tag
неоновий

4

Я знаю, що це застаріла відповідь, але ви можете легко проігнорувати всі ці поточні перевірки сторінки, скориставшись допоміжною обгорткою link_to під назвою active_link_to gem, вона працює саме так, як ви хочете, додайте активний клас до посилання на поточну сторінку


4

Ось повний приклад того, як додати активний клас на сторінку меню завантажувального вікна в режимі подання рейлів.

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


1
Дякую за пропозицію. Оскільки мій навичок настільки простий і є лише один з невеликими предметами, дорогоцінний камінь, ймовірно, перевантажений живленням.
PeterWong

3

У мене є більш лаконічна версія nav_link, яка працює точно так само, як link_to, але налаштована для виведення обгорткового тегу li.

Помістіть наступне у своєму application_helper.rb

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

Якщо ви подивитеся на наведений вище код і порівняєте його з кодом link_to в url_helper.rb, різниця полягає лише в тому, що він перевіряє, чи є URL-адресою поточну сторінку, і додає клас "активний" до обгорткового тегу li. Це тому, що я використовую помічник nav_link з навігаційним компонентом Twitter Bootstrap який надає перевагу загортанню посилань всередині тегів li та класу "active", застосованого до зовнішнього li.

Приємна річ у наведеному вище коді полягає в тому, що він дозволяє вам перейти в блок у функцію, як ви можете це зробити з link_to.

Наприклад, навігаційний список для завантаження з іконками виглядатиме так:

Тонкий:

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

Вихід:

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

Крім того, подібно до помічника link_to, ви можете передати параметри HTML у nav_link, який буде застосовано до тегу.

Приклад передачі заголовка для якіря:

Тонкий:

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

Вихід:

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

Дивовижно. Для мене це був найбільш життєздатний варіант саме тому, що він дозволяє блокувати. Дякую тонну!
Каспер

3

Для мене особисто я використав комбінацію відповідей

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

Я використовую materialize css, і мій спосіб зробити основні категорії збірними - це за допомогою наведеного нижче коду

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

сподіваюся, що це комусь допоможе


забув про це. Дякуємо, що опублікували це як нагадування.
newdark-це

2

current_page?Метод не є достатньо гнучким для мене (скажімо , ви встановили контролер , але не дія, то він буде повертати істину лише на вказівному дії контролера), так що я зробив це на основі інших відповідей:

  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

Приклад:

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

Спасибі за вашу відповідь. Я думаю, що ваша схожа на прийняту відповідь насправді :)
PeterWong

Я натрапив на цю відповідь через Google, оскільки у мене була ця проблема, тому я подумав, що допоможу і всім іншим, хто стикається з цим :)
нереальність

2

Так! Перегляньте цю статтю: Кращий спосіб додати "вибраний" клас до посилань у рейках

Завантажте nav_link_helper.rb у додаток / помічники, і це може бути так само просто, як:

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

Помічник nav_link працює так само, як і стандартний помічник Rails link_to, але додає клас "вибраний" до вашого посилання (або його обгортки), якщо певні критерії виконуються. За замовчуванням, якщо URL-адреса посилання є тим же URL-адресом, що і URL-адреса поточної сторінки, до посилання додається клас "вибраний" за замовчуванням.

Тут є суть: https://gist.github.com/3279194

ОНОВЛЕННЯ: Зараз це дорогоцінний камінь: http://rubygems.org/gems/nav_link_to


Це добре. Я взяв у користування і додав модифікацію для підтримки надання класу імені класу невибраним елементам, також як коментар у суті.
Teemu Leisti

2

Я використовую простий помічник на зразок цього для посилань верхнього рівня, тому /stories/my-storyсторінка висвітлює /storiesпосилання

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

Дозвольте мені показати своє рішення:

_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

Відповідно до відповіді Skilldrick , я зміню її на наступну:

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

щоб зробити його набагато кориснішим.


1

Ця версія заснована на версії @ Skilldrick, але дозволяє додавати HTML-вміст.

Таким чином, ви можете:

nav_link "A Page", a_page_path

але також:

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

або будь-який інший вміст html (ви можете додати, наприклад, значок).

Тут помічник:

  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

Я думаю, що я придумав просте рішення, яке може бути корисним у багатьох випадках використання. Це дозволяє мені:

  • Підтримуйте не тільки звичайний текст, але й HTML всередині link_to (наприклад, додайте значок всередині посилання)
  • Додайте лише кілька рядків коду до application_helper.rb
  • Додайте activeдо всього класу ім'я елемента посилання, а не єдиного класу.

Отже, додайте це до 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

І у вашому шаблоні ви можете мати щось подібне:

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

Як бонус ви можете вказати чи ні class_nameта використовувати його так:<div class="<%= current_page?(root_path) %>">

Завдяки попереднім відповідям 1 , 2 та ресурсам .


0

всі ці роботи працюють з простими навігаційними панелями, а як бути зі спадним підменю? коли вибрано підменю, пункт верхнього меню повинен бути "поточним", в цьому випадку tabs_on_rails мені бути рішенням


0

Так я вирішив у своєму нинішньому проекті.

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

Тоді..

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

0

Мій простий шлях -

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

Дякую.


0

Якщо ви також хочете підтримувати html параметри хеша у представленні. Наприклад, якщо ви хочете викликати його за допомогою іншого класу CSS або id, ви можете визначити функцію помічника, як це.

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

Тож у вікні зателефонуйте цьому помічнику так само, як ви б викликали помічника link_to

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

0

Створіть метод, ApplicationHelperяк показано нижче.

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

Тепер використовуйте його з огляду на наведені нижче випадки використання.

1. Для всіх дій будь-якого конкретного контролера

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

2. Для всіх дій багатьох контролерів (з відокремленою комою)

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

3. Для конкретних дій будь-якого конкретного контролера

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

4. Для конкретних дій багатьох контролерів (з відокремленою комою)

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

5. Для деяких конкретних дій будь-якого конкретного контролера

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

6. Для деяких конкретних дій багатьох контролерів (з відокремленою комою)

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

Сподіваюся, це допомагає

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.