(Quick Reference)

6.2.4 使用Sitemesh布局 - Reference Documentation

Authors: Graeme Rocher, Peter Ledbrook, Marc Palmer, Jeff Brown, Luke Daley, Burt Beckwith

Version: null

6.2.4 使用Sitemesh布局

Creating Layouts

Grails leverages Sitemesh, a decorator engine, to support view layouts. Layouts are located in the grails-app/views/layouts directory. A typical layout can be seen below:

<html>
    <head>
        <title><g:layoutTitle default="An example decorator" /></title>
        <g:layoutHead />
    </head>
    <body onload="${pageProperty(name:'body.onload')}">
        <div class="menu"><!--my common menu goes here--></menu>
            <div class="body">
                <g:layoutBody />
            </div>
        </div>
    </body>
</html>

The key elements are the layoutHead, layoutTitle and layoutBody tag invocations:

  • layoutTitle - outputs the target page's title
  • layoutHead - outputs the target page's head tag contents
  • layoutBody - outputs the target page's body tag contents

The previous example also demonstrates the pageProperty tag which can be used to inspect and return aspects of the target page.

创建布局

Grails使用Sitemesh(一个装饰引擎)来支持视图布局。布局位于grails-app/views/layouts目录下边。一个典型的布局可以如下所示:

<html>
    <head>
        <title><g:layoutTitle default="An example decorator" /></title>
        <g:layoutHead />
    </head>
    <body onload="${pageProperty(name:'body.onload')}">
        <div class="menu"><!--my common menu goes here--></menu>
            <div class="body">
                <g:layoutBody />
            </div>
        </div>
    </body>
</html>

所涉及到的关键元素是layoutHeadlayoutTitlelayoutBody标签:

  • layoutTitle - 输出目标页面的标题(title)
  • layoutHead - 输出目标页面的head标签的内容
  • layoutBody - 输出目标页面的body标签的内容

在上述示例中,也演示了pageProperty标签的用法,其用来检查和返回目标页面的详情。

Triggering Layouts

There are a few ways to trigger a layout. The simplest is to add a meta tag to the view:

<html>
    <head>
        <title>An Example Page</title>
        <meta name="layout" content="main" />
    </head>
    <body>This is my content!</body>
</html>

In this case a layout called grails-app/views/layouts/main.gsp will be used to layout the page. If we were to use the layout from the previous section the output would resemble this:

<html>
    <head>
        <title>An Example Page</title>
    </head>
    <body onload="">
        <div class="menu"><!--my common menu goes here--></div>
        <div class="body">
            This is my content!
        </div>
    </body>
</html>

触发布局

有几种方法来触发一个布局。最简单的一种就是在视图中增加一个meta标签:

<html>
    <head>
        <title>An Example Page</title>
        <meta name="layout" content="main" />
    </head>
    <body>This is my content!</body>
</html>

在上述示例中,一个名为grails-app/views/layouts/main.gsp的布局将被用于安排页面。如果我们使用上一小节的布局,那么其输出类似下面所示:

<html>
    <head>
        <title>An Example Page</title>
    </head>
    <body onload="">
        <div class="menu"><!--my common menu goes here--></div>
        <div class="body">
            This is my content!
        </div>
    </body>
</html>

Specifying A Layout In A Controller

Another way to specify a layout is to specify the name of the layout by assigning a value to the "layout" property in a controller. For example, if you have a controller such as:

class BookController {
    static layout = 'customer'

def list() { … } }

You can create a layout called grails-app/views/layouts/customer.gsp which will be applied to all views that the BookController delegates to. The value of the "layout" property may contain a directory structure relative to the grails-app/views/layouts/ directory. For example:

class BookController {
    static layout = 'custom/customer'

def list() { … } }

Views rendered from that controller would be decorated with the grails-app/views/layouts/custom/customer.gsp template.

在控制器中指定一个布局

另外一种指定布局的方法是在控制器中为"layout"属性赋值一个布局的名称。举一个例子,假设你有如下一个控制器:

class BookController {
    static layout = 'customer'

def list() { … } }

