Haml (HTML 抽象标记语言)

Haml 是一种标记语言,用于简洁明了地描述任何网页文档的 HTML,无需使用内联代码。Haml 作为内联页面模板系统(如 PHP、ERB 和 ASP)的替代方案。但是,Haml 避免了在模板中显式编码 HTML 的需要,因为它实际上是 HTML 的抽象描述,带有一些用于生成动态内容的代码。

特性

  • 空白符有效
  • 格式良好的标记
  • DRY
  • 遵循 CSS 约定
  • 集成 Ruby 代码
  • 使用 .haml 扩展名实现 Rails 模板

使用 Haml

Haml 可以通过三种方式使用

  • 作为命令行工具,
  • 作为 Ruby on Rails 的插件,
  • 以及作为独立的 Ruby 模块。

所有这些的第一步是安装 Haml gem

gem install haml

要从命令行运行 Haml,只需使用

haml render input.haml > output.html

使用 haml --help 获取完整文档。

要将 Haml 与 Rails 一起使用,请在 Gemfile 中添加以下行

gem "haml"

安装后,所有扩展名为 ".html.haml" 的视图文件都将使用 Haml 编译。

您可以在 Haml 模板中以与在 ERB 模板中相同的方式访问实例变量。辅助方法也适用于 Haml 模板。例如

# file: app/controllers/movies_controller.rb

class MoviesController < ApplicationController
  def index
    @title = "Teen Wolf"
  end
end

-# file: app/views/movies/index.html.haml

#content
 .title
   %h1= @title
   = link_to 'Home', home_url

可以编译为

<div id='content'>
  <div class='title'>
    <h1>Teen Wolf</h1>
    <a href='/'>Home</a>
  </div>
</div>

Ruby 模块

Haml 也可以完全独立于 Rails 和 ActionView 使用。为此,请使用 RubyGems 安装 gem

gem install haml

然后,您可以通过在 Ruby 代码中包含 haml gem 并使用 Haml::Template 来使用它,如下所示

engine = Haml::Template.new { "%p Haml code!" }
engine.render #=> "<p>Haml code!</p>\n"

选项

Haml 理解各种配置选项,这些选项会影响其性能和输出。

在 Rails 中,可以通过在初始化程序中使用 Haml::RailsTemplate.set_options 来设置选项

ruby # config/initializers/haml.rb Haml::RailsTemplate.set_options(escape_html: false)

在 Rails 之外,您可以通过在 Haml::Template.options 中全局配置它们来设置它们

ruby Haml::Template.options[:escape_html] = false

特别是在 sinatra 中,您可以在全局配置中使用以下方式设置它们:ruby set :haml, { escape_html: false }

最后,您还可以通过将选项哈希传递给 Haml::Engine.newHaml::Template.new 来设置它们。有关可用选项的完整列表,请参阅 Haml::Engine

纯文本

任何 HTML 文档的很大一部分是其内容,即纯文本。任何不被解释为其他内容的 Haml 行都被视为纯文本,并直接传递。例如

%gee
  %whiz
    Wow this is cool!

编译成

<gee>
  <whiz>
    Wow this is cool!
  </whiz>
</gee>

请注意,HTML 标签也会直接传递。如果您有一些不想转换为 Haml 的 HTML,或者您正在逐行转换文件,您可以直接包含它。例如

%p
  <div id="blah">Blah!</div>

编译成

<p>
  <div id="blah">Blah!</div>
</p>

转义:\

反斜杠字符转义了行的第一个字符,允许将原本被解释的字符用作纯文本。例如

%title
  = @title
  \= @title

编译成

<title>
  MyPage
  = @title
</title>

HTML 元素

元素名称:%

百分号字符放在行的开头。它后面紧跟着元素的名称,然后可选地跟着修饰符(见下文)、一个空格,以及要在元素内渲染的文本。它创建了一个形式为<element></element>的元素。例如

%one
  %two
    %three Hey there

编译成

<one>
  <two>
    <three>Hey there</three>
  </two>
</one>

