在Kotlin中使用Javascript库

时间:2016-09-20 08:06:02

标签: kotlin

我上次使用Kotlin的时间是2015年12月,当时我用它来solve a couple of Project Euler problems.

这次我想尝试与Javascript的互操作性。现在我的问题是,我们如何在Kotlin中导入/使用现有的Javascript库? 我看到有些人使用native关键字,我只想简要解释一下。

3 个答案:

答案 0 :(得分:6)

不再有native个关键字,还有@native个注释。目前,它的工作解决方案,您可以使用它与Kotlin编译器的1.0.x分支。但是,我们将弃用此注释以支持extern注释,因此请准备最终为1.1.x分支重写代码。

当您在类或顶级函数上放置@native注释时,会发生两件事:

  1. 它的主体未编译为JavaScript。
  2. 编译器直接引用此类或函数,没有包名称和修改。
  3. 我认为通过提供JavaScript库的示例更容易解释:

    function A(x) {
        this.x = x;
        this.y = 0;
    }
    A.prototype.foo = function(z) {
        return this.x + this.y + z;
    }
    
    function min(a, b) {
        return a < b ? a : b;
    }
    

    和相应的Kotlin声明

    @native class A(val x: Int) {
        var y: Int = noImpl
    
        fun foo(z: Int): Int = noImpl
    }
    
    @native fun min(a: Int, b: Int): Int = noImpl
    

    请注意noImpl是一个特殊的占位符,因为非抽象函数需要主体和非抽象属性需要初始值设定项。顺便说一句,当我们用@native替换extern时,我们将摆脱这个noImpl

    与JS库互操作的另一个方面是通过模块系统包含库。对不起,我们现在没有任何解决方案(但很快就会发布)。见proposal。您可以对node.js / CommonJS使用以下解决方法:

    @native interface ExternalModule {
        fun foo(x: Int)
    }
    
    @native fun require(name: String): dynamic = noImpl
    
    fun main(args: Array<String>) {
       val module: ExternalModule = require("externalModule")
       module.foo(123)
    }
    

    其中外部模块声明如下

    function foo(x) {
        return x + 1;
    }
    module.exports = { foo : foo };
    

答案 1 :(得分:2)

我添加了一个简单的准系统项目,作为如何做Kotlin2Js的一个例子。

https://bitbucket.org/mantis78/gradle4kotlin2js/src

这是作为主要配方的gradle文件。

group 'org.boonhighendtech'
version '1.0-SNAPSHOT'

buildscript {
    ext.kotlin_version = '1.1.2-5'
    repositories {
        maven { url 'http://dl.bintray.com/kotlin/kotlin-dev/' }
        mavenCentral()
    }
    dependencies {
        classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
    }
}

apply plugin: 'kotlin2js'

repositories {
    maven { url 'http://dl.bintray.com/kotlin/kotlin-dev/' }
    mavenCentral()
}

dependencies {
    compile "org.jetbrains.kotlin:kotlin-stdlib-js:$kotlin_version"
}

build {
    outputs.dir("web/")
}

build.doLast {
    copy {
        from 'src/main/webapp'
        into 'web/'
        include '**/*.html'
        include '**/*.js'
        include '**/*.jpg'
        include '**/*.png'
    }

    configurations.compile.each { File file ->
        copy {
            includeEmptyDirs = false

            from zipTree(file.absolutePath)
            into "${projectDir}/web"
            include { fileTreeElement ->
                def path = fileTreeElement.path
                path.endsWith(".js") && (path.startsWith("META-INF/resources/") || !path.startsWith("META-INF/"))
            }
        }
    }
}

clean.doLast {
    file(new File(projectDir, "/web")).deleteDir()
}

compileKotlin2Js {
    kotlinOptions.outputFile = "${projectDir}/web/output.js"
    kotlinOptions.moduleKind = "amd"
    kotlinOptions.sourceMap = true
}

首先,您可以指定一个动态变量,然后基本上像编码JavaScript一样对其进行动态编码。

e.g。

val jQuery: dynamic = passedInJQueryRef
jQuery.whateverFunc()

但是如果您打算输入它,那么您需要将类型引入外部库。一种方法是通过https://github.com/DefinitelyTyped/DefinitelyTyped

使用相对广泛的typedef库

在那里找到ts.d,然后运行ts2kt(https://github.com/Kotlin/ts2kt)来获取你的Kotlin文件。这通常会让你到那里。偶尔,某些转换效果不佳。您必须手动修复转换。例如。 snapsvg的snapsvg.attr()调用接收“{}”,但它被转换为一些奇怪的接口。

fun attr(params: `ts$2`): Snap.Element

我用

代替了它
 fun attr(params: Json): Snap.Element

它就像一个魅力。

答案 2 :(得分:0)

Kotlin 1.1引入了external修饰符,可以用来声明直接用JS编写的函数和类,参见http://kotlinlang.org/docs/reference/js-interop.html