webview2

package module
v1.0.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Dec 18, 2024 License: MIT Imports: 16 Imported by: 0

README

🚀 go-win-webview2

⚠️ 系统要求: 本项目仅支持 Windows 操作系统

WebView2 Logo

Stars Forks Issues License Platform Go Version

快速开始特性安装使用示例API参考性能优化错误处理最佳实践

🌟 基于Microsoft Edge WebView2的Go语言界面开发包,提供简单易用的API接口。本项目基于webview/webview | jchv/go-webview2改进,专注于Windows平台的WebView2功能增强。

📦 快速开始

✨ 特性

  • 🎯 完全兼容Webview2的API
  • 💪 专注于Windows平台WebView2的增强功能
  • 🔌 简单易用的Go语言接口
  • 🛡️ 稳定可靠的性能表现
  • 🎨 丰富的界面定制选项
  • 🔒 内置安全机制
  • 🚀 快速的启动速度
  • 📦 零依赖纯静态库

🎯 主要功能

窗口控制
  • 🎨 丰富的窗口操作
    • 无边框窗口
    • 窗口大小调整
    • 全屏切换
    • 窗口置顶
    • 透明度控制
    • 窗口最大化/最小化/还原
    • 窗口居中
    • 自定义图标
    • 窗口样式定制
浏览器功能
  • 🌐 完整的Web功能
    • HTML/CSS/JavaScript支持
    • 双向通信机制
    • Cookie管理
    • 缓存控制
    • 页面导航(前进/后退/刷新)
    • 开发者工具
    • 打印功能(直接打印/PDF导出)
事件监听
  • 📡 丰富的回调
    • 页面加载状态
    • URL变化
    • 标题变化
    • 全屏状态变化
扩展功能
  • ⚡ WebSocket支持
    • 内置WebSocket服务器
    • 双向实时通信
    • 消息处理回调
  • 🔌 JavaScript Hook机制
    • 前置/后置处理钩子
    • 优先级控制
    • 灵活的脚本注入
热键支持
  • ⌨️ 全局热键系统
    • 支持组合键
    • 字符串格式配置
    • 动态注册/注销

📦 安装

前置要求
  • Windows 10+ 操作系统
  • Go 1.16+
  • Microsoft Edge WebView2 Runtime

💡 Windows 10+系统通常已预装WebView2 runtime。如果没有,可以从Microsoft官网下载安装。

通过go get安装
go get github.com/yuaotian/go-win-webview2

🎮 使用示例

基础示例
package main

import "github.com/yuaotian/go-win-webview2"

func main() {
    w := webview2.NewWithOptions(webview2.WebViewOptions{
        Debug: true,
        WindowOptions: webview2.WindowOptions{
            Title:  "基础示例",
            Width:  800,
            Height: 600,
            Center: true,
        },
    })
    defer w.Destroy()
    
    w.Navigate("https://example.com")
    w.Run()
}
高级功能示例

JS Hook Demo
JS Hook Architecture
JS Hook 运行演示

package main

import (
    "log"
    "github.com/yuaotian/go-win-webview2"
)

func main() {
    // 创建带选项的窗口
    w := webview2.NewWithOptions(webview2.WebViewOptions{
        Debug: true,
        AutoFocus: true,
        WindowOptions: webview2.WindowOptions{
            Title:       "高级示例",
            Width:       1024,
            Height:      768,
            Center:      true,
            Frameless:   false,
            Fullscreen:  false,
            AlwaysOnTop: false,
        },
    })
    defer w.Destroy()

    // 注册热键
    w.RegisterHotKeyString("Ctrl+Alt+Q", func() {
        log.Println("退出应用...")
        w.Terminate()
    })

    // 设置事件监听
    w.OnLoadingStateChanged(func(isLoading bool) {
        if isLoading {
            log.Println("页面加载中...")
        } else {
            log.Println("页面加载完成!")
        }
    })

    // 启用WebSocket
    if err := w.EnableWebSocket(8080); err != nil {
        log.Printf("WebSocket启动失败: %v", err)
    }

    // 添加JavaScript钩子
    w.AddJSHook(&webview2.BaseJSHook{
        HookType: webview2.JSHookBefore,
        Handler: func(script string) string {
            log.Printf("执行脚本: %s", script)
            return script
        },
    })

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

    w.Navigate("https://example.com")
    w.Run()
}
WebSocket通信示例
// 设置WebSocket消息处理器
w.OnWebSocketMessage(func(message string) {
    log.Printf("收到WebSocket消息: %s", message)
    // 发送响应
    w.SendWebSocketMessage(`{"type":"response","data":"消息已收到"}`)
})

