在Kotlin js项目中使用Vaadin组件

时间:2019-04-26 08:35:36

标签: vaadin kotlin-js

这个问题是关于一个使用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
}

Source example

要运行:

从git repo的根开始:

...
customElements.define(GridElement.is, GridElement);
export { GridElement };

1 个答案:

答案 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 = ""
    })