مكونات عرض بسيطة لـ 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
*/هناك طريقتان لتمرير البيانات إلى المكونات: السمات وكتل المحتوى. السمات مفيدة للبيانات مثل المعرفات والمعدلات وهياكل البيانات (النماذج وما إلى ذلك). تعتبر كتل المحتوى مفيدة عندما تحتاج إلى ضخ محتوى 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 في مكوننا ، يمكننا طباعة طريقة .Content Component في القالب الخاص بنا ، وملءها عن طريق تمرير كتلة المحتوى إلى المساعد المكون:
<% # 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 من أجل استدعاء مساعدي Rails مثل 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 ، The Lonely Planet Guide. وكانت الإلهام الأخرى:
للحصول على قائمة من أدلة نمط العالم الحقيقي ، تحقق من http://styleguides.io.