// 在JavaScript中使用WebSocket
w.Eval(`
    window._webSocket.send(JSON.stringify({
        type: 'message',
        data: 'Hello from JavaScript!'
    }));
`)
事件监听示例
// 监听页面加载状态
w.OnLoadingStateChanged(func(isLoading bool) {
    if isLoading {
        log.Println("页面加载中...")
    } else {
        log.Println("页面加载完成!")
    }
})

// 监听URL变化
w.OnURLChanged(func(url string) {
    log.Printf("页面URL已变更: %s", url)
})

// 监听标题变化
w.OnTitleChanged(func(title string) {
    log.Printf("页面标题已变更: %s", title)
    w.SetTitle(title) // 自动更新窗口标题
})

// 监听全屏状态变化
w.OnFullscreenChanged(func(isFullscreen bool) {
    log.Printf("全屏状态已变更: %v", isFullscreen)
})
热键绑定示例
// 注册基本热键
w.RegisterHotKeyString("Ctrl+Q", func() {
    log.Println("退出应用...")
    w.Terminate()
})

// 注册功能热键
w.RegisterHotKeyString("F11", func() {
    log.Println("切换全屏...")
    // 在这里保存当前状态
    isFullscreen := false // 实际应用中需要跟踪此状态
    isFullscreen = !isFullscreen
    w.SetFullscreen(isFullscreen)
})

// 注册组合键
w.RegisterHotKeyString("Ctrl+Shift+D", func() {
    log.Println("打开开发者工具...")
    w.OpenDevTools()
})

// 注册窗口控制热键
w.RegisterHotKeyString("Ctrl+M", func() {
    log.Println("最小化窗口...")
    w.Minimize()
})
JavaScript交互示例
// 绑定Go函数到JavaScript
w.Bind("sayHello", func(name string) string {
    return fmt.Sprintf("Hello, %s!", name)
})

// 绑定带错误处理的函数
w.Bind("divide", func(a, b float64) (float64, error) {
    if b == 0 {
        return 0, errors.New("除数不能为零")
    }
    return a / b, nil
})

// 绑定异步操作
w.Bind("fetchData", func() interface{} {
    // 模拟异步操作
    time.Sleep(1 * time.Second)
    return map[string]interface{}{
        "status": "success",
        "data": []string{"item1", "item2", "item3"},
    }
})

// 在JavaScript中调用
w.Eval(`
    // 调用简单函数
    sayHello("World").then(result => {
        console.log(result); // 输出: Hello, World!
    });

    // 调用带错误处理的函数
    divide(10, 2).then(result => {
        console.log("10 ÷ 2 =", result);
    }).catch(err => {
        console.error("计算错误:", err);
    });

    // 调用异步函数
    fetchData().then(result => {
        console.log("获取的数据:", result);
    });
`)
窗口样式定制示例

JS Hook Architecture
自定义窗口样式示例

基础窗口配置
// 创建自定义样式的窗口
w := webview2.NewWithOptions(webview2.WebViewOptions{
    Debug: true,
    WindowOptions: webview2.WindowOptions{
        Title:              "现代化窗口示例",
        Width:              1024,
        Height:             768,
        Center:            true,
        Frameless:         true,  // 无边框模式
        AlwaysOnTop:       false,
        DisableContextMenu: false,
        DefaultBackground: "#ffffff",
        Opacity:           1.0,
        Resizable:         true,
    },
})
窗口状态管理
// 定义窗口状态结构
type WindowState struct {
    sync.Mutex
    isFullscreen bool
    isMaximized  bool
    isMinimized  bool
    opacity      float64
    lastWidth    int
    lastHeight   int
    lastX        int
    lastY        int
}

