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

SeD*_*Dav 7 web-component polymer scala.js es6-class polymer-2.x

我想用scala.js在Polymer 2.0项目中开发一些web组件.虽然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
Run Code Online (Sandbox Code Playgroud)

实际元素:

@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

}
Run Code Online (Sandbox Code Playgroud)

无论我是采用旧样式元素注册Polymer(MyElement)还是平台本机变体,window.customElement.define(MyElement.is, MyElement) 它都会抛出一个异常,因为MyElement它不具有实例性new MyElement.它抛出了异常:

Uncaught TypeError: Class constructor PolymerElement cannot be invoked without 'new'
Run Code Online (Sandbox Code Playgroud)

学习Scala.js门面写作指南,我已经尝试了许多外观变体声明PolymerElementPolymerBase 抽象.

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

abd*_*nce 2


更新版本(2018-04)

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

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

我的环境是:

  • 斯卡拉: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=默认

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

您可以轻松使用它们,无需任何黑客操作,例如:

@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"
        )
    )
}
Run Code Online (Sandbox Code Playgroud)

然后也在 Scala 中注册它,如下所示:

object TestJsApplication {

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

}
Run Code Online (Sandbox Code Playgroud)

html 部分很常见:

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

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

</dom-module>
Run Code Online (Sandbox Code Playgroud)

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


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

好吧,这是我找到的最好的“解决方案”。

这并没有完全解决这个问题,但我希望这将是一个有用的技巧,同时我们期待 sjs 在这方面的改进。

  1. 获取任何库来“混合”js 类。我使用过https://github.com/rse/aggregation

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

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

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

</dom-module>
Run Code Online (Sandbox Code Playgroud)
  1. 创建一个 JS 纯“伴侣”类来继承 Polymer.Element 和 ScalaJS 组件作为 mixin 并注册它:
class TestPolymerElementJs extends aggregation(Polymer.Element,TestPolymerElement) {
}
customElements.define(TestPolymerElementJs.is, TestPolymerElementJs);
Run Code Online (Sandbox Code Playgroud)

此外,您还可以在 ScalaJS 中定义属性并管理它们,例如:

@ScalaJSDefined
@JSExportTopLevel("TestPolymerElement")
class TestPolymerElement extends js.Object {
    def test = g.console.log("Hello from scala")
}

object TestPolymerElement {
    @JSExportStatic
    def is = "test-polymer-element"
}
Run Code Online (Sandbox Code Playgroud)