6

我正在尝试使用资产管道插件(v1.0.4)在 grails v2.3.1 中设置 SiteMesh 布局,但我不确定如何处理在我的模板的特定位置包含 javascript 资源(比如如果使用资源插件,您将使用 r:layoutResources )。

示例布局(grails-app/views/layouts/test.gsp):

<html>
   <head>
      <title><g:layoutTitle/></title>
      <g:layoutHead/>
   </head>
   <body>
      <div class="thecontent">
         <g:layoutBody/>
      </div>
      <asset:javascript src="application.js"/>
      <!-- WANT DECORATED PAGE RESOURCES TO BE INCLUDED HERE -->
   </body>
</html>

示例 gsp (grails-app/views/test.gsp):

<html>
   <head>
      <meta name="layout" content="test"/>
      <title>The Title</title>
      <asset:stylesheet src="thispageonly.css"/>
   </head>
   <body>
      <div id="helloworld">
         Hello World
      </div>
      <asset:javascript src="thispageonly.js"/>
   </body>
</html>

生成的装饰页面(忽略资产管道捆绑/等)适用于样式表(因为它在头部)但对于 javascript 失败:

<html>
   <head>
      <meta name="layout" content="test"/>
      <title>The Title</title>
      <link rel="stylesheet" href="/assets/thispageonly.css?compile=false"/>
   </head>
   <body>
      <div class="thecontent">
         <div id="helloworld">
            Hello World
         </div>
         <!-- *** NOT WHERE I WANT THIS *** -->
         <script src="/assets/thispageonly.js?compile=false" type="text/javascript"></script>
      </div>
      <script src="/assets/application.js?compile=false" type="text/javascript"></script>
   </body>
</html>

目前,我可以让它工作的唯一方法是使用 g:applyLayout 和 g:pageProperty:

<!-- grails-app/views/layouts/test2.gsp -->
<html>
   <head>
      <title><g:layoutTitle/></title>
      <g:layoutHead/>
   </head>
   <body>
      <div class="thecontent">
         <g:layoutBody/>
      </div>
      <asset:javascript src="application.js"/>
      <g:pageProperty name="page.javascript"/>
   </body>
</html>


<!-- grails-app/views/test2.gsp -->
<g:applyLayout name="test2">
<html>
   <head>
      <title>The Title</title>
      <asset:stylesheet src="thispageonly.css"/>
   </head>
   <body>
      <div id="helloworld">
         Hello World
      </div>
      <content tag="javascript">
         <asset:javascript src="thispageonly.js"/>
      </content>
   </body>
</html>
</g:applyLayout>

但是这种与元标记的背离似乎过于复杂(另外我不清楚记录不充分的 g:pageProperty 是否会在未来的升级中得到支持)。这样做的最佳长期方法是什么?

4

4 回答 4

3

仅供参考:这对我来说效果很好,虽然它有点难看。

<!-- grails-app/views/layouts/test2.gsp -->
<html>
   <head>
      <title><g:layoutTitle/></title>
      <g:layoutHead/>
   </head>
   <body>
      <div class="thecontent">
         <g:layoutBody/>
      </div>
      <asset:javascript src="application.js"/>
      <asset:deferredScripts/>
   </body>
</html>

<!-- grails-app/views/test2.gsp -->
<g:applyLayout name="test2">
<html>
   <head>
      <title>The Title</title>
      <asset:stylesheet src="thispageonly.css"/>
   </head>
   <body>
      <div id="helloworld">
         Hello World
      </div>
      <asset:script src="${assetPath(src: 'thispageonly.js')}" type="text/javascript" />
   </body>
</html>
</g:applyLayout>
于 2014-11-27T08:21:44.757 回答
1

忽略这个答案,请参阅下面的asset-pipeline创建者评论,了解它是如何在资产管道插件中作为<asset:script>.

旧答案:

Sitemesh 让我头疼,据我所知,使用g:layoutHeadg:layoutBody标签的解决方案并不是让你收集一堆不同的 javascript 片段并在一个块中发出它们。

我最近开始开发的应用程序大量利用了该r:script标签,并且会在单个 gsp 页面中多次使用它(在各种包含的模板上)。

我打算如何在我的应用程序中解决这个问题是使用一个标签库,它几乎可以完成r:script标签所做的事情。收集任何延迟的 javascript 片段并在用户要求发出的地方发出它。

这是一个可以执行此操作的示例 taglib:

class DeferTagLib {
    static namespace = 'defer'
    static defaultEncodeAs = [emitScript: 'raw']  // we actually want to inject javascript :)

    private static JAVASCRIPT_DEFER_PROPERTY = "__defer__javascript"

    protected String removeJavascript() {
        try {
            return getJavascript()
        } finally {
            getRequest().removeAttribute(JAVASCRIPT_DEFER_PROPERTY)
        }
    }

    protected String getJavascript() {
        return getRequest().getAttribute(JAVASCRIPT_DEFER_PROPERTY)
    }

    protected void appendJavascript(String javascript) {
        String currentValue = getJavascript() ?: ""
        getRequest().setAttribute(JAVASCRIPT_DEFER_PROPERTY, currentValue + javascript)
    }

    // For gathering script tags in your gsp files and emitting them in the footer of the layout
    // A replacement for the r:script tag that came with Resources, but is not in the asset-pipeline plugin
    def script = { attrs, body ->
        appendJavascript(body())
    }

    // Used in the layout to emit all the script that has been deferred so far in the footer of the page
    // A replacement for the <r:layoutResources/> tag that emitted javascript in the footer
    // (the 2nd time it was called, kind of confusing...)
    def emitScript = { attrs ->
        out << "<script>${removeJavascript()}</script>"
    }
}

然后,在我的 gsp 页面/片段中,我可以将任何以前的调用替换r:scriptdefer:script

<defer:script>
    // this is before
</defer:script>

... maybe another template that's included ...

<defer:script>
    alert("foo!");
</defer:script>

...  later

<defer:script>
    // after
</defer:script>

在我的布局中,在底部我可以这样做

<html>
  <head>
     .... shared head stuff ....
    <g:layoutHead/>
  </head>

  <body>
    .... body stuff before layout
    <g:layoutBody/>
    .... other body stuff after layout
    <defer:emitScript/>
  </body>
</html>

这最终会在看起来像的身体之后创建一个部分

    ... the actual body from the gsp

    <script>
      // this is before ...
      alert("foo!");
      // after
    </script>
  </body>
</html>
于 2014-03-21T21:50:48.750 回答
1

使用站点网格来控制对象放置完全是一个有效的用例。Sitemesh 不会去任何地方,我实际上用它来控制子容器和布局继承。在资产管道插件中复制这个内置的流控制是没有意义的。

另一个非常有用的技巧是使用<g:layoutHead/>and<g:layoutBody/>标签,这也非常有用。

如果这被证明是一个问题,将来我们可能会考虑提供一种具有这种行为的模式。让我知道资产管道的进展情况,如果出现此类问题,请随时在 github 上开票。显然,我还需要注意堆栈溢出:)

于 2013-12-04T14:36:24.800 回答
0

不确定您的要求。在我的项目中,我需要将所有 JavaScript 文件移动到页脚。我将“布局资源”标签从页眉移到页脚,效果很好。

<footer class="clear">
    <r:layoutResources>
</footer>
于 2017-11-02T09:41:51.437 回答