2016-09-20 107 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 

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