任何字符串都是有效的元素名称;Haml 将自动为任何元素生成开始和结束标签。

属性:{}()

大括号表示一个 Ruby 哈希,用于指定元素的属性。它实际上被评估为一个 Ruby 哈希,因此逻辑将在其中起作用,并且可以使用局部变量。属性中的引号字符将被替换为适当的转义序列。哈希放在定义标签之后。例如

%html{:xmlns => "http://www.w3.org/1999/xhtml", "xml:lang" => "en", :lang => "en"}

编译成

<html xmlns='http://www.w3.org/1999/xhtml' xml:lang='en' lang='en'></html>

属性哈希也可以扩展到多行以容纳许多属性。

%script{
  "type": text/javascript",
  "src": javascripts/script_#{2 + 7}",
  "data": {
    "controller": "reporter",
  },
}

编译成

<script src='javascripts/script_9' type='text/javascript' data-controller='reporter'></script>

:class:id 属性

:class:id 属性也可以指定为一个 Ruby 数组,其元素将被连接在一起。一个 :class 数组用 " " 连接,一个 :id 数组用 "_" 连接。例如

%div{:id => [@item.type, @item.number], :class => [@item.type, @item.urgency]}

等同于

%div{:id => "#{@item.type}_#{@item.number}", :class => "#{@item.type} #{@item.urgency}"}

数组将首先被扁平化,任何不测试为真的元素将被删除。剩余的元素将被转换为字符串。例如

%div{:class => [@item.type, @item == @sortcol && [:sort, @sortdir]] } Contents

可以渲染为以下任何一种

<div class="numeric sort ascending">Contents</div>
<div class="numeric">Contents</div>
<div class="sort descending">Contents</div>
<div>Contents</div>

取决于 @item.type 是否为 "numeric"nil@item 是否等于 @sortcol,以及 @sortdir 是否为 "ascending""descending"

如果指定单个值并且它评估为 false,则它将被忽略;否则它将被转换为字符串。例如

.item{:class => @item.is_empty? && "empty"}

可以渲染成以下两种形式:

class="item"
class="item empty"

HTML 风格属性:()

Haml 还支持一种更简洁、更少 Ruby 特定的属性语法,它基于 HTML 的属性。这些属性使用圆括号而不是花括号,如下所示

