www.zhblog.net

Go 调用 JavaScript


Go 社区中有不少人直言,Go 支持 WebAssembly 就是要取代 Javascript,虽然我个人觉得,这就姑且当成是个崇高的理想就好,不过这也表示,在编译为 WebAssembly 之后,可以调用 JavaScript 或操作 DOM,自然也是 Go 应该照料之事,为此,Go 1.11 提供了个实验性的syscall/js包来负责这项任务。

Go 与 JavaScript 毕竟是两个不同的语言,各拥有不同的数据类型与结构,因而必须先知道,两个语言间的类型如何对应,这主要定义在syscall/js包的 js.go 中。

例如,js.Value结构代表 JavaScript 中的值,定义有GetSet方法,可以对对象上的特性访问;若想访问的对象实际上是数组,可以使用IndexSetIndex并指定索引;若对象是个函数,可以使用Invoke指定实参来调用,若想调用的是对象上的方法,可以使用Call指定方法名与调用时的实参等。

在 js.go 中预先定义了一些js.Value的实例,可以透过公开的js.Undefinedjs.Nulljs.Global等函数调用获取。

因而,你可以开启〈哈啰!WebAssembly!〉中谈到的 wasm_exec.html,在<button onClick="run();" id="runButton" disabled>Run</button>标签底下加上<div id="c1">Hello, WebAssembly!</div>

<!doctype html>
<!--
Copyright 2018 The Go Authors. All rights reserved.
Use of this source code is governed by a BSD-style
license that can be found in the LICENSE file.
-->
<html>

<head>
    <meta charset="utf-8">
    <title>Go wasm</title>
</head>

<body>
    <script src="wasm_exec.js"></script>
    <script>
        WebAssembly API 等... 略
    </script>

    <button onClick="run();" id="runButton" disabled>Run</button>
    <div id="c1">Hello, WebAssembly!</div>
</body>

</html>

若想编写 Go 来获取对应的 DOM 对象,并在控制台显示innerHTML特性值,可以如下编写:

package main

import "syscall/js"

func main() {
    window := js.Global()                       // 获取全局的 window
    doc := window.Get("document")               // 相当于 window.document
    c1 := doc.Call("getElementById", "c1")      // 相当于 document.getElementById('c1')
    innerHTML := c1.Get("innerHTML").String()   // 相当于 c1.innerHTML
    println(innerHTML)
}

这边特意使用数个变量,代逐一对照获取的各是哪个 JavaScript 值,实际上当然可以直接写成底下:

package main

import "syscall/js"

func main() {
    innerHTML :=
        js.Global().
            Get("document").
            Call("getElementById", "c1").
            Get("innerHTML").
            String()
    println(innerHTML)
}

也就是相当于在 JavaScript 中编写document.getElementById("c1").innerHTML;在编译为 WebAssembly、使用浏览器连线至网页之后,按下 Run 按钮,就可以获取目标c1innerHTML

Go 调用 JavaScript

类似地,如果想在 Go 中调用浏览器提供的alert全局函数,可以如下编写:

package main

import "syscall/js"

func main() {
    alert := js.Global().Get("alert")
    // 相当于 alert('Hello, WebAssembly!')
    alert.Invoke("Hello, WebAssembly!")
}

在编译为 WebAssembly、使用浏览器连线至网页之后,按下 Run 按钮,会令浏览器出现警告对话框:

Go 调用 JavaScript

因此,如果有个自定义的 JavaScript 函数,而你想在 Go 中调用它,就是看看,那个函数是在哪个对象之上,想办法获取该对象,之后就可以加以调用了,例如:

<!doctype html>
<!--
Copyright 2018 The Go Authors. All rights reserved.
Use of this source code is governed by a BSD-style
license that can be found in the LICENSE file.
-->
<html>

<head>
    <meta charset="utf-8">
    <title>Go wasm</title>
</head>

<body>
    <script src="wasm_exec.js"></script>
    <script>
        WebAssembly API 等... 略
    </script>
    <script>
        function hi_wasm(name) {
            document.getElementById('c1').innerHTML = 'Hi, ' + name;
        }
    </script>

    <button onClick="run();" id="runButton" disabled>Run</button>
    <div id="c1">Hello, WebAssembly!</div>
</body>

</html>

在上例中,hi_wasm函数实际上是window的一个特性,因此在 Go 中可以这么调用:

package main

import "syscall/js"

func main() {
    hi_wasm := js.Global().Get("hi_wasm")
    hi_wasm.Invoke("WebAssembly")
}

在编译为 WebAssembly、使用浏览器连线至网页之后,按下 Run 按钮,就会将c1的文本改变为 Hi, WebAssembly。

如果自定义的 JavaScript 函数有返回值的话,那会成为Invoke方法的返回值,然而记得,JavaScript 的值在 Go 中是对应至js.ValueInvoke的返回类型正是js.Value,获取之后,就看它代表着什么 JavaScript 值(数值、字符串、数组、函数?),再进一步操作。


展开阅读全文

评论

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 心情