如何使用Rails助手:Bootstrap轮播演示

本文概述

视图助手是所有Rails内置结构中最被滥用, 误解和忽视的一种。位于你的app / helpers目录中, 默认情况下, 每个新的Rails项目都会生成该帮助程序, 而这些帮助程序通常是整个应用程序视图层中使用的一次性方法的垃圾场, 因此通常会因此而臭名昭著。不幸的是, Rails本身通过在默认情况下将所有帮助器都包含在每个视图中来创建这种污染的全局命名空间, 从而鼓励了这种结构的缺乏和组织不善。

但是, 如果你的助手可以在项目中更具语义, 更好地组织甚至可重用, 该怎么办?如果它们不只是遍及整个视图的一次性功能, 而是强大的方法可以轻松生成复杂的标记, 而使视图不受条件逻辑和代码的影响, 该怎么办?

让我们看看如何使用熟悉的Twitter Bootstrap框架和一些良好的老式面向对象编程来构建图像轮播时执行此操作。

Rails助手应该提供有用的结构。

何时使用Rails助手

在Rails的视图层中可以使用许多不同的设计模式:演示者, 装饰者, 局部对象以及助手, 仅举几例。我的简单经验法则是, 当你想要生成需要特定结构, 特定CSS类, 条件逻辑或在不同页面之间重用的HTML标记时, 帮助程序会非常有用。

FormBuilder及其所有用于生成输入字段, 选择标签, 标签和其他HTML结构的方法都展示了Rails助手功能的最佳例子。这些有用的方法会通过正确设置所有相关属性为你生成标记。如此便利的原因是我们所有人一开始就爱上Rails的原因。

使用精心设计的帮助程序的好处与任何编写良好的简洁代码相同:封装, 减少代码重复(DRY)以及将逻辑置于视图之外。

使用Rails助手来构建复杂的标记

Twitter Bootstrap Carousel的剖析

Twitter Bootstrap是一个广泛使用的前端框架, 它内置了对常见组件(如模式, 选项卡和图像轮播)的支持。这些Bootstrap组件对于自定义助手是一个很好的用例, 因为标记具有高度的结构, 需要正确设置某些类, ID和数据属性以使JavaScript起作用, 而设置这些属性需要一些条件逻辑。

Bootstrap 3轮播具有以下标记:

<div id="carousel-example-generic" 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)幻灯片控件。

Bootstrap传送带的零件。

目标是能够构建一个单独的帮助器方法, 该方法将收集图像并呈现整个轮播组件, 从而确保正确设置数据, 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的完整轮播标记。与其构建一套单独的方法来渲染轮播的每个部分(这需要我们将图像集合和其他有状态信息传递给每种方法), 我们将创建一个名为Carousel的新的普通旧式Ruby类, 用于代表轮播数据。此类将公开一个html方法, 该方法返回完全呈现的标记。我们使用图像URL图像的集合以及视图上下文视图对其进行初始化。

请注意, view参数是ActionView的实例, 所有Rails帮助器都混入其中。我们将其传递给对象实例, 以访问Rails的内置帮助器方法, 例如link_to, content_tag, image_tag和safe_join, 我们将使用它们在类中构建标记。我们还将添加委托宏, 因此我们可以直接调用这些方法, 而无需引用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元素。当前处于活动状态的图像指示器需要处于活动状态的CSS类, 因此, 请确保为我们创建的第一个指示器设置了它。这是逻辑的一个很好的例子, 通常必须在视图本身中。

请注意, 指示器需要引用包含轮播元素的唯一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实例的每个图像, 并创建适当的标记:一个图像标签, 包装在带有CSS类CSS的div中, 再次确保将活动类添加到我们创建的第一个图像中。

最后, 我们需要上一个/下一个控件:

    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_for来呈现整个Bootstrap轮播, 从而从视图中完全删除相当复杂的逻辑:

<% apartment = Apartment.new %>
# ...
<%= carousel_for(apartment.image_urls) %>

不确定何时使用Rails视图助手?这是一个示范。

鸣叫

总结

使用这种简单但功能强大的技术, 我们将大量的标记和逻辑移出了视图层, 并移入了一个辅助函数, 该函数可通过carousel_for(some_images)调用在任何地方渲染轮播组件。每当你使用Twitter Bootstrap时, 都可以在你的所有Rails项目中使用该通用帮助程序。最重要的是, 你的工具箱中现在有了一个新工具, 也可以将其用于特定于项目的组件。

因此, 下次你发现自己键入相同类型的标记并重新键入它们, 并将条件逻辑嵌入视图中时, 请查看是否正在等待编写辅助函数以使你的生活更轻松。

微信公众号
手机浏览(小程序)
0
分享到:
没有账号? 忘记密码?