%html(xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en")

可以通过省略引号来使用 Ruby 变量。可以使用局部变量或实例变量。例如

%a(title=@title href=href) Stuff

这与以下代码相同:

%a{:title => @title, :href => href} Stuff

但是,由于没有逗号分隔属性,因此不允许使用更复杂的表达式。对于这些表达式,您必须使用 {} 语法。但是,您可以将两种语法一起使用

%a(title=@title){:href => @link.href} Stuff

您也可以使用 #{} 插值在 HTML 风格属性中插入复杂的表达式

%span(class="widget_#{@widget.number}")

HTML 风格属性可以像哈希风格属性一样跨多行扩展

%script(type="text/javascript"
        src="javascripts/script_#{2 + 7}")

Ruby 1.9 风格的哈希

Haml 还支持 Ruby 的新哈希语法

%a{title: @title, href: href} Stuff

布尔属性

某些属性,例如 input 标签的“checked”或 option 标签的“selected”,在某种意义上是“布尔”的,因为它们的实际值并不重要,重要的是它们是否存在。在 HTML(但不是 XHTML)中,这些属性可以写成

<input selected>

要在 Haml 中使用哈希风格属性执行此操作,只需将 Ruby true 值分配给该属性

%input{:selected => true}

在 XHTML 中,这些属性的唯一有效值为属性名称。因此,这将在 XHTML 中渲染为

<input selected='selected'>

要将这些属性设置为 false,只需将它们分配给 Ruby false 值。在 XHTML 和 HTML 中,

%input{:selected => false}

将只渲染为

<input>

HTML 风格的布尔属性可以像 HTML 一样编写

%input(selected)

或使用 truefalse

%input(selected=true)

此功能仅适用于包含在 Haml::AttributeBuilder::BOOLEAN_ATTRIBUTES 中的属性,以及 data-aria- 属性。

%input{'data-hidden' => false}
%input{'aria-hidden' => false}
%input{'xyz-hidden' => false}

将渲染为

<input>
<input>
<input xyz-hidden='false'>

数据属性

HTML5 允许使用以 data- 开头的属性名称将 自定义不可见数据属性 添加到元素。 可访问的富互联网应用程序 规范使用以 aria- 开头的属性。

Haml 可以帮助生成具有相同前缀的属性集合,例如这些。dataaria 属性哈希中任何具有哈希值作为其值的条目都会扩展为一系列属性,每个键值对在哈希中对应一个属性,属性名称通过将“父”键名与键名连接起来形成,中间用连字符隔开。这仅适用于 dataaria

例如

%a{:href=>"/posts", :data => {:author_id => 123, :category => 7}} Posts By Author

将渲染为

<a data-author-id='123' data-category='7' href='/posts'>Posts By Author</a>

注意,author_id 中的下划线被替换为连字符。如果您希望抑制此行为,可以将 Haml 的 :hyphenate_data_attrs 选项设置为 false,输出将呈现为

<a data-author_id='123' data-category='7' href='/posts'>Posts By Author</a>

哈希的这种扩展是递归的 - 子哈希的任何值为哈希本身都会为每个条目创建一个属性,属性名称以所有祖先键为前缀。例如

.book-info{:data => {:book => {:id => 123, :genre => 'programming'}, :category => 7}}

将渲染为

<div class='book-info' data-book-genre='programming' data-book-id='123' data-category='7'></div>

类和 ID:.#

句点和井号借鉴自 CSS。它们用作分别指定元素的 classid 属性的快捷方式。多个类名可以以类似于 CSS 的方式指定,通过将类名用句点连接在一起。它们放置在标签之后和属性哈希之前。例如

%div#things
  %span#rice Chicken Fried
  %p.beans{ :food => 'true' } The magical fruit
  %h1.class.otherclass#id La La La

编译成

<div id='things'>
  <span id='rice'>Chicken Fried</span>
  <p class='beans' food='true'>The magical fruit</p>
  <h1 class='class otherclass' id='id'>La La La</h1>
</div>

以及,

%div#content
  %div.articles
    %div.article.title Doogie Howser Comes Out
    %div.article.date 2006-11-05
    %div.article.entry
      Neil Patrick Harris would like to dispel any rumors that he is straight

编译成

<div id='content'>
  <div class='articles'>
    <div class='article title'>Doogie Howser Comes Out</div>
    <div class='article date'>2006-11-05</div>
    <div class='article entry'>
      Neil Patrick Harris would like to dispel any rumors that he is straight
    </div>
  </div>
</div>

这些快捷方式可以与长格式属性结合使用;这两个值将合并在一起,就像它们都放在数组中一样(参见 关于 :class:id 属性的文档)。例如

%div#Article.article.entry{:id => @article.number, :class => @article.visibility}

等同于

%div{:id => ['Article', @article.number], :class => ['article', 'entry', @article.visibility]} Gabba Hey

并可能编译为

<div class="article entry visible" id="Article_27">Gabba Hey</div>

隐式 Div 元素

由于 div 的使用非常频繁,因此它们是默认元素。如果您只使用 .# 定义类和/或 id,则会自动使用 div。例如

#collection
  .item
    .description What a cool item!

%div#collection
  %div.item
    %div.description What a cool item!

相同,并编译为

<div id='collection'>
  <div class='item'>
    <div class='description'>What a cool item!</div>
  </div>
</div>

类名合并和排序

类名按以下方式排序

1) 标签标识符按顺序(即,“.alert.me” => “alert me”) 2) 出现在 HTML 样式属性中的类 3) 出现在哈希样式属性中的类

例如,这是一个复杂的、不直观的测试用例,说明了排序

.foo.moo{:class => ['bar', 'alpha']}(class='baz')

生成的 HTML 如下所示