// 初始化窗口状态
state := &WindowState{
    opacity: 1.0,
}
自定义标题栏和窗口控制
// 注入HTML和CSS样式
w.SetHtml(`
<!DOCTYPE html>
<html>
<head>
    <style>
        :root {
            --primary-color: #2196F3;
            --hover-color: #1976D2;
            --bg-color: #ffffff;
            --text-color: #333333;
            --title-bar-height: 36px;
            --resize-area: 8px;
        }

        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
        }

        body { 
            margin: 0;
            font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto;
            background: var(--bg-color);
            color: var(--text-color);
            overflow: hidden;
            user-select: none;
        }

        .title-bar {
            -webkit-app-region: drag;
            position: fixed;
            top: 0;
            left: 0;
            right: 0;
            height: var(--title-bar-height);
            background: var(--primary-color);
            color: white;
            display: flex;
            justify-content: space-between;
            align-items: center;
            padding: 0 16px;
            z-index: 9998;
            box-shadow: 0 2px 4px rgba(0,0,0,0.1);
        }

        .controls {
            -webkit-app-region: no-drag;
            display: flex;
            align-items: center;
            gap: 4px;
        }

        .ctrl-btn {
            border: none;
            background: none;
            color: white;
            width: 46px;
            height: var(--title-bar-height);
            cursor: pointer;
            font-size: 14px;
            transition: all 0.2s ease;
        }

        .ctrl-btn:hover {
            background: var(--hover-color);
        }

        .close-btn:hover {
            background: #e81123 !important;
        }

        .resize-handle {
            position: fixed;
            z-index: 9999;
        }

        .resize-handle.top { top: 0; left: var(--resize-area); right: var(--resize-area); height: var(--resize-area); cursor: n-resize; }
        .resize-handle.right { top: var(--resize-area); right: 0; bottom: var(--resize-area); width: var(--resize-area); cursor: e-resize; }
        .resize-handle.bottom { bottom: 0; left: var(--resize-area); right: var(--resize-area); height: var(--resize-area); cursor: s-resize; }
        .resize-handle.left { top: var(--resize-area); left: 0; bottom: var(--resize-area); width: var(--resize-area); cursor: w-resize; }
        .resize-handle.top-left { top: 0; left: 0; width: var(--resize-area); height: var(--resize-area); cursor: nw-resize; }
        .resize-handle.top-right { top: 0; right: 0; width: var(--resize-area); height: var(--resize-area); cursor: ne-resize; }
        .resize-handle.bottom-left { bottom: 0; left: 0; width: var(--resize-area); height: var(--resize-area); cursor: sw-resize; }
        .resize-handle.bottom-right { bottom: 0; right: 0; width: var(--resize-area); height: var(--resize-area); cursor: se-resize; }
    </style>
</head>
<body>
    <div class="title-bar">
        <div class="title">现代化窗口示例</div>
        <div class="controls">
            <button class="ctrl-btn" onclick="window.minimize()" title="最小化">─</button>
            <button class="ctrl-btn" onclick="window.toggleMaximize()" title="最大化">□</button>
            <button class="ctrl-btn close-btn" onclick="window.closeWindow()" title="关闭">×</button>
        </div>
    </div>
    <div id="content">
        <!-- 页面内容 -->
    </div>
</body>
</html>
`)
窗口控制函数绑定
// 绑定窗口控制函数
func bindWindowControls(w webview2.WebView, state *WindowState) {
    // 最小化
    w.Bind("minimize", func() {
        state.Lock()
        state.isMinimized = true
        state.Unlock()
        w.Minimize()
    })

    // 最大化切换
    w.Bind("toggleMaximize", func() {
        state.Lock()
        defer state.Unlock()

        state.isMaximized = !state.isMaximized
        if state.isMaximized {
            // 保存当前窗口位置和大���
            var rect w32.Rect
            w32.GetWindowRect(w32.Handle(w.Window()), &rect)
            state.lastX = int(rect.Left)
            state.lastY = int(rect.Top)
            state.lastWidth = int(rect.Right - rect.Left)
            state.lastHeight = int(rect.Bottom - rect.Top)
            w.Maximize()
        } else {
            w.Restore()
        }
    })

    // 关闭窗口
    w.Bind("closeWindow", func() {
        w.Terminate()
    })

    // 窗口拖动
    w.Bind("startDragging", func() {
        hwnd := w.Window()
        w32.ReleaseCapture()
        w32.SendMessage(w32.Handle(uintptr(hwnd)), w32.WMNCLButtonDown, w32.HTCaption, 0)
    })

    // 窗口大小调整
    w.Bind("startResizing", func(edge string) {
        hwnd := w.Window()
        w32.ReleaseCapture()
        var hitTest uintptr
        switch edge {
        case "top":
            hitTest = w32.HTTop
        case "right":
            hitTest = w32.HTRight
        case "bottom":
            hitTest = w32.HTBottom
        case "left":
            hitTest = w32.HTLeft
        case "topLeft":
            hitTest = w32.HTTopLeft
        case "topRight":
            hitTest = w32.HTTopRight
        case "bottomLeft":
            hitTest = w32.HTBottomLeft
        case "bottomRight":
            hitTest = w32.HTBottomRight
        }
        w32.SendMessage(w32.Handle(uintptr(hwnd)), w32.WMNCLButtonDown, hitTest, 0)
    })
}
注册快捷键
// 注册窗口控制快捷键
func registerHotkeys(w webview2.WebView, state *WindowState) {
    // Ctrl+Q 退出
    w.RegisterHotKeyString("Ctrl+Q", func() {
        w.Terminate()
    })

    // Ctrl+M 最小化
    w.RegisterHotKeyString("Ctrl+M", func() {
        state.Lock()
        state.isMinimized = !state.isMinimized
        state.Unlock()
        if state.isMinimized {
            w.Minimize()
        } else {
            w.Restore()
        }
    })

    // F11 全屏
    w.RegisterHotKeyString("F11", func() {
        state.Lock()
        state.isFullscreen = !state.isFullscreen
        state.Unlock()
        w.SetFullscreen(state.isFullscreen)
    })
}
JavaScript事件处理
// 添加到HTML中的JavaScript代码
document.addEventListener('DOMContentLoaded', function() {
    var titleBar = document.querySelector('.title-bar');
    
    // 添加窗大小调整句柄
    var resizeAreas = [
        { class: 'top', edge: 'top' },
        { class: 'right', edge: 'right' },
        { class: 'bottom', edge: 'bottom' },
        { class: 'left', edge: 'left' },
        { class: 'top-left', edge: 'topLeft' },
        { class: 'top-right', edge: 'topRight' },
        { class: 'bottom-left', edge: 'bottomLeft' },
        { class: 'bottom-right', edge: 'bottomRight' }
    ];

    resizeAreas.forEach(area => {
        var handle = document.createElement('div');
        handle.className = 'resize-handle ' + area.class;
        handle.addEventListener('mousedown', function(e) {
            e.preventDefault();
            window.startResizing(area.edge);
        });
        document.body.appendChild(handle);
    });

    // 窗口拖动
    titleBar.addEventListener('mousedown', function(e) {
        if (!e.target.closest('.controls')) {
            window.startDragging();
        }
    });
});

