Golang

wails入门系列(二)无边框应用的菜单栏以及窗口拖拽

Wails 无边框窗口开发教程,介绍 Frameless 配置、自定义标题栏实现、窗口控制按钮(最小化/最大化/关闭)以及使用 CSS --wails-draggable 实现窗口拖拽功能。

说在前面

  • 操作系统:win11
  • go版本:1.24.4
  • nodejs版本:v22.16.0
  • wails版本:v2.10.1

wails设置

  • wails设置无边框是比较简单的,在配置里将Frameless设置为true即可
    func main() {
        // Create an instance of the app structure
        app := NewApp()
    
        // Create application with options
        err := wails.Run(&options.App{
            Title:  "workbench-go",
            Width:  1024,
            Height: 768,
            AssetServer: &assetserver.Options{
                Assets: assets,
            },
            Frameless:        true,
            BackgroundColour: &options.RGBA{R: 27, G: 38, B: 54, A: 1},
            OnStartup:        app.startup,
            Bind: []interface{}{
                app,
            },
        })
    
        if err != nil {
            println("Error:", err.Error())
        }
    }
    
  • 运行结果如下,但是关闭按钮也没了,拖拽也没了

自定义菜单栏

  • wails提供的api中已经存在了对应的最大化/最小化/关闭应用等功能,可以在frontend\wailsjs\runtime\runtime.d.ts中找到:
    // [WindowMaximise](https://wails.io/docs/reference/runtime/window#windowmaximise)
    // Maximises the window to fill the screen.
    export function WindowMaximise(): void;
    
    // [WindowToggleMaximise](https://wails.io/docs/reference/runtime/window#windowtogglemaximise)
    // Toggles between Maximised and UnMaximised.
    export function WindowToggleMaximise(): void;
    
    // [WindowUnmaximise](https://wails.io/docs/reference/runtime/window#windowunmaximise)
    // Restores the window to the dimensions and position prior to maximising.
    export function WindowUnmaximise(): void;
    
    // [WindowIsMaximised](https://wails.io/docs/reference/runtime/window#windowismaximised)
    // Returns the state of the window, i.e. whether the window is maximised or not.
    export function WindowIsMaximised(): Promise<boolean>;
    
    // [WindowMinimise](https://wails.io/docs/reference/runtime/window#windowminimise)
    // Minimises the window.
    export function WindowMinimise(): void;
    
    // [WindowUnminimise](https://wails.io/docs/reference/runtime/window#windowunminimise)
    // Restores the window to the dimensions and position prior to minimising.
    export function WindowUnminimise(): void;
    
    // [WindowIsMinimised](https://wails.io/docs/reference/runtime/window#windowisminimised)
    // Returns the state of the window, i.e. whether the window is minimised or not.
    export function WindowIsMinimised(): Promise<boolean>;
    
  • 这样,我们只需要编写对应的前端代码即可
    <template>
      <div class="title-bar">
        <!-- 左侧:应用图标和名称 -->
        <div class="title-bar-left">
          <img src="../assets/images/logo-universal.webp" alt="App Icon" class="app-icon" />
          <span class="app-name">Workbench</span>
        </div>
    
        <!-- 右侧:窗口控制按钮 -->
        <div class="title-bar-right">
          <button @click="minimizeWindow" class="window-control minimize" title="最小化">
            <Minus :size="14" />
          </button>
          <button @click="toggleMaximize" class="window-control maximize" :title="isMaximized ? '还原' : '最大化'">
            <Maximize2 v-if="!isMaximized" :size="14" />
            <Minimize2 v-else :size="14" />
          </button>
          <button @click="closeWindow" class="window-control close" title="关闭">
            <X :size="14" />
          </button>
        </div>
      </div>
    </template>
    
    <script setup lang="ts">
    import { ref, onMounted } from 'vue'
    import { Minus, Maximize2, Minimize2, X } from 'lucide-vue-next'
    import { WindowMaximise, WindowMinimise, WindowUnmaximise, Quit, WindowIsMaximised } from '../../wailsjs/runtime/runtime'
    
    const isMaximized = ref(false)
    
    const minimizeWindow = async () => {
      try {
        await WindowMinimise()
      } catch (error) {
        console.error('Error minimizing window:', error)
      }
    }
    
    const toggleMaximize = async () => {
      try {
        if (isMaximized.value) {
          await WindowUnmaximise()
          isMaximized.value = false
        } else {
          await WindowMaximise()
          isMaximized.value = true
        }
      } catch (error) {
        console.error('Error toggling maximize:', error)
      }
    }
    
    const closeWindow = async () => {
      try {
        await Quit()
      } catch (error) {
        console.error('Error closing window:', error)
      }
    }
    
    const checkMaximizeState = async () => {
      try {
        isMaximized.value = await WindowIsMaximised()
      } catch (error) {
        console.error('Error checking maximize state:', error)
      }
    }
    
    onMounted(() => {
      checkMaximizeState()
      // 监听窗口状态变化
      window.addEventListener('resize', checkMaximizeState)
    })
    </script>
    </style>
    
    运行结果如下:

窗口拖拽

  • 添加完成之后,整个窗口是不能拖拽的,需要我们添加拖拽支持,wails提供了对应的方法,即设置css样式
    --wails-draggable:drag
    
    这样将菜单栏对应的dom节点设置一下就行
    <template>
      <div class="title-bar" style="--wails-draggable: drag;">
        <!-- 左侧:应用图标和名称 -->
        <div class="title-bar-left">
          <img src="../assets/images/logo-universal.webp" alt="App Icon" class="app-icon" />
          <span class="app-name">Workbench</span>
        </div>
    
        <!-- 右侧:窗口控制按钮 -->
        <div class="title-bar-right">
          <button @click="minimizeWindow" class="window-control minimize" title="最小化" style="--wails-draggable: no-drag;">
            <Minus :size="14" />
          </button>
          <button @click="toggleMaximize" class="window-control maximize" :title="isMaximized ? '还原' : '最大化'" style="--wails-draggable: no-drag;">
            <Maximize2 v-if="!isMaximized" :size="14" />
            <Minimize2 v-else :size="14" />
          </button>
          <button @click="closeWindow" class="window-control close" title="关闭" style="--wails-draggable: no-drag;">
            <X :size="14" />
          </button>
        </div>
      </div>
    </template>