Go WASM:如何在 Go 中访问 DOM API?

1,495 阅读2分钟

我报名参加金石计划1期挑战——瓜分10万奖池,这是我的第4篇文章,点击查看活动详情

在上一篇文章中,我们讲解了如何通过 JavaScript 调用 Go 编写的函数。

如何通过 JavaScript 运行用 Go 编写的 WebAssembly 模块?

这一篇文章主要介绍如何在 Go 中访问 DOM API。

文章中的代码是使用上篇文章中的代码作为基础进行开发的,如果读不懂可以去看一下上一篇文章。

访问 DOM API

我会带大家做一个小案例,这里案例会使用 go 的 crypto/rand 库生成 0-10 万之间的真随机数,并将它放置到 p 标签中输入到页面上。

首先实现一个 myRand 函数,用来生成随机数。

func myRand() (*big.Int, error) {
	n, err := rand.Int(rand.Reader, big.NewInt(100000))
	return n, err
}

然后实现包裹函数。

func randWrapper() js.Func {
	return js.FuncOf(func(this js.Value, args []js.Value) interface{} {
		jsDoc := js.Global().Get("document")
		if !jsDoc.Truthy() {
			return "document is not defined"
		}
		containerEl := jsDoc.Call("getElementById", "rand-container")
		if !containerEl.Truthy() {
			return "rand-container is not find"
		}
		p := jsDoc.Call("createElement", "p")
		n, err := myRand()
		if err != nil {
			return "unable to generate random number"
		}
		p.Set("innerText", n.Text(10))
		containerEl.Call("append", p)
		return nil
	})
}

包裹函数中的代码主要就是在 Go 中访问 DOM API 的代码,我在这里给大家解释一下。

  • js.Global():该方法的返回值对应的是 JavaScript 的全局对象,也就是浏览器的 window 对象。
  • obj.Get("prop"):obj 代表 JavaScript 中的某个对象,Get 方法可以访问它的 key。就像是 JavaScript 中的 obj.prop。
  • obj.Truthy():该方法和 obj == true 类似,用来判断是否为 nil。
  • obj.Call("method"):该方法用来调用某个对象身上的方法,类似于 JavaScript 中的 obj.method()。我们也可以在后面传递其他参数,作为实际被调用方法的参数。
  • obj.Set("prop", value):obj 代表 JavaScript 中的某个对象,Set 方法可以设置它的属性。就像是 JavaScript 中的 obj.prop = value。值得一提的是,如果想获取或者设置全局变量,都可以通过 jsGlobal().Get/jsGlobal().Set 来操作。

解释完,上面的代码就不难理解了。

我们首先获取 document 对象,然后再去获取一个 id 为 rand-container 的元素。

再去创建一个 p 元素,调用 rand 方法获取随机数,把随机数设置为 p 的内容。

最后把 p 添加到 rand-container 元素中。

实现好这两个函数后,在 main 方法中将这个方法加入到全局对象中。

	js.Global().Set("addRand", randWrapper())

然后将代码编译为 wasm 模块。

来到 index.html 中,添加两个元素。

<div id="rand-container"></div>
<button onclick="addRand()">add rand</button>

启动服务器。

go run main.go

来到浏览器中看一下效果。

大功告成!