这个示例展示了如何创建一个现代化的自定义窗口,包括:

  1. 自定义标题栏
  2. 窗口拖动
  3. 边缘调整大小
  4. 最大化/最小化/关闭控制
  5. 快捷键支持
  6. 窗口状态管理
  7. 平滑动画过渡
  8. 响应式布局

主要特点:

  • 无边框设计
  • 现代化UI风格
  • 完整窗口控制
  • 状态同步管理
  • 用户体验化
WebSocket高级示例
// 启用WebSocket并处理不同类型的消息
w.EnableWebSocket(8080)

// 定义消息结构
type WSMessage struct {
    Type string      `json:"type"`
    Data interface{} `json:"data"`
}

// 设置消息处理器
w.OnWebSocketMessage(func(message string) {
    var msg WSMessage
    if err := json.Unmarshal([]byte(message), &msg); err != nil {
        log.Printf("解析消息失败: %v", err)
        return
    }

    // 根据消息类型处理
    switch msg.Type {
    case "ping":
        w.SendWebSocketMessage(`{"type":"pong"}`)
    
    case "eval":
        if script, ok := msg.Data.(string); ok {
            w.Eval(script)
        }
    
    case "notification":
        // 处理通知消息
        if data, ok := msg.Data.(map[string]interface{}); ok {
            log.Printf("收到通知: %v", data)
        }
    
    default:
        log.Printf("未知消息类型: %s", msg.Type)
    }
})

