Применить класс CSS к элементу, если текущая страница в Phoenix

В настоящее время я хочу добавить класс CSS, если страница активна. Как лучше всего это сделать в Фениксе в настоящее время? Есть ли помощник на этот случай?

def active(option, conn) do
  if option == conn.request_path do
    " class=\"active\""
  else
    ""
  end
end

В шаблоне:

<%= "contact" |> active(@conn) |> raw %>

person rockerBOO    schedule 22.07.2015    source источник


Ответы (3)


Мы будем использовать conn.path_info, который возвращает текущий путь в виде списка строк вместо conn.request_path. Мы могли бы использовать это, чтобы получить нашего помощника active_class.

def active_class(conn, path) do
  current_path = Path.join(["/" | conn.path_info])
  if path == current_path do
    "active"
  else
    nil
  end
end

Затем мы используем его как:

<%= link "Users", to: user_path(@conn, :index), class: active_class(@conn, user_path(@conn, :index))%>

Обратите внимание, что мы user_path/2 дважды выше. Мы могли бы высушить это с помощью другого помощника:

def active_link(conn, text, opts) do
  class = [opts[:class], active_class(conn, opts[:to])]
          |> Enum.filter(& &1) 
          |> Enum.join(" ")
  opts = opts
         |> Keyword.put(:class, class)
  link(text, opts)
end

Зачем использовать conn.path_info вместо conn.request_path? Это связано с тем, что conn.request_path вернет точный путь, запрошенный пользователем. Если пользователь посещает путь /foo/, то conn.request_path вернет /foo/. Проблема в том, что помощник маршрутизатора, с которым мы будем сравнивать, всегда будет возвращать путь /foo без завершающего /.

Надеюсь, это поможет! Дайте мне знать, если что-то неясно.

person Gjaldon    schedule 23.07.2015
comment
Это кажется довольно ясным и довольно простым и работает напрямую с путями. conn.request_path сейчас находится в мастере 0.15 на github, но его нет в ‹ 0.15. - person rockerBOO; 23.07.2015
comment
@rockerBOO, ты прав. Это в plug master. Пробовал, но я бы все же предложил использовать conn.path_info. Я обновлю свой ответ, почему - person Gjaldon; 24.07.2015

Я создал помощник для этого, который выглядит так:

defmodule LinkHelper
  @doc """
  Calls `active_link/3` with a class of "active"
  """
  def active_link(conn, controllers) do
    active_link(conn, controllers, "active")
  end

  @doc """
  Returns the string in the 3rd argument if the expected controller
  matches the Phoenix controller that is extracted from conn. If no 3rd
  argument is passed in then it defaults to "active".

  The 2nd argument can also be an array of controllers that should
  return the active class.
  """
  def active_link(conn, controllers, class) when is_list(controllers) do
    if Enum.member?(controllers, Phoenix.Controller.controller_module(conn)) do
      class
    else
      ""
    end
  end

  def active_link(conn, controller, class) do
    active_link(conn, [controller], class)
  end
end

Затем я импортирую это в функцию def view внутри web/web.ex

def view do
  ...
  import LinkHelper
  ...
end

Применение:

<li class="<%= active_link(@conn, PageController)%>"><a href="<%= page_path(@conn, :index) %>">Home</a></li>
<li class="<%= active_link(@conn, [FooController, BarController])%>"><a href="<%= foo_path(@conn, :index) %>">Foo or Bar</a></li>
person Gazler    schedule 22.07.2015
comment
Это кажется хорошим выбором для интеграции в систему контроллера. Некоторые проблемы с вашим примером кода. defmodule LinkHelper do и import LinkHelper - person rockerBOO; 24.07.2015
comment
@rockerBOO хорошее место - должно быть, забыл обновить импорт, когда копировал его! - person Gazler; 24.07.2015
comment
Разве этот подход не устанавливает активную ссылку для всех действий контроллера, которые вы ему передаете? Например, page_path(@conn, :index) и page_path(@conn, :show) будут активны, если вы передадите PageController в active_link/3. Разве мы не хотим, чтобы страница show была активной, только если мы находимся в page.show? - person Gjaldon; 25.07.2015

У меня работает следующий код, включая отслеживание параметров:

вспомогательная функция выглядит следующим образом:

def active_class(path, conn) do
  query_string = cond do
    conn.query_string == "" -> ""
    true -> "?#{conn.query_string}"
  end
  if ("#{conn.request_path}#{query_string}" === path) do "active" else "" end
end

и в представлении:

<% important_issues_path = issue_path(@conn, :index, important: true) %>

<%= link "important", to: important_issues_path,
    class: "nav-link #{
      MyApp.TheHelper.active_class(important_issues_path, @conn)
   }"
%>
person Amed    schedule 24.06.2018