Rails 5.1+的簡單視圖組件,旨在與Elemental_styleguide配合使用。兩者一起靈感來自布拉德·弗羅斯特(Brad Frost)的作品以及《孤獨星球風格指南》(Rizzo)背後的想法。
將此行添加到您的應用程序的gemfile:
gem "elemental_components"然後執行:
$ bundle此處提供的示例將使用BEM命名約定。
組件生活在app/components中。通過執行來生成組件:
$ bin/rails g elemental_components:component alert這將創建以下文件:
app/
components/
alert/
_alert.html.erb
alert.css
alert.js
alert_component.rb
發電機還採用--skip-css和--skip-js選項。
讓我們添加一些標記和CSS:
<% # app/components/alert/_alert.html.erb %>
< div class =" alert alert--primary " role =" alert " >
Message
</ div > /* app/components/alert/alert.css */
. alert {
padding : 1 rem ;
}
. alert--primary {
background : blue;
}
. alert--success {
background : green;
}
. alert--danger {
background : red;
}現在可以使用component助手來渲染此組件:
<%= component "alert" %> 為了需要CSS之類的資產,要么在清單中手動需要它們,例如application.css :
/*
*= require alert/alert
*/或需要components ,這又需要所有組件的資產:
/*
*= require elemental_components
*/將數據傳遞給組件有兩種方法:屬性和內容塊。屬性可用於數據,例如ID,修飾符和數據結構(模型等)。當您需要將HTML內容注入組件時,內容塊很有用。
讓我們定義一些我們剛創建的組件的屬性:
# app/components/alert_component.rb %>
class AlertComponent < ElementalComponents :: Component
attribute :context
attribute :message
end <% # app/components/alert/_alert.html.erb %>
< div class =" alert alert-- <%= alert.context %> " role =" alert " >
<%= alert.message %>
</ div > <%= component "alert", message: "Something went right!", context: "success" %>
<%= component "alert", message: "Something went wrong!", context: "danger" %> 為了將一些文本或HTML內容注入我們的組件中,我們可以在模板中打印組件。包含方法,並通過將內容塊傳遞給組件助手:填充它:
<% # app/components/alert/_alert.html.erb %>
< div class =" alert alert-- <%= alert.context %> " role =" alert " >
<%= alert.content %>
</ div > <%= component "alert", context: "success" do %>
< em > Something </ em > went right!
<% end %>屬性的另一個好的用例是,當您具有由模型支持的組件時:
# app/components/comment_component.rb %>
class CommentComponent < ElementalComponents :: Component
attribute :comment
delegate :id ,
:author ,
:body , to : :comment
end <% # app/components/comment/_comment.html.erb %>
< div id =" comment- <%= comment.id %> " class =" comment " >
< div class =" comment__author " >
<%= link_to comment.author.name, author_path(comment.author) %>
</ div >
< div class =" comment__body " >
<%= comment.body %>
</ div >
</ div > <% comments.each do |comment| %>
<%= component "comment", comment: comment %>
<% end %> 屬性可以具有默認值:
# app/components/alert_component.rb %>
class AlertComponent < ElementalComponents :: Component
attribute :message
attribute :context , default : "primary"
end用其他邏輯覆蓋屬性很容易:
# app/components/alert_component.rb %>
class AlertComponent < ElementalComponents :: Component
attribute :message
attribute :context , default : "primary"
def message
@message . upcase if context == "danger"
end
end為了確保您的組件適當初始化,您可以在元素或組件中使用ActiveModel::Validations :
# app/components/alert_component.rb %>
class AlertComponent < ElementalComponents :: Component
attribute :label
validates :label , presence : true
end您的驗證將在組件初始化期間執行,並在任何驗證失敗時提高ActiveModel::ValidationError 。
屬性和塊非常適合以數據結構(例如模型)支持的簡單組件或組件。其他組件本質上是更通用的,可以在各種情況下使用。它們通常由多個部分或元素組成,有時會重複,有時需要自己的修飾符。
取一個卡組件。在React中,一種常見的方法是創建子組件:
< Card flush = { true } >
< CardHeader centered = { true } >
Header
</ CardHeader >
< CardSection size = "large" >
Section 1
</ CardSection >
< CardSection size = "small" >
Section 2
</ CardSection >
< CardFooter >
Footer
</ CardFooter >
</ Card >這種方法有兩個問題:
CardHeader放置在Card外。CardHeader放置在下面或在CardFooter內。使用此GEM,可以像這樣編寫相同的組件:
# app/components/card_component.rb %>
class CardComponent < ElementalComponents :: Component
attribute :flush , default : false
element :header do
attribute :centered , default : false
end
element :section , multiple : true do
attribute :size
end
element :footer
end <% # app/components/card/_card.html.erb %>
< div class =" card <%= "card--flush" if card.flush %> " >
<% if card.header.content? %>
< div class =" card__header <%= "card__header--centered" if card.header.centered %> " >
<%= card.header.content %>
</ div >
<% end %>
<% card.sections.each do |section| %>
< div class =" card__section <%= "card__section--#{section.size}" %> " >
<%= section.content %>
</ div >
<% end %>
<% if card.footer.content? %>
< div class =" card__footer " >
<%= card.footer.content %>
</ div >
<% end %>
</ div >可以將元素視為孤立的子組件,並且它們在組件上定義。傳遞multiple: true使其成為重複元素,並且通過一個塊使我們可以以相同的方式聲明元素上的屬性。
為了用數據填充它們,我們將一個塊傳遞給組件助手,該組件輔助器會產生組件,這使我們可以在元素上以相同的方式對元素設置屬性和內容塊:
<%= component "card", flush: true do |c| %>
<% c.header centered: true do %>
Header
<% end %>
<% c.section size: "large" do %>
Section 1
<% end %>
<% c.section size: "large" do %>
Section 2
<% end %>
<% c.footer do %>
Footer
<% end %>
<% end %> 對重複元素的多個調用,例如上面的示例中的section ,將每個部分附加到數組。
另一個好的用例是導航組件:
# app/components/navigation_component.rb %>
class NavigationComponent < ElementalComponents :: Component
element :items , multiple : true do
attribute :label
attribute :url
attribute :active , default : false
end
end <%= component "navigation" do |c| %>
<% c.item label: "Home", url: root_path, active: true %>
<% c.item label: "Explore" url: explore_path %>
<% end %> 這裡的替代方法是將數據結構作為屬性傳遞給組件,如果在渲染組件時不需要注入HTML:
<%= component "navigation", items: items %> 元素也可以進行驗證:
class NavigationComponent < ElementalComponents :: Component
element :items , multiple : true do
attribute :label
attribute :url
attribute :active , default : false
validates :label , presence : true
validates :url , presence : true
end
end元素也可以嵌套,儘管建議將嵌套到最低限制:
# app/components/card_component.rb %>
class CardComponent < ElementalComponents :: Component
...
element :section , multiple : true do
attribute :size
element :header
element :footer
end
end除了聲明屬性和元素外,還可以聲明助手方法。如果您希望將邏輯放在模板之外,這將很有用。讓我們從卡組件模板中提取修飾符邏輯:
# app/components/card_component.rb %>
class CardComponent < ElementalComponents :: Component
...
def css_classes
css_classes = [ "card" ]
css_classes << "card--flush" if flush
css_classes . join ( " " )
end
end <% # app/components/card/_card.html.erb %>
<%= content_tag :div, class: card.css_classes do %>
...
<% end %>甚至可以在元素上宣布幫助者:
# app/components/card_component.rb %>
class CardComponent < ElementalComponents :: Component
...
element :section , multiple : true do
attribute :size
def css_classes
css_classes = [ "card__section" ]
css_classes << "card__section-- #{ size } " if size
css_classes . join ( " " )
end
end
end <% # app/components/card/_card.html.erb %>
<%= content_tag :div, class: card.css_classes do %>
...
<%= content_tag :div, class: section.css_classes do %>
<%= section %>
<% end %>
...
<% end %>助手方法還可以使用@view實例變量,以調用link_to或content_tag等導軌幫助者。
對於某些小組件(例如按鈕),完全跳過部分以加快渲染速度可能是有意義的。這可以通過在組件上覆蓋render來完成:
# app/components/button_component.rb %>
class ButtonComponent < ElementalComponents :: Component
attribute :label
attribute :url
attribute :context
def render
@view . link_to label , url , class : css_classes
end
def css_classes
css_classes = "button"
css_classes << "button-- #{ context } " if context
css_classes . join ( " " )
end
end <%= component "button", label: "Sign up", url: sign_up_path, context: "primary" %>
<%= component "button", label: "Sign in", url: sign_in_path %> 組件可以嵌套在名稱空間下。如果您想練習諸如原子設計,bemit或任何其他組件分類方案之類的東西,這將很有用。為了創建名稱尺寸的組件,請將其粘貼在文件夾中,然後將類包裝在模塊中:
module Objects
class MediaObject < ElementalComponents :: Component ; end
end然後從類似模板中調用它:
<%= component "objects/media_object" %> 該圖書館與Elemental_styleguide一起,靈感來自布拉德·弗羅斯特(Brad Frost)關於原子設計和生活方式指南的著作,以及《孤獨星球風格指南》(Rizzo)。其他靈感是:
有關現實世界風格指南的列表,請查看http://styleguides.io。