// 注入WebSocket客户端增强代码
w.Init(`
    // WebSocket 重连机制
    class WSClient {
        constructor(url, options = {}) {
            this.url = url;
            this.options = {
                reconnectInterval: 1000,
                maxReconnects: 5,
                ...options
            };
            this.reconnectCount = 0;
            this.handlers = new Map();
            this.connect();
        }

        connect() {
            this.ws = new WebSocket(this.url);
            this.ws.onopen = () => {
                console.log('WebSocket已连接');
                this.reconnectCount = 0;
                this.handlers.get('open')?.forEach(fn => fn());
            };
            
            this.ws.onclose = () => {
                console.log('WebSocket已断开');
                this.reconnect();
                this.handlers.get('close')?.forEach(fn => fn());
            };
            
            this.ws.onmessage = (event) => {
                const data = JSON.parse(event.data);
                this.handlers.get('message')?.forEach(fn => fn(data));
            };
        }

        reconnect() {
            if (this.reconnectCount < this.options.maxReconnects) {
                this.reconnectCount++;
                setTimeout(() => this.connect(), this.options.reconnectInterval);
            }
        }

        on(event, handler) {
            if (!this.handlers.has(event)) {
                this.handlers.set(event, new Set());
            }
            this.handlers.get(event).add(handler);
        }

        send(data) {
            if (this.ws.readyState === WebSocket.OPEN) {
                this.ws.send(JSON.stringify(data));
            }
        }
    }

    // 创建WebSocket客户端实例
    window._ws = new WSClient('ws://localhost:8080/ws', {
        reconnectInterval: 2000,
        maxReconnects: 10
    });

    // 添加事件监听
    window._ws.on('message', data => {
        console.log('收到消息:', data);
    });
`)

🛠 性能优化

内存管理
// 使用对象池复用WebView实例
var webviewPool = sync.Pool{
    New: func() interface{} {
        return webview2.NewWithOptions(webview2.WebViewOptions{
            Debug: false,
            WindowOptions: webview2.WindowOptions{
                Width:  800,
                Height: 600,
            },
        })
    },
}

// 获取WebView实例
w := webviewPool.Get().(webview2.WebView)
defer webviewPool.Put(w)
资源释放
// 确保资源正确释放
func cleanup(w webview2.WebView) {
    w.Eval(`
        // 清理DOM事件监听器
        document.querySelectorAll('*').forEach(el => {
            el.replaceWith(el.cloneNode(true));
        });
        // 清理WebSocket连接
        if(window._ws) {
            window._ws.close();
        }
        // 清理定时
        for(let i = setTimeout(()=>{}, 0); i > 0; i--) {
            clearTimeout(i);
        }
    `)
    w.Destroy()
}
渲染优化
// 优化渲染性能
w.Init(`
    // 使用CSS containment优化重排
    .optimized-container {
        contain: content;
    }
    
    // 使用transform代替top/left
    .animated-element {
        transform: translate3d(0, 0, 0);
        will-change: transform;
    }
    
    // 避免大量DOM操作
    const fragment = document.createDocumentFragment();
    items.forEach(item => {
        const div = document.createElement('div');
        div.textContent = item;
        fragment.appendChild(div);
    });
    container.appendChild(fragment);
`)

⚠️ 错误处理

全局错误处理
func setupErrorHandling(w webview2.WebView) {
    // JavaScript错误处理
    w.Init(`
        window.onerror = function(msg, url, line, col, error) {
            console.error('JavaScript错误:', {
                message: msg,
                url: url,
                line: line,
                column: col,
                error: error
            });
            return false;
        };
        
        window.onunhandledrejection = function(event) {
            console.error('未处理的Promise拒绝:', event.reason);
        };
    `)
    
    // Go端错误处理
    w.Bind("handleError", func(err string) {
        log.Printf("应用错误: %s", err)
        // 可以添加错误上报逻辑
    })
}
优雅降级
// 功能检测和降级处理
w.Init(`
    // WebSocket支持检测
    if (!window.WebSocket) {
        console.warn('浏览器不支持WebSocket,使用轮询替代');
        startPolling();
    }
    
    // 存���API检测
    const storage = window.localStorage || {
        _data: {},
        setItem(id, val) { this._data[id] = val; },
        getItem(id) { return this._data[id]; }
    };
`)
错误恢复
// 实现错误恢复机制
func recoverableOperation(w webview2.WebView, operation func() error) {
    const maxRetries = 3
    var err error
    
    for i := 0; i < maxRetries; i++ {
        err = operation()
        if err == nil {
            return
        }
        log.Printf("操作失败(重试 %d/%d): %v", i+1, maxRetries, err)
        time.Sleep(time.Second * time.Duration(i+1))
    }
    
    // 最终失败处理
    w.Eval(`alert('操作失败,请稍后重试')`)
}

📚 最佳实践

代码组织
// 模块化组织代码
type Application struct {
    webview webview2.WebView
    state   *WindowState
    config  *Config
}

func NewApplication() *Application {
    return &Application{
        webview: webview2.NewWithOptions(defaultOptions),
        state:   NewWindowState(),
        config:  LoadConfig(),
    }
}

func (app *Application) Initialize() {
    app.setupErrorHandling()
    app.setupEventListeners()
    app.setupHotkeys()
    app.loadInitialContent()
}
状态管理
// 使用发布订阅模式管理状态
type StateManager struct {
    state     map[string]interface{}
    listeners map[string][]func(interface{})
    mu        sync.RWMutex
}

func (sm *StateManager) Subscribe(key string, listener func(interface{})) {
    sm.mu.Lock()
    defer sm.mu.Unlock()
    sm.listeners[key] = append(sm.listeners[key], listener)
}

func (sm *StateManager) SetState(key string, value interface{}) {
    sm.mu.Lock()
    sm.state[key] = value
    listeners := sm.listeners[key]
    sm.mu.Unlock()
    
    for _, listener := range listeners {
        listener(value)
    }
}
安全实践
// 实现CSP策略
w.Init(`
    // 添加CSP meta标签
    const meta = document.createElement('meta');
    meta.httpEquiv = 'Content-Security-Policy';
    meta.content = "default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline';";
    document.head.appendChild(meta);
    
    // 防止XSS
    function sanitizeHTML(str) {
        const div = document.createElement('div');
        div.textContent = str;
        return div.innerHTML;
    }
`)

// 实现安全的消息传递
type SecureMessage struct {
    Payload   interface{} `json:"payload"`
    Timestamp int64      `json:"timestamp"`
    Signature string     `json:"signature"`
}

func (app *Application) sendSecureMessage(payload interface{}) {
    msg := SecureMessage{
        Payload:   payload,
        Timestamp: time.Now().Unix(),
        Signature: app.generateSignature(payload),
    }
    app.webview.Eval(fmt.Sprintf("window.handleSecureMessage(%s)", toJSON(msg)))
}

🛠 API参考

窗口控制
API 描述
SetFullscreen(bool) 设置全屏模式
SetAlwaysOnTop(bool) 设置窗口置顶
SetOpacity(float64) 设置窗口透明度
Minimize() 最小化窗口
Maximize() 最大化窗口
Restore() 还原窗口
Center() 居中窗口
浏览器控制
API 描述
Navigate(string) 导航到URL
SetHtml(string) 设置HTML内容
Reload() 刷新页面
Back() 后退
Forward() 前进
Stop() 停止加载
ClearCache() 清除缓存
ClearCookies() 清除Cookies
开发工具
API 描述
OpenDevTools() 打开开发者工具
CloseDevTools() 关闭开发者工具
DisableContextMenu() 禁用右键菜单
EnableContextMenu() 启用右键菜单
WebSocket相关
API 描述
EnableWebSocket(port) 启用WebSocket服务
DisableWebSocket() 禁用WebSocket服务
OnWebSocketMessage(handler) 设置消息处理器
SendWebSocketMessage(message) 发送WebSocket消息
JavaScript Hook
API 描述
AddJSHook(hook) 添加JS钩子
RemoveJSHook(hook) 移除JS钩子
ClearJSHooks() 清除所有钩子

📝 常见问题

Q: 如何处理窗口关闭事件?
w.Bind("onClose", func() {
    // 执行清理操作
    w.Terminate()
})
Q: 如何实现自定义标题栏?
// 设置无边框窗口
w := webview2.NewWithOptions(webview2.WebViewOptions{
    WindowOptions: webview2.WindowOptions{
        Frameless: true,
    },
})

// 注入自定义标题栏HTML和CSS
w.Init(`
    const titleBar = document.createElement('div');
    titleBar.style.cssText = 'position:fixed;top:0;left:0;right:0;height:30px;-webkit-app-region:drag;background:#f0f0f0;';
    document.body.appendChild(titleBar);
`)
Q: 如何优化WebSocket连接?
// 启用带动重连的WebSocket
w.Init(`
    function connectWebSocket() {
        if (!window._webSocket || window._webSocket.readyState !== 1) {
            window._webSocket = new WebSocket('ws://localhost:8080/ws');
            window._webSocket.onclose = () => {
                setTimeout(connectWebSocket, 1000);
            };
        }
    }
    connectWebSocket();
`)

🤝 贡献指南

欢迎提交问题和改进建议! 请查看我们的贡献指南了解更多信息。

  1. Fork 项目
  2. 创建新分支 (git checkout -b feature/AmazingFeature)
  3. 提交更改 (git commit -m 'Add some AmazingFeature')
  4. 推送到分支 (git push origin feature/AmazingFeature)
  5. 提交Pull Request

📄 版权说明

该项目采用 MIT 许可证 - 详情请参阅 LICENSE 文件

🙏 鸣谢

📊 项目状态

Alt

Built with ❤️ by 煎饼果子卷鲨鱼辣椒

Documentation

Rendered for windows/amd64

Overview

+build windows

Index

Constants

This section is empty.

Variables

View Source
var (
	ErrInvalidFunction   = errors.New("only functions can be bound")
	ErrTooManyReturns    = errors.New("function may only return a value or a value+error")
	ErrInvalidReturnType = errors.New("second return value must be an error")
)

错误定义

Functions

This section is empty.

Types

type BaseJSHook

type BaseJSHook struct {
	HookType     JSHookType
	Handler      func(script string) string
	HookPriority int
}

BaseJSHook 提供基本的 JSHook 实现

func (*BaseJSHook) Handle

func (h *BaseJSHook) Handle(script string) string

func (*BaseJSHook) Priority

func (h *BaseJSHook) Priority() int

func (*BaseJSHook) Type

func (h *BaseJSHook) Type() JSHookType

type Hint

type Hint int

提示用于配置窗口大小和调整大小行为。

const (
	//HintNone 指定宽度和高度为默认尺寸
	HintNone Hint = iota

	//HintFixed 指定用户无法更改窗口大小
	HintFixed

	//HintMin 指定宽度和高度为最小边界
	HintMin

	//HintMax 指定宽度和高度为最大边界
	HintMax
)

type HotKey

type HotKey struct {
	Modifiers int // 修饰符
	KeyCode   int // 键码
}

HotKey 表示一个键组合

func ParseHotKey

func ParseHotKey(s string) (HotKey, error)

ParseHotKey 将热键字符串解析为 HotKey 结构 例如: "Ctrl+Alt+Q" -> HotKey{MOD_CONTROL|MOD_ALT, 'Q'}

type HotKeyHandler

type HotKeyHandler func()

在错误定义之后添加 HotKeyHandler 是热键处理函数的类型

type JSHook

type JSHook interface {
	Type() JSHookType            // 获取 Hook 类型
	Handle(script string) string // 处理脚本
	Priority() int               // Hook 优先级,数字越小优先级越高
}

JSHook 定义 JavaScript 钩子接口

type JSHookType

type JSHookType int

JSHookType 定义 Hook 的类型

const (
	JSHookBefore JSHookType = iota // JS 执行前
	JSHookAfter                    // JS 执行后
)

type WebSocketHandler

type WebSocketHandler func(message string)

WebSocketHandler 定义 WebSocket 消息处理函数

type WebSocketHook

type WebSocketHook struct {
	BaseJSHook
	// contains filtered or unexported fields
}

WebSocketHook 定义 WebSocket 相关的 JSHook

func NewWebSocketHook

func NewWebSocketHook(conn *websocket.Conn) *WebSocketHook

NewWebSocketHook 创建新的 WebSocket Hook

type WebView

