我在Play-scala 2.4中做了类似的事情,但是在主体关闭标签之前有脚本进入页脚。 我不熟悉Play的java api,但我相信这个概念仍然有用。
这是要点: https : //gist.github.com/zv3/2dad7cb63813e82f8412
控制器/ StackableAction.scala
// Borrowed from: https://github.com/rabitarochan/Play2-ChainAction/blob/master/core/src/main/scala/com/github/rabitarochan/play2/stackableaction/StackableAction.scala
abstract class StackableAction extends ActionBuilder[RequestWithAttributes] with StackableFilter {
override def filter[A](request: RequestWithAttributes[A])(f: RequestWithAttributes[A] => Future[Result]): Future[Result] = {
f(request)
}
def invokeBlock[A](req: Request[A], block: RequestWithAttributes[A] => Future[Result]): Future[Result] = {
val reqWA = new RequestWithAttributes(req, new TrieMap[AttributeKey[_], Any]())
filter(reqWA)(block)
}
}
trait StackableFilter {
def filter[A](request: RequestWithAttributes[A])(f: RequestWithAttributes[A] => Future[Result]): Future[Result]
}
trait AttributeKey[A] {
def ->(value: A): Attribute[A] = Attribute(this, value)
}
case class Attribute[A](key: AttributeKey[A], value: A) {
def toTuple: (AttributeKey[A], A) = (key, value)
}
class RequestWithAttributes[A](request: Request[A], attributes: TrieMap[AttributeKey[_], Any]) extends WrappedRequest[A](request) {
def get[B](key: AttributeKey[B]): Option[B] = attributes.get(key).asInstanceOf[Option[B]]
def set[B](key: AttributeKey[B], value: B): RequestWithAttributes[A] = {
attributes.put(key, value)
this
}
def getAll[T](implicit classTag: ClassTag[T]) = {
attributes.filterKeys {
case p: T => true
case _ => false
}
}
}
意见/支持/ JavascriptPage.scala
object JavascriptPage {
case class NonBlockingJS(key: String) extends AttributeKey[Html]
case class BlockingJS(key: String) extends AttributeKey[Html]
def addNonBlockingJS(div: String)(jscript: Html)(implicit request: Request[_]): Unit = {
request match {
case i: RequestWithAttributes[_] =>
i.set(NonBlockingJS(div), jscript)
case _ =>
}
}
// scripts that are supposed to go into the <head> tag, thus blocking scripts
def addBlockingJS(div: String)(jscript: Html)(implicit request: Request[_]): Unit = {
request match {
case i: RequestWithAttributes[_] =>
i.set(BlockingJS(div), jscript)
case _ =>
}
}
// scripts that are supposed to go before the </body> tag, non blocking scripts that is
def getNonBlockingJS()(implicit request: Request[_]): Seq[(String, Html)] = {
request match {
case i: RequestWithAttributes[_] =>
i.getAll[NonBlockingJS].toSeq.map {
case (NonBlockingJS(div), jscript: Html) => (div, jscript)
}
case _ => Seq.empty
}
}
}
inlineNonBlockingJS.scala.html
@import views.support.JavascriptPage
@(implicit request: Request[_])
<script src="/javascripts/your_javascript_app.js"></script>
<script id="non-blocking" type="text/javascript">
@defining(JavascriptPage.getNonBlockingJS()) { scripts =>
@scripts.map { case (_, item) => @item }
}
</script>
它基本上将请求(使用play的动作组合)包含在一个案例类中,该案例类具有TrieMap作为其成员之一,然后它将作为与请求关联的额外属性的持有者,并且这些属性可以是javascript条目和几乎您希望在请求期间拥有和分享的任何其他内容。