有条件地向视图中的 HTML 元素添加类的优雅方法是什么?

我偶尔需要根据条件向 html 元素添加一个类。问题是我想不出一个干净利落的方法。下面是我试过的一个例子:

<div <%= if @status = 'success'; "class='ok'"; end %>>
some message here
</div>

或者

<% if @status == 'success' %>
<div class='success'>
<% else %>
<div>
<% end %>
some message here
</div>

我不喜欢第一种方法,因为它看起来拥挤而且难以阅读。我不喜欢第二种方法,因为嵌套搞砸了。把它放到模型中是很好的,(类似于 @status.css_class) ,但是它不属于那里。大多数人都做什么?

95743 次浏览

我使用第一种方法,但语法稍微简洁一些:

<div class="<%= 'ok' if @status == 'success' %>">

Though usually you should represent success with boolean true or a numeric record ID, and failure with boolean false or nil. This way you can just test your variable:

<div class="<%= 'ok' if @success %>">

如果您想在两个类之间进行选择,那么使用三元 ?:运算符的第二种形式是有用的:

<div class="<%= @success ? 'good' : 'bad' %>">

最后,您可以使用 Rail 的 记录标签助手,例如 div_for,它将根据您提供的记录自动设置您的 ID 和类。给定一个 id 为47的 Person:

# <div id="person_47" class="person good">
<% div_for @person, class: (@success ? 'good' : 'bad') do %>
<% end %>

避免在视图中使用逻辑

标准方法的问题在于它需要以 if语句或视图中的三元组的形式进行逻辑。如果有多个条件 CSS 类与默认类混合,那么需要将该逻辑放入字符串插值或 ERB 标记中。

Here's an updated approach that avoids putting any logic into the views:

<div class="<%= class_string(ok: @success) %>">
some message here
</div>

class_string

class_string助手接受一个散列,其键/值对由 CSS 类名字符串布尔值组成。该方法的结果是一个类字符串,其中布尔值的计算结果为 true。

使用情况样本

class_names(foo: true, bar: false, baz: some_truthy_variable)
# => "foo baz"

其他用例

这个助手可以在 ERB标记中使用,也可以与诸如 link_to之类的 Rails 助手一起使用。

<div class="<%= class_string(ok: @success) %>">
some message here
</div>


<% div_for @person, class: class_string(ok: @success) do %>
<% end %>


<% link_to "Hello", root_path, class: class_string(ok: @success) do %>
<% end %>

无论是/或类

对于需要三元组的用例(例如 @success ? 'good' : 'bad') ,传递一个数组,其中第一个元素是 true的类,另一个元素是 false的类

<div class="<%= [:good, :bad] => @success %>">

灵感来自 React

This technique is inspired by an add-on called classNames (formerly known as classSet) from Facebook’s React front-end framework.

在 Rails 项目中使用

到目前为止,Rails 中还没有 class_names函数,但是 这篇文章向您展示了如何将其添加到项目中或实现它。

You can also use the content_for helper, especially if the DOM is located in a layout and you want to set the css class depending on the partial loaded.

关于布局:

%div{class: content_for?(:css_class) ? yield(:css_class) : ''}

关于局部:

- content_for :css_class do
my_specific_class

就是这样。

class_names (Rails 6.1+)

Rails 6.1引入了 class_names视图助手 更容易有条件地应用类名 视野。

以前:

<div class="<%= item.for_sale? ? 'active' : '' %>">

之后:

<div class="<%= class_names(active: item.for_sale?) %>">

更多例子:

class_names("foo", "bar")
# => "foo bar"
class_names({ foo: true, bar: false })
# => "foo"
class_names(nil, false, 123, "", "foo", { bar: true })
# => "123 foo bar"

Sources: