发布于 2026-01-06 3 阅读
0

使用 (Tiny)Go 和 WebAssembly 创建开发者的离线页面 🦄💡✨ 代码 代码 代码

使用 (Tiny)GO 和 WebAssembly 创建开发者的离线页面 🦄💡✨

代码 代码 代码

开发者的离线页面很有趣,我们用 Rust 和 WebAssembly 实现了它

Go语言很简单。我们能用Go和WebAssembly实现吗?答案是肯定的……

我这里有一个示例应用程序。如果您想从头开始编写,请查看此教程

如果你只想查看源代码,请查看这个分支

代码 代码 代码

go/main.go我们首先在.中导入“syscall/js”和“fmt” 。

“syscall/js”包在使用js/WASM架构时提供对WebAssembly宿主环境的访问。它的API基于JavaScript语义。此包处于实验阶段。🦄🦄

package main 


import( 
    "fmt"
    "syscall/js"
)
Enter fullscreen mode Exit fullscreen mode

添加一些全局可用的变量,这些变量是我们可能需要在从 JavaScript 或浏览器调用函数时使用的变量。

var (
    isPainting bool
    x          float64
    y          float64
    ctx        js.Value
    color      string
)
Enter fullscreen mode Exit fullscreen mode

我们将手动在 . 中添加 canvas 元素out/index.html

<canvas id="canvas"> </canvas>
Enter fullscreen mode Exit fullscreen mode

删除函数Hello World内部的这行代码main,并替换为以下代码。

document从浏览器中获取对象。使用我们刚才添加的元素documentcanvas

我们可以通过使用syscall/jsAPI​​来实现这一点。

func main() {

    doc := js.Global().Get("document")
    canvasEl := doc.Call("getElementById", "canvas")
}

Enter fullscreen mode Exit fullscreen mode

API很简单。从JavaScript的全局命名空间获取文档。

在文档内部通过 ID 调用 canvas 元素。

我们将设置一些属性,例如canvasEl宽度、高度。我们还将获取画布的context

bodyW := doc.Get("body").Get("clientWidth").Float()
bodyH := doc.Get("body").Get("clientHeight").Float()
canvasEl.Set("width", bodyW)
canvasEl.Set("height", bodyH)
ctx = canvasEl.Call("getContext", "2d")
Enter fullscreen mode Exit fullscreen mode

然后我们将定义三个事件监听器mousedown| mousemove|mouseupcanvasElement

鼠标向下

当我们点击鼠标时,绘画就开始了。

startPaint := js.FuncOf(func(this js.Value, args []js.Value) interface{} {
    e := args[0]
    isPainting = true

    x = e.Get("pageX").Float() - canvasEl.Get("offsetLeft").Float()
    y = e.Get("pageY").Float() - canvasEl.Get("offsetTop").Float()
    return nil
})


canvasEl.Call("addEventListener", "mousedown", startPaint)

Enter fullscreen mode Exit fullscreen mode

请注意,返回 nil 非常重要,否则程序将无法编译。

整个 API 都是基于Reflect API 的

鼠标移动

我们将定义绘制函数。


paint := js.FuncOf(func(this js.Value, args []js.Value) interface{} {
    if isPainting {
        e := args[0]
        nx := e.Get("pageX").Float() - canvasEl.Get("offsetLeft").Float()
        ny := e.Get("pageY").Float() - canvasEl.Get("offsetTop").Float()

        ctx.Set("strokeStyle", color)
        ctx.Set("lineJoin", "round")
        ctx.Set("lineWidth", 5)

        ctx.Call("beginPath")
        ctx.Call("moveTo", nx, ny)
        ctx.Call("lineTo", x, y)
        ctx.Call("closePath")

        // actually draw the path*
        ctx.Call("stroke")

        // Set x and y to our new coordinates*
        x = nx
        y = ny
    }
    return nil
})
canvasEl.Call("addEventListener", "mousemove", paint)
Enter fullscreen mode Exit fullscreen mode

鼠标向上

最后,我们将定义当鼠标抬起事件触发时调用的退出方法。



    exit := js.FuncOf(func(this js.Value, args []js.Value) interface{} {
        isPainting = false
        return nil
    })

    canvasEl.Call("addEventListener", "mouseup", exit)
Enter fullscreen mode Exit fullscreen mode

最后,我们将定义颜色选择器。在 `<head>` 标签中添加一个 `colors` div 元素out/index.html,并添加必要的 CSS 代码。

<style>
     .color {
            display: inline-block;
            width: 50px;
            height: 50px;
            border-radius: 50%;
            cursor: pointer;
            margin: 10px;
       }
</style>

<div id="colors></div>
Enter fullscreen mode Exit fullscreen mode

我们将颜色定义为一个数组。然后遍历该数组中的颜色,并创建一个颜色样本节点。为该颜色样本添加一个点击事件监听器。


divEl := doc.Call("getElementById", "colors")

    colors := [6]string {"#F4908E", "#F2F097", "#88B0DC", "#F7B5D1", "#53C4AF", "#FDE38C"}

    for _, c := range colors {  
        node := doc.Call("createElement", "div")
        node.Call("setAttribute","class", "color")
        node.Call("setAttribute", "id", c)
        node.Call("setAttribute","style", fmt.Sprintf("background-color: %s", c))

        setColor := js.FuncOf(func(this js.Value, args []js.Value) interface{} {
                e := args[0]
                color = e.Get("target").Get("id").String()
                return nil;
        })


        node.Call("addEventListener", "click", setColor)


        divEl.Call("appendChild", node)


    }

Enter fullscreen mode Exit fullscreen mode

就是这样。

现在运行以下命令启动 Web 服务器go run webServer.go

使用以下方式将 Go 编译成 WebAssembly 模块

tinygo build -o ./out/main.wasm -target wasm -no-debug ./go/main.go
Enter fullscreen mode Exit fullscreen mode

访问localhost:8080,即可看到超棒的画布,供您尽情发挥创意🦄。

💡 生成的WebAssembly模块只有52KB。TinyGo太棒了,它能生成体积小得惊人的 WebAssembly 二进制文件。它是如何做到的呢?敬请期待本系列的下一篇文章。💡

注意:请使用 Firefox 或 Firefox Nightly 版本。Chrome 浏览器有时会崩溃。

更多优化❤️

移除fmt导入语句,替换fmt.Sprintf为普通的字符串拼接,这样可以再节省26KB 的空间。请在此处查看提交记录

感谢Justin Clift分享这个小技巧 :)

你喜欢 Rust 吗?点击这里了解如何使用 Rust 开发 WebAssembly。

希望这篇文章能激励你开启精彩的 WebAssembly 之旅。如果你有任何问题、建议,或者觉得我遗漏了什么,欢迎留言。

你可以在推特上关注我。

如果你喜欢这篇文章,请点赞或留言。❤️

谢谢

文章内容

文章来源:https://dev.to/sendilkumarn/create-dev-s-offline-page-with-tiny-go-and-web assembly-9n6