ส่วนประกอบมุมมองที่เรียบง่ายสำหรับ Rails 5.1+ ออกแบบมาให้เข้ากันได้ดีกับ Elemental_styleguide ทั้งสองได้รับแรงบันดาลใจจากผลงานของแบรดฟรอสต์และความคิดเบื้องหลังคู่มือสไตล์ Lonely Planet 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
*/มีสองวิธีในการส่งข้อมูลไปยังส่วนประกอบ: คุณลักษณะและบล็อกเนื้อหา แอตทริบิวต์มีประโยชน์สำหรับข้อมูลเช่น IDs, ตัวดัดแปลงและโครงสร้างข้อมูล (รุ่น ฯลฯ ) บล็อกเนื้อหามีประโยชน์เมื่อคุณต้องการฉีดเนื้อหา 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 หากการตรวจสอบใด ๆ ล้มเหลว
แอตทริบิวต์และบล็อกนั้นยอดเยี่ยมสำหรับส่วนประกอบหรือส่วนประกอบที่เรียบง่ายที่ได้รับการสนับสนุนโดยโครงสร้างข้อมูลเช่นโมเดล ส่วนประกอบอื่น ๆ นั้นมีอยู่ทั่วไปในธรรมชาติมากขึ้นและสามารถใช้ในบริบทที่หลากหลาย บ่อยครั้งที่พวกเขาประกอบด้วยหลายส่วนหรือองค์ประกอบบางครั้งที่ทำซ้ำและบางครั้งต้องการตัวดัดแปลงของตัวเอง
ใช้ส่วนประกอบการ์ด ในการตอบสนองวิธีการทั่วไปคือการสร้างส่วนประกอบย่อย:
< 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การใช้อัญมณีนี้ส่วนประกอบเดียวกันสามารถเขียนได้เช่นนี้:
# 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 หรือรูปแบบการจำแนกองค์ประกอบอื่น ๆ ในการสร้างส่วนประกอบ namespaced ติดไว้ในโฟลเดอร์และห่อคลาสในโมดูล:
module Objects
class MediaObject < ElementalComponents :: Component ; end
endจากนั้นเรียกมันจากเทมเพลตเช่นนั้น:
<%= component "objects/media_object" %> ห้องสมุดนี้พร้อมกับ Elemental_styleguide ได้รับแรงบันดาลใจจากงานเขียนของแบรดฟรอสต์เกี่ยวกับการออกแบบอะตอมและคู่มือสไตล์การใช้ชีวิตและ Rizzo คู่มือสไตล์ Lonely Planet แรงบันดาลใจอื่น ๆ คือ:
สำหรับรายการคู่มือสไตล์โลกแห่งความเป็นจริงลองดู http://styleguides.io