scala.js中真正的JS类来开发webcomponents

时间:2017-05-15 09:28:54

标签: polymer web-component scala.js es6-class polymer-2.x

我想用scala.js在Polymer 2.0项目中开发一些web组件。虽然有wonderful demo-project on github证明它如何与Polymer 1.0一起使用。我无法使用与Polymer 2.0和本机元素注册技术类似的东西。

简单的外观可能如下所示

@ScalaJSDefined
class PolymerElement extends PolymerBase {
  def is: String = ""
  def properties: js.Dynamic = js.Dynamic.literal()
}

@js.native
@JSGlobal("Polymer.Element")
class PolymerBase extends HTMLElement

实际元素:

@JSExportTopLevel("MyElement")
@ScalaJSDefined
class MyElement extends PolymerElement  {

   private var label = "init"

   override def is = "my-element"

   override def properties = js.Dynamic.literal(
    "label" -> Map(
      "type" -> "String",
      "value" -> "init",
      "notify" -> true
    ).toJSDictionary
  )

  def testMe = {
    println(label)
  }
}

object MyElement {
  @JSExportStatic
  val is: String = MyElement.is

  @JSExportStatic
  val properties: js.Dynamic = MyElement.properties

}

无论我是采用旧样式元素注册Polymer(MyElement)还是平台原生变体window.customElement.define(MyElement.is, MyElement) 它显然会引发异常,因为MyElement不能用new MyElement进行实例化。 它引发了异常:

Uncaught TypeError: Class constructor PolymerElement cannot be invoked without 'new'

研究Scala.js facade writing guide,我已经尝试了很多外观变体,声明PolymerElementPolymerBase 抽象

我想到的一个可能的解决方案是编写一个本机JavaScript类,它确实是可实例化的并且在它们上使用@js.native外观。但我正在寻找一种方法来实现它 Scala.js 0.6.16 提供的东西。

1 个答案:

答案 0 :(得分:1)

更新版本(2018-04)

好的,这对其他人也有帮助,我决定发布我的新版本。

我使用这种纯ScalaJS解决方案与Polymer2 / CustomElements集成。

我的环境是:

  • Scala:2.12
  • ScalaJS:0.6.22
  • 还有:"org.scala-js" %%% "scalajs-dom" % "0.9.2"

ScalaJS选项:

"-P:scalajs:sjsDefinedByDefault"

我为CustomElements和Polymer 2创建了一些ScalaJS外墙并在此处发布 - https://bitbucket.org/latestbit/scalymer/src/tip/src/main/scala/org/latestbit/sjs/polymer2/?at=default

他们不是功能齐全的聚合物外墙,只是处于最初状态,但他们正在为我工​​作。

你可以轻松使用它们而不会出现任何黑客攻击:

@JSExportTopLevel(name = "TestElement")
class TestElement() extends Polymer.Element {

    override def connectedCallback(): Unit = {
        super.connectedCallback()
        global.console.log(s"Attribute name ${getAttribute("name")}. Body is ${dom.document.querySelector("body")}")
        global.console.log(s"${this.$.selectDynamic("testCl")}")
        global.console.log(s"${$$("testCl")}")
    }
}


object TestElement {
    @JSExportStatic
    def is = "test-element"

    @JSExportStatic
    def properties = js.Dictionary(
        "name" -> js.Dictionary(
            "type" -> "String"
        )
    )
}

然后在Scala中注册它,如:

object TestJsApplication {

    def main() : Unit = {
        Globals.customElements.define(TestElement.is,
            js.constructorOf[TestElement]
        )
    }

}

html部分通常是:

<dom-module id="test-element">

    <template>
        <span id="testCl">Not much here yet.</span>
        This is <b>[[name]]</b>.
    </template>

</dom-module>

您可以在此处找到完整示例 - https://bitbucket.org/latestbit/scalymer/src

旧尝试解决(出于历史目的)

好的,这是最好的解决方案&#39;我找到了。

这不是完全解决它,但我希望它能成为一个有用的技巧,同时我们期待sjs在这方面有所改进。

  1. 将任何图书馆带到&#39; mixin&#39; js课程。我使用了https://github.com/rse/aggregation

  2. 创建ScalaJS组件,但不要尝试直接从Polymer.Element继承它:

  3. @ScalaJSDefined
    @JSExportTopLevel("TestPolymerElement")
    class TestPolymerElement extends js.Object {
        def test = g.console.log("Hello from scala")
    }
    
    object TestPolymerElement {
        @JSExportStatic
        def is = "test-polymer-element"
    }
    
    1. 创建一个JS pure&#34;伴侣&#34;要将Polymer.Element和ScalaJS组件作为mixin继承并注册它的类:
    2. class TestPolymerElementJs extends aggregation(Polymer.Element,TestPolymerElement) {
      }
      customElements.define(TestPolymerElementJs.is, TestPolymerElementJs);
      

      此外,您可以在ScalaJS中定义属性并对其进行管理,如:

      @ScalaJSDefined
      @JSExportTopLevel("TestPolymerElement")
      class TestPolymerElement(val name : String) extends js.Object {
      
          def test = g.console.log(s"Hello from ${name}")
      
      }
      
      object TestPolymerElement {
          @JSExportStatic
          def is = "test-polymer-element"
      
          @JSExportStatic
          def properties = js.Dictionary (
              "name" -> js.Dictionary(
                  "type" -> "String"
              )
          )
      }