簡體   English   中英

加<script> to the <head> from scala template tags in Play Framework 2

[英]Add <script> to the <head> from scala template tags in Play Framework 2

我想從標簽內添加javascript到我的網頁的<head>

這是我在我的網頁上使用的更多腳本:

main.scala.html

@(title: String, scripts: Html = Html(""))(content: Html)
<!DOCTYPE html>
<html lang="nl">
    <head>
        <title>@title</title>
        <meta http-equiv="content-type" content="text/html; charset=utf-8" />
        <script src="//ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
        @scripts
    </head>
    <body>
        @content
    </body>
</html>

page.scala.html

@scripts = {
    <script type="text/javascript">
        $(document).ready(function() {
            alert(1);
        });
    </script>
}
@main("Title", scripts) {
    <p>page content</p>
}

到現在為止還挺好! 但是我想在我編寫的標簽(組件)中做同樣的事情,需要在網頁中包含一些javascript代碼。

我的問題是如何將<script>元素從標記傳遞到main.scala.html

所以page.scala.html將是:

page.scala.html

@import tags._
@main("Title") {
    @mytag("green")
}

mytag.scala.html

@(color: String)
<script type="text/javascript">
    $(document).ready(function() {
        alert('@color');
    });
</script>

<p>Some more content</p>

在這種情況下, <script>標記在HTML頁面的中間呈現,我想將<script>標記傳遞給@scripts變量,以便它可以在<head>標記內呈現。

好的,我想出了一個更好的解決方案恕我直言。

我創建了以下標記:

script.scala.html

@(content: Html)
@{
    var additionalScripts = ctx().args.get("additionalScripts").asInstanceOf[List[Html]];
    if(additionalScripts == null) {
        additionalScripts = new ArrayList[Html]();
        ctx().args.put("additionalScripts", additionalScripts)
    }

    val added = additionalScripts.add(content);
}

renderscripts.scala.html

@additionalScripts = @{ctx().args.get("additionalScripts").asInstanceOf[List[Html]]}
@if(additionalScripts != null) {
    @for(additionalScript <- additionalScripts) {
        @additionalScript
    }
}

main.scala.html您可以使用:

@(title: String)(content: Html)
@import tags._
<!DOCTYPE html>
<html lang="nl">
    <head>
        <title>@title</title>
        <script src="//ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
        @renderscripts()
    </head>
    <body>
        @content
    </body>
</html>

您可以使用以下命令在模板或標簽中指定其他腳本:

@import tags._
@script {
    <script type="text/javascript">
        $(document).ready(function() {
            alert('This will be in the head!');
        });
    </script>
}

這很好,對吧? :)

也許有人可以使用他們的Scala魔法來清理或增強我的代碼:)

這是可行的,但我同意ajozwik,並說你的腳本內聯將更容易,應該仍然可以正常工作。


你可以做的是添加另一個參數組,基本上是另一個(content:Html)到你的主模板,這將呈現使用mytag生成的<script>標簽。

main.scala.html

@(title: String, scripts: Html = Html(""))(content: Html)(implicit mytagScripts: Html = null)
<!DOCTYPE html>
<html lang="nl">
  <head>
    <title>@title</title>
    <meta http-equiv="content-type" content="text/html; charset=utf-8" />
    <script src="//ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
    @scripts
    @mytagScripts
  </head>
  <body>
    @content
  </body>
</html>

在您使用mytag任何視圖上,您​​需要定義mytagScripts的值。 它是隱含的,因此您不必在不使用它的模板上定義它,它只使用默認值。

除了需要生成<script>並將其存儲以供以后使用之外,您的標記模板不會發生太大變化。 我們可以使用Context.args映射。

mytag.scala.html

@(color:String)
@{ctx().args.put("mytagScriptHtml", new Html("<script>alert('" + color + "');</script>"))}
<div>
  <!-- whatever else you're tag is generating -->
</div>

最后,你的頁面看起來像這樣。 注意第二組花括號,它是在主模板上定義mytagScripts的。 組之間的關閉/打開括號必須在同一行上,否則您將收到編譯器錯誤。

page.scala.html

@import tags._
@main("Title") {
  @mytag("green")
} {
  @ctx().args.get("mytagScriptHtml")
}

簡化示例...如果您希望在頁面中多次使用該標記,則需要跟蹤List中的<script>標記或其他內容。 同樣的概念,因為您可以在Context.args存儲任何Object

為什么不直接將mytag傳遞給main

page.scala.html

@import tags.html.mytag
@main("Title", mytag("green")) {
    <p>page content</p>
}

我在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條目和幾乎您希望在請求期間擁有和分享的任何其他內容。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM