链式html标记

时间:2011-06-10 07:43:59

标签: html ruby templates chaining

动机和问题

使用ruby(erb,haml,builder,markaby,tagz,...)生成html标记字符串有几个库,但我对它们中的任何一个都不满意。原因在于,除了erb之外,它们采用的是嵌套方式而不是链式。而erb是一种在rubh中嵌入ruby而不是用ruby生成html的方法。

据我所知,红宝石的一个美妙之处在于鼓励使用链式:

receiver.method1(args1).method2(args2). ... method_n(args_n)

而不是做嵌套风格:

method_n(...method2(method1(receiver, args1), args2), ... args_n)

但上面提到的库(erb除外)采用嵌套样式(有时借助块参数)。

我的想法

为了我自己的目的,我写了一个方法dom,这样我就可以用链式做html标记。应用于字符串时,此示例

"This is a link to SO".dom(:a, href: "http://stackoverflow.com").dom(:body).dom(:html)

将生成:

<html><body><a href="http://stackoverflow.com";>This is a link to SO</a></body></html>

当应用于数组时,这个:

[
  ["a".dom(:td), "b".dom(:td)].dom(:tr),
  ["c".dom(:td), "d".dom(:td)].dom(:tr)
].dom(:table, border: 1)

将生成

<table border="1";>
  <tr>
    <td>"a"</td>
    <td>"b"</td>
  </tr>
  <tr>
    <td>"c"</td>
    <td>"d"</td>
  </tr>
<table>

并且,在没有显式接收器的情况下应用(在字符串和数组域之外),

dom(:img, src: "picture.jpg", width: 48, height: 48)

将生成

<img src="picture.jpg";width="48";height="48";/>

请注意,所有操作都只使用一种方法dom完成。这比使用其他库简单得多。它也很灵活,因为它不受html标签库存变化的影响;你只需用符号参数指定它。在其他库中,每个标签都有类和/或方法。更确切地说,与erb不同,它是纯粹的红宝石。它不是需要转换的DSL。

我的实施

实施如下:

class Hash
    def attribute
        map{|k, v| %Q{#{k}#{
            case v
            when TrueClass; ''
            when Hash;       %Q{="#{v.subattribute}"}
            else             %Q{="#{v}"}
            end
        ;}}}.join
    end
    def subattribute
        map{|k, v| %Q{#{k}:#{v};}}.join
    end
end

class Array
    def dom type, hash = {}
        "<#{type} #{hash.attribute}>\n#{join("\n").gsub(/^/, "  ")}\n</#{type}>"
    end
end

class String
    def dom type, hash = {}
        "<#{type} #{hash.attribute}>#{self}</#{type}>"
    end
end

class Object
    def dom type, hash = {}
        "<#{type} #{hash.attribute}/>"
    end
end

问题

  • 是否有稳定的库可以做类似的事情?
  • 这种方法可能会遇到什么问题(尤其是我的实施或链式方法)?
  • 某些属性采用布尔值,通常鼓励将其省略。例如,<input type="text";readonly>而不是<input type="text";readonly="true">。在我目前的实现中,我可以通过将true(最终不会使用)作为dom(:input, type: "text", readonly: true)这样的属性的值来实现,但这似乎是多余的,也是原因的一部分我在代码中有case语句,使其变慢。有更好的方法吗?
  • 实施方面是否有任何可能的改进?

1 个答案:

答案 0 :(得分:1)

haml和其他大多数嵌套内容的主要原因是,基本上很容易看出你的HTML是如何嵌套的。我假设这个,但你真的编码HTML或你做更多的后端东西?原因在于,在嵌套样式中,您将看到元素是如何嵌套的(如果您还要编写样式,这对您很重要)

虽然写起来比较容易

 .dom(:body).dom(:html)

设计人员很难看到HTML如何在没有映射的情况下流动并尝试在脑中进行可视化,而是:

 %html
   %body

只用一眼看就可以了。

不要再举一个例子:

 "This is a link to SO".dom(:a, href: "http://stackoverflow.com").dom(:body).dom(:html)

如果说客户端或者您需要在链接中添加可点击图像,会更容易吗?你会怎么做的?在haml中它很容易:

 %html
   %body
     %a{:href => "blah"}
       = image_tag("image.png")

另外,恕我直言,为每个html标签写dom(:)就像为它编写结束标签一样繁琐(HAML和其他人固定)

同样,这些只是我对XHTML / CSS程序员的看法(而不是红宝石程序员的观点)

最后,我还认为这可以变成一个社区维基或其他东西,因为这不值得一个确切的答案,并可能产生很多像这样的主观的。