19.9 Layouts and Components
Layouts 是为了解决页面显示重复:
The average web site,though, has lots of duplication.
• Many pages share the same tops, tails, and sidebars.
• Multiple pages may contain the same snippets of rendered HTML (a blog site, for example, may have multiple places where an article is displayed).
• The same functionality may appear in multiple places. Many sites have a standard search component, or a polling component, that appears in most of the sites’ sidebars.
Rails has layouts, partials, and components that reduce the need for duplication in these three situations.
Layouts
Let’s look at a layout template.
- <html>
- <head>
- <title>Form: <%= controller.action_name %></title>
- <%= stylesheet_link_tag 'scaffold' %>
- </head>
- <body>
- <%= @content_for_layout %>
- </body>
- </html>
#控制器里的action
def my_action
@msg = "Hello, World!"
end
#视图
my_action.rhtml template
<h1><%= @msg %></h1>
#最终html代码
the browser would see the following HTML.
<html>
<head>
<title>Form: my_action</title>
<link href="/stylesheets/scaffold.css" media="screen" el="Stylesheet" type="text/css" />
</head>
<body>
<h1>Hello, World!</h1>
</body>
</html>
Locating Layout Files
#使用模板
The layout file will be looked for in the app/views/layouts directory.
class StoreController < ApplicationController
layout "standard"
# ...
end
#设置except和only模板
You can qualify which actions will have the layout applied to them using the :only and :except qualifiers.
class StoreController < ApplicationController
layout "standard" , :except => [ :rss, :atom ]
# ...
end
#:determine_layout是一个标签,其规则是相应action名字的返回值才是真正的模板,比如说store_down或standard模板
class StoreController < ApplicationController
layout :determine_layout
# ...
private
def determine_layout
if Store.is_closed?
"store_down"
else
"standard"
end
end
end
#给action单独制定模板
Finally, individual actions can choose to render using a specific layout (or with no layout at all) by passing render( ) the :layout option.
def rss
render(:layout => false) # never use a layout
end
def checkout
render(:layout => "layouts/simple" )
end
#传递数据到模板
#子模板@title = "My Wonderful Life"对@title赋值,会把值带到父模板
Passing Data to Layouts
<html>
<head>
<title><%= @title %></title>
<%= stylesheet_link_tag 'scaffold' %>
</head>
<body>
<h1><%= @title %></h1>
<%= @content_for_layout %>
</body>
</html>
An individual template could set the title by assigning to the @title variable.
<% @title = "My Wonderful Life" %>
<p>
Dear Diary:
</p>
<p>
Yesterday I had pizza for dinner. It was nice.
</p>
Partial Page Templates
_article.rhtml
<div class="article" >
<div class="articleheader" >
<h3><%= article.title %></h3>
</div>
<div class="articlebody" >
<%= h(article.body) %>
</div>
</div>
Other templates use the render(:partial=>) method to invoke this
<%= render(:partial => "article" , :object => @an_article) %>
<h3>Add Comment</h3>
. . .
#render的:partial参数 是要载入到模板中的页面名称(但是这个名字不需要"_",例如"_article.rhtml"在此处的名字为article),
#:object的值是传递给_article.html的实例,而在_article.html里我们不使用@an_article变量名而是使用页面却不要"_"的名字,
#及我们在_article中使用article来代替 @an_article
#如果传递给局部模板的对象是一个控制器里的变量,并且这个变量与局部模板同名,则可以忽略object参数
If the object to be passed to the partial is in a controller instance variable with
the same name as the partial, you can omit the :object parameter.
#在我们前面的例子中,如果我们的控制器里有一个@article实例变量,视图可以仅仅像这样,完成前面的功能
If, in the previous example, our controller had set up the article in the instance
variable @article, the view could have rendered the partial using just
<%= render(:partial => "article" ) %> # = <%= render(:partial => "article",:object=>@article ) %>
<h3>Add Comment</h3>
. . .
#可以通过:locals参数传递本地变量到模板,:locals是一个hash,hash中每个实体为本地变量的名字和值
You can set additional local variables in the template by passing render( ) a :locals parameter. This takes a hash where the entries represent the names and values of the local variables to set.
render(:partial => 'article' ,
:object => @an_article,
:locals => { :authorized_by => session[:user_name],
:from_ip => @request.remote_ip })
#局部模板和集合
Partials and Collections
<%= render(:partial => "article" , :collection => @article_list,[:spacer_template=>"spacer"]) %>
集合@article_list根据集合元素的个数来循环的引用_article.rhtml页面,其中的每一个元素在_article.rhtml中的变量名为article
其中:spacer_template是可选的,它的作用是在每个局部模块中间隔的局部模板
例如:_spacer.rhtml代码如下
<hr />
即在每个局部模板_article之间加上一个换行符;
Shared Partial Page Templates
在render()方法中的:partial参数是一个简单的名字,则在当前控制器的视图目录下找相应页面;
如果是"/"的形式,例如"contorllername/viewname"则到相应的controller下面去找view,这样就实现了局部模板的共享;
但是,根据惯例,应该把这些共享模板放在app/views/shared目录下