2

这个问题是关于一个使用 Kotlin 前端插件的 Kotlin JS 项目。

我想使用Vaadin 组件库中的一些 UI 组件。

我对此有两个问题:

(1) 在 Kotlin JS 中包含 Web 组件的最佳方式是什么

=> 对于我的完整代码,请参阅下面的源链接。总而言之,相关细节是:

构建.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_gridDSL 被定义为一个自定义的 kotlinx.html 标签,它是不相关的代码。

(2) 我希望尽可能避免键入代码,asDynamic但是当我将其HTMLElement转换为 Vaadin 元素时,我得到 ClassCastExceptions (因为GridElementis undefined)。

例如我想写这样的东西:

val grid : GridElement = document.querySelector("#grid") as GridElement
grid.items = ... // vs grid.asDynamic().items which does work

这是我定义外部 GridElement 的方式

vaadin/按钮/Imports.kt

@file:JsModule("@vaadin/vaadin-grid")
@file:JsNonModule

package vaadin.grid

import org.w3c.dom.HTMLElement

abstract external class GridElement : HTMLElement {
    var items: Array<*> = definedExternally
}

构建/node_modules/@vaadin/vaadin-grid/src/vaadin-grid.js

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

源示例

跑步:

从 git repo 的根目录:

./gradlew 05-kt-frontend-vaadin:build && open 05-kt-frontend-vaadin/frontend.html
4

1 回答 1

2

我找到了答案

对于第一个问题

(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

    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 = ""
    })
于 2019-05-14T13:47:04.873 回答