<div class='foo moo baz bar alpha'></div>

5.0 之前的 Haml 版本会按字母顺序排序类名。

空(void)标签:/

在标签定义的末尾放置正斜杠字符,会导致 Haml 将其视为空(或 void)元素。根据格式,标签将以不带结束标签的方式呈现(:html4:html5),或以自闭合标签的方式呈现(:xhtml)。

以下示例

%br/
%meta{'http-equiv' => 'Content-Type', :content => 'text/html'}/

当格式为 :html4:html5 时,编译为

<br>
<meta content='text/html' http-equiv='Content-Type'>

当格式为 :xhtml 时,编译为

<br />
<meta content='text/html' http-equiv='Content-Type' />

某些标签会自动被视为空标签,只要它们在 Haml 源代码中没有内容。metaimglinkbrhrinputareaparamcolbase 标签默认被视为空标签。此列表可以通过设置 :autoclose 选项进行自定义。

空白符移除:><

>< 可以让你更好地控制标签附近的空白符。> 会移除标签周围的所有空白符,而 < 会移除标签内部的所有空白符。你可以将它们想象成吃掉空白符的鳄鱼:> 面向标签外部,吃掉外部的空白符,而 < 面向标签内部,吃掉内部的空白符。它们放在标签定义的末尾,在类、id 和属性声明之后,但在 /= 之前。例如

%blockquote<
  %div
    Foo!

编译成

<blockquote><div>
  Foo!
</div></blockquote>

以及

%img
%img>
%img

编译成

<img /><img /><img />

以及

%p<= "Foo\nBar"

编译成

<p>Foo
Bar</p>

最后

%img
%pre><
  foo
  bar
%img

编译成

<img /><pre>foo
bar</pre><img />

对象引用:[]

方括号紧跟在标签定义之后,包含一个用于设置该标签的类和 id 的 Ruby 对象。类被设置为对象的类(转换为使用下划线而不是驼峰式命名法),id 被设置为对象的类,后面跟着其 #to_key#id 方法的值(按此顺序)。这对表示 Active Model 模型实例的元素最有用。此外,第二个参数(如果存在)将用作 id 和类属性的前缀。例如

# file: app/controllers/users_controller.rb

def show
  @user = CrazyUser.find(15)
end

-# file: app/views/users/show.haml

%div[@user, :greeting]
  %bar[290]/
  Hello!

编译成

<div class='greeting_crazy_user' id='greeting_crazy_user_15'>
  <bar class='fixnum' id='fixnum_581' />
  Hello!
</div>

如果你需要将类设置为除下划线形式的对象类以外的其他值,可以在对象上实现 haml_object_ref 方法。

# file: app/models/crazy_user.rb

class CrazyUser < ActiveRecord::Base
  def haml_object_ref
    "a_crazy_user"
  end
end

-# file: app/views/users/show.haml

%div[@user]
  Hello!

编译成

<div class='a_crazy_user' id='a_crazy_user_15'>
  Hello!
</div>

:class 属性可以与对象引用一起使用。编译后的元素将包含所有类的并集。

- user = User.find(1)
%p[user]{:class => 'alpha bravo'}
<p id="user_1" class="alpha bravo user"></p>

文档类型:!!!

使用 Haml 描述 HTML 文档时,可以通过包含字符 !!! 来自动生成文档类型或 XML 前言。例如

!!! XML
!!!
%html
  %head
    %title Myspace
  %body
    %h1 I am the international space station
    %p Sign my guestbook

编译成

<?xml version='1.0' encoding='utf-8' ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
  <head>
    <title>Myspace</title>
  </head>
  <body>
    <h1>I am the international space station</h1>
    <p>Sign my guestbook</p>
  </body>
</html>

:format 设置为 :xhtml 时,您也可以在 !!! 后指定特定的文档类型。支持以下文档类型