你就可以创建一个grails-app/views/layouts/customer.gsp布局,这样BookController所有的所有视图将使用此布局。"layout"属性的值还可以包含一个目录结构,不过要相对于grails-app/views/layouts/目录。比如:

class BookController {
    static layout = 'custom/customer'

def list() { … } }

那个控制器所渲染的视图将使用grails-app/views/layouts/custom/customer.gsp模板来装饰。

Layout by Convention

Another way to associate layouts is to use "layout by convention". For example, if you have this controller:

class BookController {
    def list() { … }
}

You can create a layout called grails-app/views/layouts/book.gsp, which will be applied to all views that the BookController delegates to.

Alternatively, you can create a layout called grails-app/views/layouts/book/list.gsp which will only be applied to the list action within the BookController.

If you have both the above mentioned layouts in place the layout specific to the action will take precedence when the list action is executed.

If a layout may not be located using any of those conventions, the convention of last resort is to look for the application default layout which is grails-app/views/layouts/application.gsp. The name of the application default layout may be changed by defining a property in grails-app/conf/Config.groovy as follows:

grails.sitemesh.default.layout = 'myLayoutName'

With that property in place, the application default layout will be grails-app/views/layouts/myLayoutName.gsp.

布局规约

另外一种关联布局的方式是使用"布局规约"。比如,你的控制器如下所示:

class BookController {
    def list() { … }
}

你可以创建grails-app/views/layouts/book.gsp布局,此布局将会应用于一个BookController的所有视图。

此外,你也可以创建一个grails-app/views/layouts/book/list.gsp布局,其用于BookControllerlist操作。

如果你有如上所述的两个布局,那么当list操作被执行时,跟操作相关的布局将优先使用。

如果一个布局在这些约定中没有找到,那么此规约的最后顺序是查找应用的缺省布局grails-app/views/layouts/application.gsp。应用的缺省布局名称可以通过修改grails-app/conf/Config.groovy中的属性来改变,比如:

grails.sitemesh.default.layout = 'myLayoutName'

设置新值后,应用的缺省布局将是grails-app/views/layouts/myLayoutName.gsp

Inline Layouts

Grails' also supports Sitemesh's concept of inline layouts with the applyLayout tag. This can be used to apply a layout to a template, URL or arbitrary section of content. This lets you even further modularize your view structure by "decorating" your template includes.

Some examples of usage can be seen below:

<g:applyLayout name="myLayout" template="bookTemplate" collection="${books}" />

<g:applyLayout name="myLayout" url="http://www.google.com" />

<g:applyLayout name="myLayout"> The content to apply a layout to </g:applyLayout>

内联布局

Grails同样支持Sitemesh的内联布局概念,可以使用applyLayout标签来实现。此标签可以将一个布局应用于一个模板,URL或者任意部分的内容。更甚者,通过“装饰”你的模板你可以将你的视图模块化。

这些用法的一些示例如下:

<g:applyLayout name="myLayout" template="bookTemplate" collection="${books}" />

<g:applyLayout name="myLayout" url="http://www.google.com" />

<g:applyLayout name="myLayout"> The content to apply a layout to </g:applyLayout>

Server-Side Includes

While the applyLayout tag is useful for applying layouts to external content, if you simply want to include external content in the current page you use the include tag:

<g:include controller="book" action="list" />

You can even combine the include tag and the applyLayout tag for added flexibility:

<g:applyLayout name="myLayout">
   <g:include controller="book" action="list" />
</g:applyLayout>

Finally, you can also call the include tag from a controller or tag library as a method:

def content = include(controller:"book", action:"list")

The resulting content will be provided via the return value of the include tag.

服务器端的包含

applyLayout标签可以将布局应用到外部内容,而如果你只想简单地将外部内容包含到当前页面,你可以使用include标签:

<g:include controller="book" action="list" />

你甚至可以灵活地组合includeapplyLayout标签,比如:

<g:applyLayout name="myLayout">
   <g:include controller="book" action="list" />
</g:applyLayout>

最后,你还可以从控制器或者标签库中将include标签作为方法来调用:

def content = include(controller:"book", action:"list")

由此产生的内容是通过include标签的返回值提供的。