Scala 如何在play framework 2中使用脚本处理多层模板?

Scala 如何在play framework 2中使用脚本处理多层模板?,scala,playframework-2.0,template-engine,Scala,Playframework 2.0,Template Engine,我有这样一个模板结构: modal.scala.view @() ... HTML code to display a modal in my app ... /** * Output type for components to render body, head and end-of-body content * @param bodyMarkup the visual part of the component output * @param resources tags f

我有这样一个模板结构:

modal.scala.view

@()
  ... HTML code to display a modal in my app ...
/**
 * Output type for components to render body, head and end-of-body content
 * @param bodyMarkup the visual part of the component output
 * @param resources tags for content to include in the head or footer
 */
case class MultipartHtml(bodyMarkup: Html, resources: Seq[MultipartHtml.Resource] = Nil) {
  import com.huffpost.hyperion.lib.MultipartHtml._

  /**
   * Apply a transformation to the body content of this object
   * @param bodyMapper transformation function
   * @return a new object with transformed body content
   */
  def map(bodyMapper: Html => Html): MultipartHtml = MultipartHtml(bodyMapper(bodyMarkup), resources)

  /**
   * @param bodyMapper transformation function
   * @return the bodyMapper result combined with the component resource list
   */
  def flatMap(bodyMapper: Html => MultipartHtml): MultipartHtml = bodyMapper(bodyMarkup) ++ resources

  /**
   * Add a head and/or footer content to this object
   * @param resources the resources to add
   * @return a new object with the resource added
   */
  def ++(resources: GenTraversableOnce[Resource]): MultipartHtml = resources.foldLeft(this)(_ :+ _)

  /**
   * Add a head or footer content to this object
   * @param resource the resource to add
   * @return a new object with the resource added
   */
  def :+(resource: Resource): MultipartHtml = MultipartHtml(bodyMarkup, (resources :+ resource).distinct)

  /**
   * Prepend a head or footer content to this object
   * @param resource the resource to add
   * @return a new object with the resource added
   */
  def +:(resource: Resource): MultipartHtml = MultipartHtml(bodyMarkup, (resource +: resources).distinct)

  /** Get tags by resource type for injection into a template */
  def renderResourcesByType(resourceType: ResourceType): Html = Html(resources.filter(_.resourceType == resourceType).mkString("\n"))
}

/** Utility methods for MultipartHtml type */
object MultipartHtml {
  /** Empty MultipartHtml */
  def empty = MultipartHtml(Html(""))

  /** A resource that can be imported in the HTML head or footer*/
  trait ResourceType
  trait Resource {
    def resourceType: ResourceType
  }

  object HeadTag extends ResourceType
  object FooterTag extends ResourceType

  /** A style tag */
  case class StyleTag(styleUrl: String) extends Resource {
    val resourceType = HeadTag
    override def toString = {
      val assetUrl = routes.Assets.at(styleUrl).url
      s"""<link rel="stylesheet" type="text/css" media="screen" href="$assetUrl">"""
    }
  }

  /** A script tag */
  case class ScriptTag(scriptUrl: String) extends Resource {
    val resourceType = FooterTag
    override def toString = {
      val assetUrl = routes.Assets.at(s"javascript/$scriptUrl").url
      s"""<script type="text/javascript" src="$assetUrl"></script>"""
    }
  }
}



我想在modal.scala.view中保留modal的脚本,但我找不到将脚本从子模板传递到父模板的方法,以便在主模板的正确位置渲染它们。有什么想法吗?提前谢谢

我认为对你的问题没有一个游戏团队认可的标准答案,但我可以想到两种方法:一元方法和命令式方法

在子控制器中包裹视图;在输出中封装脚本

我正在从事的一个大型项目使用这种策略。我们创建了一个
MultipartHtml
类型,其中包含应该包含在文档正文中的
Html
输出,以及一个我们创建的名为
Resources
的类型,其中包含应该放在别处的内容。我们将这种类型视为monad,这样我们就可以
map
flatMap
它来操作
Html
文档内容,同时积累和消除
资源的重复