!!!
XHTML 1.0 Transitional
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
!!! Strict
XHTML 1.0 Strict
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
!!! Frameset
XHTML 1.0 Frameset
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd">
!!! 5
XHTML 5
<!DOCTYPE html>
!!! 1.1
XHTML 1.1
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
!!! Basic
XHTML Basic 1.1
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML Basic 1.1//EN" "http://www.w3.org/TR/xhtml-basic/xhtml-basic11.dtd">
!!! Mobile
XHTML Mobile 1.2
<!DOCTYPE html PUBLIC "-//WAPFORUM//DTD XHTML Mobile 1.2//EN" "http://www.openmobilealliance.org/tech/DTD/xhtml-mobile12.dtd">
!!! RDFa
XHTML+RDFa 1.0
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML+RDFa 1.0//EN" "http://www.w3.org/MarkUp/DTD/xhtml-rdfa-1.dtd">

:format 选项设置为 :html4 时,支持以下文档类型

!!!
HTML 4.01 Transitional
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
!!! Strict
HTML 4.01 Strict
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
!!! Frameset
HTML 4.01 Frameset
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Frameset//EN" "http://www.w3.org/TR/html4/frameset.dtd">

:format 选项设置为 :html5 时,!!! 始终为 <!DOCTYPE html>

如果您没有为文档使用 UTF-8 字符集,则可以以类似的方式指定 XML 前言中应出现的编码。例如

!!! XML iso-8859-1

编译成

<?xml version='1.0' encoding='iso-8859-1' ?>

如果正在渲染的模板的 mime_type 为 text/xml,则即使全局输出格式设置为 :html4:html5,也会使用 :xhtml 格式。

注释

Haml 支持两种类型的注释:显示在 HTML 输出中的注释和不显示的注释。

HTML 注释:/

当正斜杠字符放在行首时,它会将它之后的所有文本包装在 HTML 注释中。例如

%peanutbutterjelly
  / This is the peanutbutterjelly element
  I like sandwiches!

编译成

<peanutbutterjelly>
  <!-- This is the peanutbutterjelly element -->
  I like sandwiches!
</peanutbutterjelly>

正斜杠也可以用来包裹缩进的代码段。例如

/
  %p This doesn't render...
  %div
    %h1 Because it's commented out!

编译成

<!--
  <p>This doesn't render...</p>
  <div>
    <h1>Because it's commented out!</h1>
  </div>
-->

条件注释:/[]

您也可以使用 Internet Explorer 条件注释,方法是在 / 后面的方括号中包含条件。例如

/[if IE]
  %a{ :href => 'http://www.mozilla.com/en-US/firefox/' }
    %h1 Get Firefox

编译成

<!--[if IE]>
  <a href='http://www.mozilla.com/en-US/firefox/'>
    <h1>Get Firefox</h1>
  </a>
<![endif]-->

要生成“向下级显示”条件注释,其中内容对 IE 隐藏,但对其他浏览器不隐藏,请在方括号之前添加 !/![]。Haml 在生成此类条件注释时将生成有效的 HTML。

例如

/![if !IE]
  You are not using Internet Explorer, or are using version 10+.

编译成

<!--[if !IE]><!-->
  You are not using Internet Explorer, or are using version 10+.
<!--<![endif]-->

Haml 注释:-#

连字符后紧跟井号表示静默注释。此后的任何文本都不会在生成的文档中呈现。

例如

%p foo
-# This is a comment
%p bar

编译成

<p>foo</p>
<p>bar</p>

您也可以在静默注释下方嵌套文本。所有这些文本都不会被渲染。例如

%p foo
-#
  This won't be displayed
    Nor will this
                   Nor will this.
%p bar

编译成

<p>foo</p>
<p>bar</p>

Ruby 评估

插入 Ruby:=

等号后跟 Ruby 代码。此代码将被评估,输出将插入文档中。例如

%p
  = ['hi', 'there', 'reader!'].join " "
  = "yo"

编译成

<p>
  hi there reader!
  yo
</p>

如果设置了 :escape_html 选项,= 将对脚本生成的任何 HTML 敏感字符进行清理。例如

= '<script>alert("I\'m evil!");</script>'

