2016-09-20 112 views
8

我最后一次使用科特林是2015年12月,当我把它用来solve a couple of Project Euler problems.使用JavaScript库在科特林

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

+1

可能是很好的阅读起点的地方:https://discuss.kotlinlang.org/c/javascript,Kotlin Slack #javascript频道,以及这个其他的SO问题http://stackoverflow.com/questions/36250680/写-javascript-applications-kotlin –

回答

6

有没有native关键字了,有@native注释。目前,它是工作解决方案,您可以将它与Kotlin编译器的1.0.x分支结合使用。不过,我们将会弃用这个注解来支持extern注解,所以请准备好最终为1.1.x分支重写您的代码。

当你把@native注解一个类或一个顶级功能,发生两件事情:

  1. 它的身体不能编译为JavaScript。
  2. 编译器直接引用此类或函数,没有包名称和变形。

我觉得它更容易通过提供一个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; 
} 

和相应的科特林声明

@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是的需要的,因为一个特殊的占位符非抽象函数所需的主体和非抽象属性需要初始化器。顺便说一下,当我们用extern代替@native时,我们将摆脱这个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 }; 
+0

哇,非常专业的答案!谢谢 :) –

-1

我添加了一个简单的准系统项目,作为如何执行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 
} 

首先,您可以指定一个动态变量,然后根据代码动态地编写代码。

例如

val jQuery: dynamic = passedInJQueryRef 
jQuery.whateverFunc() 

但是,如果您的意图是要输入它,那么您需要将类型引入外部库。一种方法是利用相对广泛的typedefs库https://github.com/DefinitelyTyped/DefinitelyTyped

找到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 

取代它,它就像一个魅力。