真正的 JS 类在 scala 中.js用于开发 Web组件



我想用scala.js开发Polymer 2.0项目中的一些Web组件。虽然在github上有一个很棒的演示项目,展示了它如何与Polymer 1.0一起工作。我无法获得类似于使用聚合物 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 立面写作指南时,我已经尝试了很多声明PolymerElementPolymerBase抽象的立面变体。

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


更新版本 (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=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


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

好的,这是我找到的最好的"解决方案"。

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

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

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

@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纯"companion"类来继承Polymer.Element和ScalaJS组件作为mixin并注册它:
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"
)
)
}

最新更新