type WebView interface {
	// 上下文管理相关方法
	Context() context.Context
	WithContext(ctx context.Context) WebView

	// 窗口控制
	Run()
	// 运行
	RunAsync()
	// 终止
	Terminate()
	// 调度函数
	Dispatch(f func())
	// 调度函数
	DispatchAsync(f func())
	// 销毁
	Destroy()
	// 获取窗口
	Window() unsafe.Pointer
	// 设置标题
	SetTitle(title string)
	// 设置大小
	SetSize(w int, h int, hint Hint)
	// 导航
	Navigate(url string)
	// 设置HTML
	SetHtml(html string)
	//初始化(加载之前注入js,永久注入)
	Init(js string)
	// 执行JS(加载之后注入js,临时注入)
	Eval(js string)
	// 绑定函数
	Bind(name string, f interface{}) error

	// 热键相关
	RegisterHotKey(modifiers int, keyCode int, handler HotKeyHandler) error
	// 注销热键
	UnregisterHotKey(modifiers int, keyCode int)
	// 注册热键字符串
	RegisterHotKeyString(hotkey string, handler HotKeyHandler) error

	// 窗口状态
	// 设置全屏
	SetFullscreen(enable bool)
	// 设置置顶
	SetAlwaysOnTop(enable bool)
	// 设置最小化
	SetMinimized(enable bool)
	// 设置最大化
	SetMaximized(enable bool)

	// 新增方法
	Minimize()                  // 最小化窗口
	Maximize()                  // 最大化窗口
	Restore()                   // 还原窗口
	Center()                    // 居中窗口
	SetOpacity(opacity float64) // 设置窗口透明度 (0.0-1.0)

	// 浏览器功能
	Reload()       // 刷新页面
	Back()         // 后退
	Forward()      // 前进
	Stop()         // 停止加载
	ClearCache()   // 清除缓存
	ClearCookies() // 清除 cookies

	// 开发工具
	OpenDevTools()  // 打开开发者工具
	CloseDevTools() // 关闭开发者工具

	// 状态监听
	OnLoadingStateChanged(func(isLoading bool))  // 加载状态变化
	OnURLChanged(func(url string))               // URL 变化
	OnTitleChanged(func(title string))           // 标题变化
	OnFullscreenChanged(func(isFullscreen bool)) // 全屏状态变化

	// 打印相关方法
	Print()                 // 直接打印
	PrintToPDF(path string) // 打印到 PDF 文件
	ShowPrintDialog()       // 显示打印对话框

	// 右键菜单控制
	DisableContextMenu() // 禁用右键菜单
	EnableContextMenu()  // 启用右键菜单

	// JavaScript Hook 相关方法
	AddJSHook(hook JSHook)    // 添加 JS Hook
	RemoveJSHook(hook JSHook) // 移除 JS Hook
	ClearJSHooks()            // 清除所有 JS Hook

	// WebSocket 相关方法
	EnableWebSocket(port int) error              // 启用 WebSocket 服务
	DisableWebSocket()                           // 禁用 WebSocket 服务
	OnWebSocketMessage(handler WebSocketHandler) // 设置 WebSocket 消息处理器
	SendWebSocketMessage(message string)         // 发送 WebSocket 消息
}

WebView是webview的接口。

func New

func New(debug bool) WebView

New 在新窗口中创建一个新的 webview。

func NewWindow

func NewWindow(debug bool, window unsafe.Pointer) WebView

NewWindow 使用现有窗创一个新的 webview。

已弃用:使用 NewWithOptions。

func NewWithOptions

func NewWithOptions(options WebViewOptions) WebView

NewWithOptions 使用提供的选项创建一个的 webview。

type WebViewOptions

type WebViewOptions struct {
	Window unsafe.Pointer
	Debug  bool

	//DataPath 指定 WebView2 运行时使用的数据路径
	//浏览器实例。
	DataPath string

	//窗口打开时,AutoFocus 将尝试保持 WebView2 小部件聚焦
	//已聚焦。
	AutoFocus bool

	//WindowOptions 自定义创建的窗口以嵌入
	//WebView2 小部件。
	WindowOptions WindowOptions
}

type WindowOptions

type WindowOptions struct {
	Title              string  // 窗口标题
	Width              uint    // 窗口宽度
	Height             uint    // 窗口高度
	IconId             uint    // 图标ID
	Center             bool    // 是否居中
	Frameless          bool    // 是否无边框
	Fullscreen         bool    // 是否全屏
	AlwaysOnTop        bool    // 是否置顶
	Resizable          bool    // 是否可调整大小
	Minimizable        bool    // 是否可最小化
	Maximizable        bool    // 是否可最大化
	DisableContextMenu bool    // 是否禁用右键菜单
	EnableDragAndDrop  bool    // 是否启用拖放
	HideWindowOnClose  bool    // 关闭时是否隐藏窗口而不是退出
	DefaultBackground  string  // 默认背景色 (CSS 格式,如 "#FFFFFF")
	Opacity            float64 // 初始透明度 (0.0-1.0)
	IconPath           string  // 图标文件路径
	IconData           []byte  // 图标进制数据
}

func DefaultWindowOptions

func DefaultWindowOptions() WindowOptions

添加默认配置

Directories

Path Synopsis
internal
w32
pkg

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL