如何使用 Rails 助手:引導輪播演示
已發表: 2022-03-11在所有 Rails 內置結構中,最被濫用、誤解和忽視的一種是視圖助手。 位於你的app/helpers
目錄中,並且在每個新的 Rails 項目中默認生成,幫助程序經常因為成為整個應用程序視圖層中使用的一次性方法的垃圾場而聲名狼藉。 不幸的是,Rails 本身通過默認情況下將所有助手包含到每個視圖中來鼓勵這種缺乏結構和糟糕的組織,從而創建了一個被污染的全局命名空間。
但是,如果您的助手可以更具語義化、組織性更好,甚至可以跨項目重用呢? 如果它們不僅僅是散佈在整個視圖中的一次性函數,而是可以輕鬆生成複雜標記的強大方法,讓您的視圖擺脫條件邏輯和代碼呢?
讓我們看看在構建圖像輪播時如何做到這一點,使用熟悉的 Twitter Bootstrap 框架和一些好的老式面向對象編程。
何時使用 Rails 助手
在 Rails 的視圖層中可以使用許多不同的設計模式:presenters、decorator、partials 以及 helpers,僅舉幾例。 我的簡單經驗法則是,當您想要生成需要特定結構、特定 CSS 類、條件邏輯或跨不同頁面重用的 HTML 標記時,幫助程序非常有用。
展示 Rails 助手功能的最佳示例是FormBuilder
及其用於生成輸入字段、選擇標籤、標籤和其他 HTML 結構的所有相關方法。 這些有用的方法使用正確設置的所有相關屬性為您生成標記。 像這樣的便利性是我們一開始就愛上 Rails 的原因。
使用精心設計的幫助程序的好處與任何編寫良好、乾淨的代碼相同:封裝、減少代碼重複 (DRY) 以及將邏輯排除在視圖之外。
Twitter Bootstrap 輪播的剖析
Twitter Bootstrap 是一個廣泛使用的前端框架,它內置了對常見組件的支持,例如模式、選項卡和圖像輪播。 這些 Bootstrap 組件是自定義助手的一個很好的用例,因為標記是高度結構化的,需要正確設置某些類、ID 和數據屬性才能使 JavaScript 工作,並且設置這些屬性需要一些條件邏輯。
Bootstrap 3 輪播具有以下標記:
<div class="carousel slide" data-ride="carousel"> <!-- Indicators --> <ol class="carousel-indicators"> <li data-target="#carousel-example-generic" data-slide-to="0" class="active"></li> <li data-target="#carousel-example-generic" data-slide-to="1"></li> <li data-target="#carousel-example-generic" data-slide-to="2"></li> </ol> <!-- Wrapper for slides --> <div class="carousel-inner"> <div class="item active"> <img src="..." alt="..."> </div> <div class="item"> <img src="..." alt="..."> </div> ... </div> <!-- Controls --> <a class="left carousel-control" href="#carousel-example-generic" data-slide="prev"> <span class="glyphicon glyphicon-chevron-left"></span> </a> <a class="right carousel-control" href="#carousel-example-generic" data-slide="next"> <span class="glyphicon glyphicon-chevron-right"></span> </a> </div>
如您所見,有三個主要結構:(1)指示器(2)圖像幻燈片(3)滑動控件。
目標是能夠構建一個單獨的輔助方法,該方法獲取一組圖像並呈現整個輪播組件,確保數據、 id
、 href
屬性和 CSS 類都設置正確。
幫手
讓我們從助手的基本輪廓開始:
# app/helpers/carousel_helper.rb module CarouselHelper def carousel_for(images) Carousel.new(self, images).html end class Carousel def initialize(view, images) @view, @images = view, images end def html # TO FILL IN end private attr_accessor :view, :images end end
輔助方法carousel_for
將返回給定圖像 URL 的完整輪播標記。 與其構建一套單獨的方法來渲染輪播的每個部分(這將需要我們將圖像集合和其他狀態信息傳遞給每個方法),我們將創建一個新的普通的舊 Ruby 類,稱為Carousel
以表示輪播數據。 此類將公開一個html
方法,該方法返回完全呈現的標記。 我們使用圖像 URL images
的集合和視圖上下文view
對其進行初始化。
請注意, view
參數是ActionView
的一個實例,所有 Rails 助手都混入其中。 我們將它傳遞給我們的對象實例,以便訪問 Rails 的內置輔助方法,例如link_to
、 content_tag
、 image_tag
和safe_join
,我們將使用它們在類中構建標記。 我們還將添加delegate
宏,因此我們可以直接調用這些方法,而無需引用view
:
def html content = view.safe_join([indicators, slides, controls]) view.content_tag(:div, content, class: 'carousel slide') end private attr_accessor :view, :images delegate :link_to, :content_tag, :image_tag, :safe_join, to: :view def indicators # TO FILL IN end def slides # TO FILL IN end def controls # TO FILL IN end
我們知道輪播由三個獨立的組件組成,所以讓我們將最終為每個組件提供標記的方法存根,然後讓html
方法將它們連接到容器div
標記中,為輪播本身應用必要的 Bootstrap 類。
safe_join
是一種方便的內置方法,它將字符串集合連接在一起並在結果上調用html_safe
。 請記住,我們可以通過創建實例時傳入的view
參數訪問這些方法。
我們將首先構建指標:
def indicators items = images.count.times.map { |index| indicator_tag(index) } content_tag(:ol, safe_join(items), class: 'carousel-indicators') end def indicator_tag(index) options = { class: (index.zero? ? 'active' : ''), data: { target: uid, slide_to: index } } content_tag(:li, '', options) end
指示符是一個簡單的有序列表ol
,其中集合中的每個圖像都有一個列表項li
元素。 當前活動的圖像指示器需要active
的 CSS 類,因此我們將確保為我們創建的第一個指示器設置它。 這是一個很好的邏輯示例,通常必須在視圖本身中。

請注意,指標需要引用包含輪播元素的唯一id
(如果頁面上有多個輪播)。 我們可以在初始化程序中輕鬆生成此id
,並在整個類的其餘部分(特別是在指標和控件中)使用它。 在輔助方法中以編程方式執行此操作可確保id
在輪播元素之間保持一致。 很多時候,一個小錯字或在一個地方更改id
而不是其他地方會導致輪播中斷; 這不會在這裡發生,因為所有元素都會自動引用相同的id
。
def initialize(view, images) # ... @uid = SecureRandom.hex(6) end attr_accessor :uid
接下來是圖片幻燈片:
def slides items = images.map.with_index { |image, index| slide_tag(image, index.zero?) } content_tag(:div, safe_join(items), class: 'carousel-inner') end def slide_tag(image, is_active) options = { class: (is_active ? 'item active' : 'item'), } content_tag(:div, image_tag(image), options) end
我們簡單地遍歷傳遞給Carousel
實例的每個圖像並創建正確的標記:使用item
CSS 類包裝在div
中的圖像標籤,再次確保將active
類添加到我們創建的第一個類中。
最後,我們需要上一個/下一個控件:
def controls safe_join([control_tag('left'), control_tag('right')]) end def control_tag(direction) options = { class: "#{direction} carousel-control", data: { slide: direction == 'left' ? 'prev' : 'next' } } icon = content_tag(:i, nil, class: "glyphicon glyphicon-chevron-#{direction}") control = link_to(icon, "##{uid}", options) end
我們創建控制輪播在圖像之間來回移動的鏈接。 再次注意uid
的使用; 無需擔心在輪播結構中的所有不同位置都沒有使用正確的 ID,它會自動保持一致且唯一。
成品:
至此,我們的輪播助手就完成了。 這是它的全部內容:
# app/helpers/carousel_helper.rb module CarouselHelper def carousel_for(images) Carousel.new(self, images).html end class Carousel def initialize(view, images) @view, @images = view, images @uid = SecureRandom.hex(6) end def html content = safe_join([indicators, slides, controls]) content_tag(:div, content, id: uid, class: 'carousel slide') end private attr_accessor :view, :images, :uid delegate :link_to, :content_tag, :image_tag, :safe_join, to: :view def indicators items = images.count.times.map { |index| indicator_tag(index) } content_tag(:ol, safe_join(items), class: 'carousel-indicators') end def indicator_tag(index) options = { class: (index.zero? ? 'active' : ''), data: { target: uid, slide_to: index } } content_tag(:li, '', options) end def slides items = images.map.with_index { |image, index| slide_tag(image, index.zero?) } content_tag(:div, safe_join(items), class: 'carousel-inner') end def slide_tag(image, is_active) options = { class: (is_active ? 'item active' : 'item'), } content_tag(:div, image_tag(image), options) end def controls safe_join([control_tag('left'), control_tag('right')]) end def control_tag(direction) options = { class: "#{direction} carousel-control", data: { slide: direction == 'left' ? 'prev' : 'next' } } icon = content_tag(:i, '', class: "glyphicon glyphicon-chevron-#{direction}") control = link_to(icon, "##{uid}", options) end end end
幫手在行動:
最後,為了強調重點,讓我們看一個簡單的例子,說明這個助手如何讓我們的生活更輕鬆。 假設我們正在建立一個出租公寓列表的網站。 每個Apartment
對像都有一個圖像 URL 列表:
class Apartment def image_urls # ... end end
使用我們的 carousel 助手,我們可以通過一次調用carousel_for
來渲染整個 Bootstrap 輪播,從視圖中完全移除相當複雜的邏輯:
<% apartment = Apartment.new %> # ... <%= carousel_for(apartment.image_urls) %>
不確定何時使用 Rails 視圖助手? 這是一個演示。
鳴叫
結論
使用這種簡單但功能強大的技術,我們將大量標記和邏輯從視圖層移到了一個輔助函數中,該函數可用於在任何地方渲染輪播組件,只需調用carousel_for(some_images)
. 每當您使用 Twitter Bootstrap 時,都可以在所有 Rails 項目中使用這個通用助手。 最重要的是,您的工具包中現在有了一個新工具,您也可以將它用於特定於項目的組件。
因此,下次當您發現自己鍵入和重新鍵入相同類型的標記並將條件邏輯嵌入到您的視圖中時,請查看輔助函數是否正在等待編寫以使您的生活更輕鬆。