golang实现Go与JS值互操作插件库vert的使用

vert - Go与JS值互操作插件库

vert是一个用于在WebAssembly环境中实现Go与JavaScript值互操作的库。

安装

GOOS=js GOARCH=wasm go get github.com/norunners/vert

使用示例

基础类型互操作

package main

import "github.com/norunners/vert"

func main() {
    v := vert.ValueOf("Hello World!")
    // 将v作为JS值使用

    s := ""
    v.AssignTo(&s)
    // 将s作为Go值使用
}

结构体与对象互操作

package main

import "github.com/norunners/vert"

type Data struct {
    Message string
}

func main() {
    v := vert.ValueOf(Data{
        Message: "Hello World!",
    })
    // 转换为JS对象,如{"Message": "Hello World!"}

    d := &Data{}
    v.AssignTo(d)
}

带标签的结构体字段

package main

import "github.com/norunners/vert"

type Data struct {
    Message string `js:"msg"`  // 使用js标签指定JS中的字段名
}

func main() {
    v := vert.ValueOf(Data{
        Message: "Hello World!",
    })
    // 转换为JS对象,如{"msg": "Hello World!"}

    d := &Data{}
    v.AssignTo(d)
}

错误处理

package main

import "github.com/norunners/vert"

type Data struct {
    Message string
}

func main() {
    v := vert.ValueOf("Hello World!")

    d := &Data{}
    if err := v.AssignTo(d); err != nil {
        // 处理错误
    }
}

vert解决的问题

Go标准库中的syscall/js对Go与JS值互操作的支持有限:

  1. js.ValueOf不接受结构体类型,会导致panic
  2. js.Value类型不支持非基本Go值的Interface或赋值方法

vert扩展了syscall/js的功能,解决了这些限制。

完整示例

package main

import (
    "fmt"
    "github.com/norunners/vert"
)

// 定义带有JS标签的结构体
type User struct {
    ID      int    `js:"user_id"`
    Name    string `js:"username"`
    Email   string `js:"email"`
    Active  bool   `js:"is_active"`
}

func main() {
    // 创建Go结构体实例
    goUser := User{
        ID:     1,
        Name:   "John Doe",
        Email:  "john@example.com",
        Active: true,
    }

    // 转换为JS值
    jsValue := vert.ValueOf(goUser)
    // 这里jsValue可以传递给JS代码使用

    // 从JS值转换回Go结构体
    var newUser User
    if err := jsValue.AssignTo(&newUser); err != nil {
        fmt.Println("转换错误:", err)
        return
    }

    fmt.Printf("转换结果: %+v\n", newUser)
}

这个示例展示了如何:

  1. 定义一个带有JS字段标签的结构体
  2. 将Go结构体转换为JS值
  3. 将JS值转换回Go结构体
  4. 处理可能出现的错误

vert库使得在WebAssembly环境中Go与JavaScript之间的数据交换变得简单高效。


更多关于golang实现Go与JS值互操作插件库vert的使用的实战教程也可以访问 https://www.itying.com/category-94-b0.html

1 回复

更多关于golang实现Go与JS值互操作插件库vert的使用的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


Go与JS值互操作插件库vert的使用指南

vert是一个轻量级的Go插件库,专门用于简化Go与JavaScript之间的值互操作。下面我将详细介绍vert的使用方法,并提供相应的Go代码示例。

安装vert

首先,使用go get安装vert库:

go get github.com/norunners/vert

基本用法

1. 将Go值转换为JS值

package main

import (
	"github.com/norunners/vert"
	"syscall/js"
)

func main() {
	// 初始化JS运行时
	js.Global().Get("console").Call("log", "Starting vert demo...")

	// 基本类型转换
	goInt := 42
	jsValue := vert.ValueOf(goInt)
	js.Global().Get("console").Call("log", "Go int to JS:", jsValue)

	// 结构体转换
	type Person struct {
		Name string
		Age  int
	}
	p := Person{Name: "Alice", Age: 30}
	jsPerson := vert.ValueOf(p)
	js.Global().Get("console").Call("log", "Go struct to JS:", jsPerson)

	// 切片转换
	goSlice := []string{"apple", "banana", "cherry"}
	jsSlice := vert.ValueOf(goSlice)
	js.Global().Get("console").Call("log", "Go slice to JS:", jsSlice)
}