将编译为

&lt;script&gt;alert(&quot;I'm evil!&quot;);&lt;/script&gt;

= 也可以用在标签的末尾,以在该标签内插入 Ruby 代码。例如

%p= "hello"

将编译为

<p>hello</p>

只要除了最后一行之外的每一行都以逗号结尾,Ruby 代码行就可以跨越多行。例如

= link_to_remote "Add to cart",
    :url => { :action => "add", :id => product.id },
    :update => { :success => "cart", :failure => "error" }

请注意,在以 = 结尾的标签内嵌套代码是非法的。

运行 Ruby:-

连字符后也跟 Ruby 代码。此代码将被评估,但不会插入文档中。

不建议您广泛使用此功能;几乎所有处理代码和逻辑都应限制在控制器、助手或局部视图中。

例如

- foo = "hello"
- foo << " there"
- foo << " you!"
%p= foo

编译成

<p>
  hello there you!
</p>

只要除了最后一行之外的每一行都以逗号结尾,Ruby 代码行就可以跨越多行。例如

- links = {:home => "/",
    :docs => "/docs",
    :about => "/about"}

Ruby 块

Ruby 块与 XHTML 标签一样,不需要在 Haml 中显式关闭。相反,它们会根据缩进自动关闭。只要在 Ruby 评估命令之后缩进增加,块就会开始。当缩进减少时,块就会结束(只要它不是 else 子句或类似内容)。例如

- (42...47).each do |i|
  %p= i
%p See, I can count!

编译成

<p>42</p>
<p>43</p>
<p>44</p>
<p>45</p>
<p>46</p>
<p>See, I can count!</p>

另一个例子

%p
  - case 2
  - when 1
    = "1!"
  - when 2
    = "2?"
  - when 3
    = "3."

编译成

<p>
  2?
</p>

保留空格:~

~ 的工作方式与 = 相同,只是它对输入运行 Haml::Helpers.preserve。例如,

~ "Foo\n<pre>Bar\nBaz</pre>"

= find_and_preserve("Foo\n<pre>Bar\nBaz</pre>")

相同,并编译为

Foo
<pre>Bar&#x000A;Baz</pre>

另请参见 保留空格

Ruby 插值:#{}

Ruby 代码也可以使用 #{} 在纯文本中进行插值,类似于 Ruby 字符串插值。例如,

%p This is #{h quality} cake!

%p= "This is #{h quality} cake!"

并可能编译为

<p>This is scrumptious cake!</p>

可以使用反斜杠来转义 #{} 字符串,但它们在字符串中的其他任何地方都不会充当转义符。例如

%p
  Look at \\#{h word} lack of backslash: \#{foo}
  And yon presence thereof: \{foo}

可能编译成

<p>
  Look at \yon lack of backslash: #{foo}
  And yon presence thereof: \{foo}
</p>

插值也可以在 过滤器 中使用。例如

:javascript
  $(document).ready(function() {
    alert(#{@message.to_json});
  });

可能编译成

<script type='text/javascript'>
  //<![CDATA[
    $(document).ready(function() {
      alert("Hi there!");
    });
  //]]>
</script>

注意事项

Haml 使用一个过于简单的正则表达式来识别字符串插值,而不是一个完整的 Ruby 解析器。这很快,并且适用于大多数代码,但你可能会在以下代码中遇到错误

%span #{'{'}

这段代码将生成语法错误,抱怨括号不平衡。在这种情况下,推荐的解决方法是将代码作为 Ruby 字符串输出,以强制 Haml 使用 Ruby 解析代码。

%span= "#{'{'}"

转义 HTML:&=

一个与号后面跟着一个或两个等号,就像没有与号的等号一样,会评估 Ruby 代码,但会对代码结果中任何对 HTML 敏感的字符进行清理。例如

&= "I like cheese & crackers"

编译成

I like cheese &amp; crackers

如果设置了 :escape_html 选项,&= 的行为与 = 相同。

& 也可以单独使用,以便对 #{} 插值进行转义。例如,

& I like #{"cheese & crackers"}

编译成

I like cheese &amp; crackers

取消转义 HTML:!=

一个感叹号后面跟着一个或两个等号,就像等号一样,会评估 Ruby 代码,但永远不会对 HTML 进行清理。

默认情况下,单个等号也不会对 HTML 进行清理。但是,如果设置了 :escape_html 选项,= 将清理 HTML,但 != 仍然不会。例如,如果设置了 :escape_html

= "I feel <strong>!"
!= "I feel <strong>!"

编译成

I feel &lt;strong&gt;!
I feel <strong>!

! 也可以单独使用,以便对 #{} 插值进行取消转义。例如,

! I feel #{"<strong>"}!

编译成

I feel <strong>!

过滤器

冒号字符表示一个过滤器。这允许你将一个缩进的文本块作为输入传递给另一个过滤程序,并将结果添加到 Haml 的输出中。语法很简单,就是一个冒号后面跟着过滤器的名称。例如

%p
  :markdown
    # Greetings

    Hello, *World*

编译成

<p>
  <h1>Greetings</h1>

  <p>Hello, <em>World</em></p>
</p>

过滤器可以使用 #{} 对 Ruby 代码进行插值。例如

- flavor = "raspberry"
#content
  :textile
    I *really* prefer _#{flavor}_ jam.

编译成

<div id='content'>
  <p>I <strong>really</strong> prefer <em>raspberry</em> jam.</p>
</div>

一些过滤器的功能,例如 Markdown,可以由许多不同的库提供。通常你不需要担心这个问题 - 你只需加载你选择的 gem,Haml 就会自动使用它。

但是,在某些情况下,你可能希望 Haml 明确使用一个特定的 gem 来被过滤器使用。在这种情况下,你可以通过 Tilt 来实现,Tilt 是 Haml 用于实现其许多过滤器的库

Tilt.prefer Tilt::RedCarpetTemplate

有关更多信息,请参阅 Tilt 文档

Haml 附带了以下定义的过滤器

:cdata

用 CDATA 标签包围过滤后的文本。

:coffee

使用 CoffeeScript 将过滤后的文本编译成 JavaScript,并放在 <script> 标签中。你也可以将此过滤器引用为 :coffeescript。此过滤器使用 Tilt 实现。

:css

将过滤后的文本用 `<style>` 标签(可选)和 CDATA 标签包围。这对于包含内联 CSS 很有用。使用 `:cdata` 选项控制何时添加 CDATA 标签。

:erb

使用 ERB 解析过滤后的文本,就像 RHTML 模板一样。如果 `:suppress_eval` 选项设置为 true,则不可用。嵌入的 Ruby 代码在与 Haml 模板相同的上下文中进行评估。此过滤器使用 Tilt 实现。

:escaped

与 plain 相同,但在将文本放入文档之前对其进行 HTML 转义。

:javascript

将过滤后的文本用 `<script>` 标签(可选)和 CDATA 标签包围。这对于包含内联 Javascript 很有用。使用 `:cdata` 选项控制何时添加 CDATA 标签。

:less

使用 Less 解析过滤后的文本,以在 `<style>` 标签中生成 CSS 输出。此过滤器使用 Tilt 实现。

:markdown

使用 Markdown 解析过滤后的文本。此过滤器使用 Tilt 实现。

:maruku

使用 Maruku 解析过滤后的文本,它对 Markdown 有一些非标准扩展。

从 Haml 4.0 开始,此过滤器在 Haml contrib 中定义,但出于历史原因会自动加载。在 Haml 的未来版本中,它可能不会默认加载。此过滤器使用 Tilt 实现。

:plain

不解析过滤后的文本。这对于没有 HTML 标签的大块文本很有用,当您不希望以 `.` 或 `-` 开头的行被解析时。

:preserve

将过滤后的文本插入模板中,保留空格。`preserve` 的文本块不会缩进,换行符将被替换为换行符的 HTML 转义代码,以保留美观的输出。另请参见 空格保留

:ruby

使用正常的 Ruby 解释器解析过滤后的文本。Ruby 代码在与 Haml 模板相同的上下文中进行评估。

:sass

使用 Sass 解析过滤后的文本,以在 `<style>` 标签中生成 CSS 输出。此过滤器使用 Tilt 实现。

:scss

使用 Sass 解析过滤后的文本,就像 `:sass` 过滤器一样,但使用较新的 SCSS 语法在 `<style>` 标签中生成 CSS 输出。此过滤器使用 Tilt 实现。

:textile

使用 Textile 解析过滤后的文本。仅当安装了 RedCloth 时才有效。

从 Haml 4.0 开始,此过滤器在 Haml contrib 中定义,但出于历史原因会自动加载。在 Haml 的未来版本中,它可能不会默认加载。此过滤器使用 Tilt 实现。

自定义过滤器

您也可以定义自己的过滤器。`Haml::Filters::YourCustomFilter#compile` 应该返回 一个 Temple 表达式

过滤器最简单的例子可能类似于

class HelloFilter < Haml::Filters::Base
  def compile(_node)
    [:static, "hello world"]
  end
end

Haml::Filters.registered[:hello] ||= HelloFilter

一个更复杂的例子

class BetterFilter < Haml::Filters::Base
  def compile(node)
    temple = [:multi]
    temple << [:static, "hello "]
    temple << compile_text(node.value[:text])
    temple << [:static, " world"]
    temple
  end

  private
  def compile_text(text)
    if ::Haml::Util.contains_interpolation?(text)
      [:dynamic, ::Haml::Util.unescape_interpolation(text)]
    else
      [:static, text]
    end
  end
end

Haml::Filters.registered[:better] ||= BetterFilter

参见 Haml::Filters 获取示例。

多行:|

管道字符表示多行字符串。它放置在行尾(在一些空格之后),表示所有以|结尾的后续行将被视为在同一行上。注意,即使多行块中的最后一行也应该以|结尾。 例如

%whoo
  %hoo= h(                       |
    "I think this might get " +  |
    "pretty long so I should " + |
    "probably make it " +        |
    "multiline so it doesn't " + |
    "look awful.")               |
  %p This is short.

编译成

<whoo>
  <hoo>I think this might get pretty long so I should probably make it multiline so it doesn't look awful.</hoo>
  <p>This is short</p>
</whoo>

在 Haml 中使用多行声明是故意很麻烦的。这是为了阻止人们在 Haml 模板中放置大量 Ruby 代码。如果你发现自己使用多行声明,请停下来思考:我可以用助手更好地完成这件事吗?

请注意,在某些情况下,允许某些内容以非尴尬的方式流到多行上是有用的。其中之一是 HTML 属性。某些元素只是有很多属性,因此你可以包装属性而无需使用|(参见 属性)。

此外,有时你需要调用 Ruby 方法或声明需要大量模板信息的数据结构。因此,需要大量参数的数据结构和函数可以跨多行包装,只要除最后一行以外的每一行都以逗号结尾(参见 插入 Ruby)。

保留空格

有时你不想让 Haml 缩进所有文本。例如,pretextarea 等标签对空格敏感;缩进文本会导致它们渲染错误。

Haml 通过在将换行符放入文档之前“保留”它们来处理这个问题 - 将它们转换为 HTML 空格转义代码&#x000A;。然后 Haml 不会尝试重新格式化缩进。

文字textareapre 标签会自动保留通过=给出的内容。动态生成的textareapre 无法自动保留,因此应该通过 Haml::Helpers.preserve~ 命令 传递,它们具有相同的效果。

可以使用 :preserve 过滤器 保留文字块。

Turbo

对于使用 Turbo-rails 的用户,需要执行以下操作之一:* 遵循 HTML 格式的命名约定(例如,确保所有 .haml 文件以 .html.haml 结尾),或者 * 添加以下猴子补丁

```rb # config/initializers/haml.rb require “haml/rails_template”

module Haml class RailsTemplate def default_format :html end end end ```