我们所有的控制器都返回
多端口tml
。它们从视图的结果构造一个实例,然后简单地将
:+
资源
标记到结果。我们的页面级控制器将这些部分组合在一起。我们所做工作的核心如下:

modal.scala.view

@()
  ... HTML code to display a modal in my app ...
/**
 * Output type for components to render body, head and end-of-body content
 * @param bodyMarkup the visual part of the component output
 * @param resources tags for content to include in the head or footer
 */
case class MultipartHtml(bodyMarkup: Html, resources: Seq[MultipartHtml.Resource] = Nil) {
  import com.huffpost.hyperion.lib.MultipartHtml._

  /**
   * Apply a transformation to the body content of this object
   * @param bodyMapper transformation function
   * @return a new object with transformed body content
   */
  def map(bodyMapper: Html => Html): MultipartHtml = MultipartHtml(bodyMapper(bodyMarkup), resources)

  /**
   * @param bodyMapper transformation function
   * @return the bodyMapper result combined with the component resource list
   */
  def flatMap(bodyMapper: Html => MultipartHtml): MultipartHtml = bodyMapper(bodyMarkup) ++ resources

  /**
   * Add a head and/or footer content to this object
   * @param resources the resources to add
   * @return a new object with the resource added
   */
  def ++(resources: GenTraversableOnce[Resource]): MultipartHtml = resources.foldLeft(this)(_ :+ _)

  /**
   * Add a head or footer content to this object
   * @param resource the resource to add
   * @return a new object with the resource added
   */
  def :+(resource: Resource): MultipartHtml = MultipartHtml(bodyMarkup, (resources :+ resource).distinct)

  /**
   * Prepend a head or footer content to this object
   * @param resource the resource to add
   * @return a new object with the resource added
   */
  def +:(resource: Resource): MultipartHtml = MultipartHtml(bodyMarkup, (resource +: resources).distinct)

  /** Get tags by resource type for injection into a template */
  def renderResourcesByType(resourceType: ResourceType): Html = Html(resources.filter(_.resourceType == resourceType).mkString("\n"))
}

/** Utility methods for MultipartHtml type */
object MultipartHtml {
  /** Empty MultipartHtml */
  def empty = MultipartHtml(Html(""))

  /** A resource that can be imported in the HTML head or footer*/
  trait ResourceType
  trait Resource {
    def resourceType: ResourceType
  }

  object HeadTag extends ResourceType
  object FooterTag extends ResourceType

  /** A style tag */
  case class StyleTag(styleUrl: String) extends Resource {
    val resourceType = HeadTag
    override def toString = {
      val assetUrl = routes.Assets.at(styleUrl).url
      s"""<link rel="stylesheet" type="text/css" media="screen" href="$assetUrl">"""
    }
  }

  /** A script tag */
  case class ScriptTag(scriptUrl: String) extends Resource {
    val resourceType = FooterTag
    override def toString = {
      val assetUrl = routes.Assets.at(s"javascript/$scriptUrl").url
      s"""<script type="text/javascript" src="$assetUrl"></script>"""
    }
  }
}
然后在模板中,您可以执行以下操作:

@(addTag: Html => Unit)

@addTag {
  <script src="myscript.js"></script>
}

@* Generate HTML *@
@(addTag:Html=>单位)
@地址标签{
}
@*生成HTML*@

这里的缺点是,您必须以某种方式将此对象向下转发,如果您的局部视图层次结构深入,这可能会很痛苦

谢谢你,阿杰。我将尝试命令式方法,因为我在java play中工作。如果成功,我将在这里报告结果。再次感谢!可变的方式很好地工作。使用隐式,我可以避免将所有模板与可变对象混在一起。谢谢你,伙计。
@(addTag: Html => Unit)

@addTag {
  <script src="myscript.js"></script>
}

@* Generate HTML *@