2. 将JS值转换为Go值

func jsToGo() {
	// 假设我们有一个JS对象
	jsObj := js.Global().Get("Object").New()
	jsObj.Set("name", "Bob")
	jsObj.Set("age", 25)
	jsObj.Set("hobbies", []interface{}{"reading", "swimming"})

	// 转换为Go的map
	var goMap map[string]interface{}
	vert.Assign(&goMap, jsObj)
	println("JS to Go map:", goMap["name"], goMap["age"])

	// 转换为结构体
	type JsPerson struct {
		Name    string   `js:"name"`
		Age     int      `js:"age"`
		Hobbies []string `js:"hobbies"`
	}
	var person JsPerson
	vert.Assign(&person, jsObj)
	println("JS to Go struct:", person.Name, person.Age)
}

高级特性

1. 处理复杂嵌套结构

type Address struct {
	Street string `js:"street"`
	City   string `js:"city"`
}

type User struct {
	Name    string   `js:"name"`
	Age     int      `js:"age"`
	Address Address  `js:"address"`
	Tags    []string `js:"tags"`
}

func handleComplexStruct() {
	// 创建JS复杂对象
	jsUser := js.Global().Get("Object").New()
	jsUser.Set("name", "Charlie")
	jsUser.Set("age", 35)
	
	jsAddress := js.Global().Get("Object").New()
	jsAddress.Set("street", "123 Main St")
	jsAddress.Set("city", "Metropolis")
	jsUser.Set("address", jsAddress)
	
	jsTags := vert.ValueOf([]string{"admin", "developer"})
	jsUser.Set("tags", jsTags)

	// 转换为Go结构体
	var user User
	vert.Assign(&user, jsUser)
	
	fmt.Printf("User: %+v\n", user)
}

2. 处理函数回调

func registerCallback() {
	// 将Go函数暴露给JS
	callback := js.FuncOf(func(this js.Value, args []js.Value) interface{} {
		// 将JS参数转换为Go值
		var goArgs []interface{}
		vert.Assign(&goArgs, args)
		fmt.Println("Callback received:", goArgs)
		return nil
	})
	
	js.Global().Set("goCallback", callback)
	
	// 在JS中可以这样调用: goCallback("hello", 123, {key: "value"})
}

3. 性能优化技巧

对于频繁调用的场景,可以预先创建转换器:

func optimizedConversion() {
	// 预编译转换器
	type Point struct {
		X int `js:"x"`
		Y int `js:"y"`
	}
	converter := vert.NewConverter(Point{})
	
	// 多次使用同一个转换器
	jsPoint := js.Global().Get("Object").New()
	jsPoint.Set("x", 10)
	jsPoint.Set("y", 20)
	
	var p1, p2 Point
	converter.Assign(&p1, jsPoint)
	converter.Assign(&p2, jsPoint)
	
	fmt.Println("Optimized conversion:", p1, p2)
}

注意事项

  1. vert不支持循环引用的数据结构
  2. 转换大型数据结构时注意性能影响
  3. 结构体字段标签js:"fieldName"是可选的,但建议显式声明
  4. 处理JS的null/undefined时,Go中对应的零值

完整示例

package main

import (
	"fmt"
	"syscall/js"
	"github.com/norunners/vert"
)

func main() {
	// 等待前端加载完成
	done := make(chan struct{})
	
	// 注册Go函数供JS调用
	js.Global().Set("goAdd", js.FuncOf(add))
	
	// 演示JS调用Go函数
	js.Global().Call("eval", `
		console.log("Calling Go function from JS...");
		const result = goAdd(5, 7);
		console.log("Result from Go:", result);
	`)
	
	<-done
}

func add(this js.Value, args []js.Value) interface{} {
	var a, b int
	vert.Assign(&a, args[0])
	vert.Assign(&b, args[1])
	
	sum := a + b
	return vert.ValueOf(sum)
}

vert库通过简单的API简化了Go和JS之间的数据交换,特别适合WebAssembly场景。使用时注意类型映射关系,对于复杂场景可以结合性能优化技巧提升效率。

回到顶部