golang跨平台Webview窗口与JavaScript双向绑定插件库webview的使用

Golang跨平台Webview窗口与JavaScript双向绑定插件库webview的使用

webview是一个用于构建现代跨平台GUI的微型跨平台webview库,支持Golang等多种语言绑定。它提供了HTML5 UI抽象层,并支持JavaScript与原生代码之间的双向绑定。

Golang绑定

Golang绑定已经从主仓库迁移到单独的仓库:webview/webview_go

基本使用示例

下面是一个完整的Golang webview示例,展示如何创建窗口并与JavaScript进行交互:

package main

import (
	"github.com/webview/webview"
)

func main() {
	// 创建webview窗口,debug模式关闭
	w := webview.New(false)
	defer w.Destroy() // 确保窗口被销毁

	// 设置窗口标题和大小
	w.SetTitle("Golang Webview示例")
	w.SetSize(800, 600, webview.HintNone)

	// 绑定Go函数到JavaScript
	w.Bind("sayHello", func(name string) string {
		return "Hello, " + name + " from Go!"
	})

	// 设置HTML内容并注入JavaScript
	html := `
		<!DOCTYPE html>
		<html>
		<head>
			<meta charset="UTF-8">
			<title>Webview测试</title>
		</head>
		<body>
			<h1>Golang Webview示例</h1>
			<button onclick="callGo()">调用Go函数</button>
			<p id="result"></p>
			
			<script>
				function callGo() {
					const result = sayHello("Webview用户");
					document.getElementById("result").innerText = result;
					
					// 从Go调用JavaScript函数
					window.external.invoke("alertUser", "JavaScript收到消息");
				}
				
				function alertUser(message) {
					alert(message);
				}
			</script>
		</body>
		</html>
	`

	w.SetHtml(html)

	// 处理从JavaScript调用的消息
	w.Bind("alertUser", func(message string) {
		w.Dispatch(func() {
			w.Eval(fmt.Sprintf(`alert("%s")`, message))
		})
	})

	// 运行主循环
	w.Run()
}

双向绑定详解

从Go调用JavaScript

使用w.Eval()方法可以执行任意JavaScript代码:

w.Eval(`console.log("Hello from Go!")`)

从JavaScript调用Go

  1. 首先在Go中绑定函数:
w.Bind("addNumbers", func(a, b int) int {
    return a + b
})
  1. 然后在JavaScript中调用:
const result = addNumbers(5, 3);
console.log(result); // 输出8

异步通信

webview支持异步通信模式:

