这个问题是关于一个使用Kotlin前端插件的Kotlin JS项目。
我想使用Vaadin Components library中的一些UI组件。
对此我有两个问题:
(1)在Kotlin JS中包括Web组件的最佳方法是什么
=>有关我的完整代码,请参见下面的源链接。概括而言,相关细节是:
build.gradle.kts
kotlinFrontend {
npm {
dependency("@vaadin/vaadin-grid")
}
}
vaadin.grid.Imports.kt
@file:JsModule("@vaadin/vaadin-grid")
@file:JsNonModule
package vaadin.grid
external class GridElement {
companion object
}
为什么使用companion object
?解决方法需要它(见下文)。
foo.kt
fun main() {
document.getElementById("container")!!.append {
vaadin_grid {
attributes["id"] = "grid"
}
}
initUI()
}
fun initUI() {
// Force the side-effects of the vaadin modules. Is there a better way?
console.log(GridElement)
val grid = document.querySelector("#grid") /* ?? as GridElement ?? */
}
console.log
是我要避免的丑陋的解决方法。如果我不对GridElement 做任何事情,那么它就不包含在我的捆绑包中。
vaadin_grid
DSL被定义为与代码无关的自定义kotlinx.html标记。
(2)我想保持代码尽可能的键入以避免asDynamic
,但是当我将HTMLElement
转换为Vaadin元素时,我得到ClassCastExceptions(因为GridElement
是{{ 1}})。
例如,我想写这样的东西:
undefined
这是我定义外部GridElement的方式
vaadin / button / Imports.kt
val grid : GridElement = document.querySelector("#grid") as GridElement
grid.items = ... // vs grid.asDynamic().items which does work
build/node_modules/@vaadin/vaadin-grid/src/vaadin-grid.js
@file:JsModule("@vaadin/vaadin-grid")
@file:JsNonModule
package vaadin.grid
import org.w3c.dom.HTMLElement
abstract external class GridElement : HTMLElement {
var items: Array<*> = definedExternally
}
要运行:
从git repo的根开始:
...
customElements.define(GridElement.is, GridElement);
export { GridElement };
答案 0 :(得分:1)
我找到了答案
第一个问题
(1)在Kotlin JS中包括Web组件的最佳方法是什么
我使用console.log
代替了require(...)
来引发副作用
external fun require(module: String): dynamic
fun main() {
require("@vaadin/vaadin-button")
require("@vaadin/vaadin-text-field")
require("@vaadin/vaadin-grid")
...
}
(记入某人在kotlin-frontend-plugin list上的答案的信)
(2)我想让我的代码尽可能地键入以避免asDynamic
我必须导入实际上暴露元素的文件,而不是导入@vaadin/vaadin-grid
。然后它似乎起作用了,我什至可以将泛型添加到我的GridElement中:
@file:JsModule("@vaadin/vaadin-grid/src/vaadin-grid")
@file:JsNonModule
package vaadin.grid
import org.w3c.dom.HTMLElement
abstract external class GridElement<T> : HTMLElement {
var items: Array<out T> = definedExternally
}
这样,我就可以摆脱所有asDynamic
s
val firstNameField = document.querySelector("#firstName") as TextFieldElement?
val lastNameField = document.querySelector("#lastName") as TextFieldElement?
val addButton = document.querySelector("#addButton") as ButtonElement?
val grid = document.querySelector("#grid") as GridElement<Person>?
val initialPeople: Array<out Person> = emptyArray()
grid?.items = initialPeople
addButton?.addEventListener("click", {
// Read the new person's data
val person = Person(firstNameField?.value, lastNameField?.value)
// Add it to the items
if(grid != null){
val people = grid.items
grid.items = people.plus(person)
}
// Reset the form fields
firstNameField?.value = ""
lastNameField?.value = ""
})