Komponen tampilan sederhana untuk Rails 5.1+, dirancang untuk cocok dengan elemental_styleguide. Keduanya bersama -sama terinspirasi oleh karya -karya Brad Frost dan oleh pemikiran di balik pemandu gaya Lonely Planet Rizzo.
Tambahkan baris ini ke gemfile aplikasi Anda:
gem "elemental_components"Dan kemudian mengeksekusi:
$ bundleContoh -contoh yang disediakan di sini akan menggunakan konvensi penamaan BEM.
Komponen hidup dalam app/components . Menghasilkan komponen dengan mengeksekusi:
$ bin/rails g elemental_components:component alertIni akan membuat file berikut:
app/
components/
alert/
_alert.html.erb
alert.css
alert.js
alert_component.rb
Generator juga mengambil opsi --skip-css dan --skip-js .
Mari kita tambahkan beberapa markup dan 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;
} Komponen ini sekarang dapat diterjemahkan menggunakan pembantu component :
<%= component "alert" %> Untuk meminta aset seperti CSS, baik mengharuskannya secara manual dalam manifes, misalnya application.css :
/*
*= require alert/alert
*/ Atau membutuhkan components , yang pada gilirannya akan memerlukan aset untuk semua komponen:
/*
*= require elemental_components
*/Ada dua cara untuk meneruskan data ke komponen: atribut dan blok konten. Atribut berguna untuk data seperti ID, pengubah dan struktur data (model dll). Blok konten berguna ketika Anda perlu menyuntikkan konten HTML ke dalam komponen.
Mari kita tentukan beberapa atribut untuk komponen yang baru saja kita buat:
# 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" %> Untuk menyuntikkan beberapa konten teks atau HTML ke dalam komponen kami, kami dapat mencetak metode komponen.
<% # 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 %>Kasing penggunaan lain yang baik untuk atribut adalah ketika Anda memiliki komponen yang didukung oleh model:
# 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 %> Atribut dapat memiliki nilai default:
# app/components/alert_component.rb %>
class AlertComponent < ElementalComponents :: Component
attribute :message
attribute :context , default : "primary"
endMudah untuk mengganti atribut dengan logika tambahan:
# app/components/alert_component.rb %>
class AlertComponent < ElementalComponents :: Component
attribute :message
attribute :context , default : "primary"
def message
@message . upcase if context == "danger"
end
end Untuk memastikan komponen Anda diinisialisasi dengan benar, Anda dapat menggunakan ActiveModel::Validations dalam elemen atau komponen Anda:
# app/components/alert_component.rb %>
class AlertComponent < ElementalComponents :: Component
attribute :label
validates :label , presence : true
end Validasi Anda akan dieksekusi selama inisialisasi komponen dan meningkatkan ActiveModel::ValidationError jika ada validasi yang gagal.
Atribut dan blok sangat bagus untuk komponen atau komponen sederhana yang didukung oleh struktur data, seperti model. Komponen lain lebih generik dan dapat digunakan dalam berbagai konteks. Seringkali mereka terdiri dari banyak bagian atau elemen, yang terkadang berulang, dan kadang -kadang membutuhkan pengubah mereka sendiri.
Ambil komponen kartu. Dalam Bereaksi, pendekatan umum adalah membuat subkomponen:
< Card flush = { true } >
< CardHeader centered = { true } >
Header
</ CardHeader >
< CardSection size = "large" >
Section 1
</ CardSection >
< CardSection size = "small" >
Section 2
</ CardSection >
< CardFooter >
Footer
</ CardFooter >
</ Card >Ada dua masalah dengan pendekatan ini:
CardHeader dapat ditempatkan di luar Card .CardHeader dapat ditempatkan di bawah, atau di dalam CardFooter .Menggunakan permata ini, komponen yang sama dapat ditulis seperti ini:
# 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 > Elemen dapat dianggap sebagai subkomponen yang terisolasi, dan mereka didefinisikan pada komponen. Melewati multiple: true menjadikannya elemen berulang, dan melewati blok memungkinkan kami menyatakan atribut pada elemen kami, dengan cara yang sama kami menyatakan atribut pada komponen.
Untuk mengisinya dengan data, kami meneruskan blok ke penolong komponen, yang menghasilkan komponen, yang memungkinkan kami mengatur atribut dan blok konten pada elemen dengan cara yang sama seperti yang kami lakukan untuk komponen:
<%= 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 %> Beberapa panggilan ke elemen berulang, seperti section dalam contoh di atas, akan menambahkan setiap bagian ke array.
Kasing penggunaan yang baik lainnya adalah komponen navigasi:
# 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 %> Alternatif di sini adalah meneruskan struktur data ke komponen sebagai atribut, jika tidak ada HTML yang perlu disuntikkan saat merender komponen:
<%= component "navigation", items: items %> Elemen juga dapat memiliki validasi:
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
endUnsur -unsur juga dapat bersarang, meskipun disarankan untuk tetap bersarang seminimal mungkin:
# app/components/card_component.rb %>
class CardComponent < ElementalComponents :: Component
...
element :section , multiple : true do
attribute :size
element :header
element :footer
end
endSelain mendeklarasikan atribut dan elemen, juga dimungkinkan untuk menyatakan metode pembantu. Ini berguna jika Anda lebih suka menjaga logika dari templat Anda. Mari kita ekstrak logika pengubah dari template komponen kartu:
# 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 %>Bahkan mungkin untuk menyatakan pembantu pada elemen:
# 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 %> Metode helper juga dapat memanfaatkan variabel instance @view untuk menghubungi pembantu rel seperti link_to atau content_tag .
Untuk beberapa komponen kecil, seperti tombol, mungkin masuk akal untuk melewatkan parsial sama sekali, untuk mempercepat rendering. Ini dapat dilakukan dengan mengesampingkan render pada komponen:
# 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 %> Komponen dapat bersarang di bawah namespace. Ini berguna jika Anda ingin mempraktikkan hal -hal seperti desain atom, Bemit atau skema klasifikasi komponen lainnya. Untuk membuat komponen namespaced, tempelkan di folder dan bungkus kelas dalam modul:
module Objects
class MediaObject < ElementalComponents :: Component ; end
endKemudian panggil dari templat seperti itu:
<%= component "objects/media_object" %> Perpustakaan ini, bersama dengan Elemental_Styleguide, terinspirasi oleh tulisan -tulisan Brad Frost pada desain atom dan pemandu gaya hidup, dan Rizzo, panduan gaya Lonely Planet. Inspirasi lainnya adalah:
Untuk daftar panduan gaya dunia nyata, lihat http://styleguides.io.