w.Bind("asyncTask", func(prompt string) *webview.Promise {
    return webview.NewPromise(func(resolve, reject func(interface{})) {
        go func() {
            // 模拟耗时操作
            time.Sleep(2 * time.Second)
            resolve("操作完成: " + prompt)
        }()
    }
})

JavaScript端可以这样使用:

asyncTask("处理数据").then(result => {
    console.log(result);
}).catch(error => {
    console.error(error);
});

平台支持

webview支持以下平台:

平台 技术栈
Linux GTK, WebKitGTK
macOS Cocoa, WebKit
Windows Windows API, WebView2

高级功能

导航控制

w.Navigate("https://example.com") // 导航到URL
w.SetHtml("<h1>本地内容</h1>")    // 设置本地HTML内容

窗口控制

w.SetTitle("新标题")
w.SetSize(1024, 768, webview.HintNone)
w.SetFullscreen(true) // 全屏模式

剪贴板操作

text := w.GetClipboardText() // 获取剪贴板文本
w.SetClipboardText("要复制的文本") // 设置剪贴板文本

实际应用示例

下面是一个更完整的应用示例,展示了文件操作和更复杂的交互:

package main

import (
	"fmt"
	"io/ioutil"
	"log"
	
	"github.com/webview/webview"
)

func main() {
	w := webview.New(true) // 开启调试模式
	defer w.Destroy()

	w.SetTitle("文件编辑器")
	w.SetSize(800, 600, webview.HintNone)

	// 绑定文件操作函数
	w.Bind("readFile", func(path string) (string, error) {
		data, err := ioutil.ReadFile(path)
		if err != nil {
			return "", err
		}
		return string(data), nil
	})

	w.Bind("writeFile", func(path, content string) error {
		return ioutil.WriteFile(path, []byte(content), 0644)
	})

	// 绑定工具函数
	w.Bind("showAlert", func(message string) {
		w.Dispatch(func() {
			w.Eval(fmt.Sprintf(`alert("%s")`, message))
		})
	})

	html := `
	<!DOCTYPE html>
	<html>
	<head>
		<meta charset="UTF-8">
		<title>文件编辑器</title>
		<style>
			body { font-family: Arial; margin: 20px; }
			textarea { width: 100%; height: 400px; }
			.controls { margin: 10px 0; }
		</style>
	</head>
	<body>
		<h1>文件编辑器</h1>
		<div class="controls">
			<input type="file" id="fileInput">
			<button onclick="loadFile()">加载文件</button>
			<button onclick="saveFile()">保存文件</button>
		</div>
		<textarea id="editor"></textarea>
		
		<script>
			let currentFile = null;
			
			document.getElementById('fileInput').addEventListener('change', function(e) {
				currentFile = e.target.files[0].path;
			});
			
			async function loadFile() {
				if (!currentFile) {
					showAlert("请先选择文件");
					return;
				}
				
				try {
					const content = await readFile(currentFile);
					document.getElementById('editor').value = content;
					showAlert("文件加载成功");
				} catch (err) {
					showAlert("加载失败: " + err);
				}
			}
			
			async function saveFile() {
				if (!currentFile) {
					showAlert("请先选择文件");
					return;
				}
				
				const content = document.getElementById('editor').value;
				try {
					await writeFile(currentFile, content);
					showAlert("文件保存成功");
				} catch (err) {
					showAlert("保存失败: " + err);
				}
			}
		</script>
	</body>
	</html>
	`

	w.SetHtml(html)
	w.Run()
}

注意事项

  1. 在Windows上,用户需要安装WebView2运行时才能运行应用
  2. 对于Linux系统,需要安装GTK和WebKitGTK开发包
  3. 线程安全:所有UI操作必须在主线程执行,可以使用w.Dispatch()将操作调度到主线程

更多资源

这个库非常适合需要轻量级跨平台GUI解决方案的Golang项目,特别是那些希望利用现有Web技术构建界面的应用。


更多关于golang跨平台Webview窗口与JavaScript双向绑定插件库webview的使用的实战教程也可以访问 https://www.itying.com/category-94-b0.html

1 回复

更多关于golang跨平台Webview窗口与JavaScript双向绑定插件库webview的使用的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


Golang跨平台Webview与JavaScript双向绑定指南

Webview是一个轻量级的跨平台库,允许在Go应用程序中嵌入Web技术(HTML/CSS/JavaScript)构建用户界面。下面我将详细介绍如何使用webview库实现Go与JavaScript的双向通信。

安装webview库

首先安装webview库:

go get github.com/webview/webview

基本使用示例

package main

import (
	"github.com/webview/webview"
)

func main() {
	// 创建webview窗口
	w := webview.New(false)
	defer w.Destroy()
	
	// 设置窗口标题和大小
	w.SetTitle("Go Webview Demo")
	w.SetSize(800, 600, webview.HintNone)
	
	// 加载HTML内容
	w.SetHtml(`
		<!DOCTYPE html>
		<html>
		<head>
			<title>Webview Demo</title>
			<script>
				function callGoFunction() {
					// 调用Go函数
					window.external.invoke("Hello from JavaScript");
				}
				
				// 接收Go调用
				function updateContent(text) {
					document.getElementById("content").innerText = text;
				}
			</script>
		</head>
		<body>
			<h1>Webview Demo</h1>
			<p id="content">Initial content</p>
			<button onclick="callGoFunction()">Call Go Function</button>
		</body>
		</html>
	`)
	
	// 绑定Go函数供JS调用
	w.Bind("external", func(data string) {
		println("Received from JS:", data)
		// 调用JS函数
		w.Eval("updateContent('Updated from Go: " + data + "')")
	})
	
	// 运行窗口
	w.Run()
}

双向绑定详解

1. JavaScript调用Go函数

通过Bind方法将Go函数暴露给JavaScript:

w.Bind("external", func(data string) {
    println("Received from JS:", data)
})

在JavaScript中通过window.external.invoke()调用:

window.external.invoke("Some data");

2. Go调用JavaScript函数

使用Eval方法执行JavaScript代码:

w.Eval("updateContent('Hello from Go')")

3. 复杂数据交互

对于更复杂的数据结构,可以使用JSON进行序列化:

w.Bind("api", func(jsonData string) {
    // 解析JSON数据
    var data map[string]interface{}
    if err := json.Unmarshal([]byte(jsonData), &data); err != nil {
        println("Error parsing JSON:", err.Error())
        return
    }
    
    // 处理数据...
    
    // 返回响应
    response := map[string]interface{}{
        "status": "success",
        "data": "Processed data",
    }
    jsonResponse, _ := json.Marshal(response)
    w.Eval(fmt.Sprintf("handleResponse(%s)", string(jsonResponse)))
})

JavaScript端:

const data = {
    action: "getUser",
    id: 123
};
window.api(JSON.stringify(data));

function handleResponse(response) {
    console.log("Response from Go:", response);
}

高级特性

1. 同步调用

w.Bind("syncApi", func(data string) string {
    return "Processed: " + data
})

JavaScript端:

const result = window.syncApi("test");
console.log(result); // 输出: Processed: test

2. 多函数绑定

w.Bind("math", struct {
    Add func(a, b int) int `json:"add"`
    Sub func(a, b int) int `json:"sub"`
}{
    Add: func(a, b int) int { return a + b },
    Sub: func(a, b int) int { return a - b },
})

JavaScript端:

const sum = window.math.add(5, 3); // 8
const diff = window.math.sub(5, 3); // 2

实际应用示例:文件选择器

package main

import (
	"encoding/json"
	"fmt"
	"github.com/webview/webview"
)

func main() {
	w := webview.New(true)
	defer w.Destroy()
	
	w.SetTitle("File Picker Demo")
	w.SetSize(600, 400, webview.HintNone)
	
	w.SetHtml(`
		<!DOCTYPE html>
		<html>
		<head>
			<title>File Picker</title>
			<script>
				function pickFile() {
					window.backend.pickFile().then(path => {
						document.getElementById("filePath").innerText = path || "No file selected";
					});
				}
			</script>
		</head>
		<body>
			<h1>File Picker Demo</h1>
			<button onclick="pickFile()">Select File</button>
			<p>Selected file: <span id="filePath">None</span></p>
		</body>
		</html>
	`)
	
	w.Bind("backend", struct {
		PickFile func() string `json:"pickFile"`
	}{
		PickFile: func() string {
			// 这里可以调用原生文件选择对话框
			// 返回选择的文件路径
			return "/path/to/selected/file.txt"
		},
	})
	
	w.Run()
}

注意事项

  1. 线程安全:所有与webview的交互必须在主线程进行
  2. 性能:频繁的跨语言调用会影响性能,尽量减少调用次数
  3. 调试:可以启用调试工具 w.SetDebug(true)
  4. 跨平台差异:不同平台可能有细微的行为差异

通过webview库,你可以轻松创建跨平台的桌面应用,同时利用Go的强大后端能力和现代Web技术的前端表现力。

回到顶部