🎯 痛点场景:为什么需要桌面应用开发技能?
你是否遇到这些问题?
- 学了Go语言,却只会写命令行工具?
- 想学桌面开发,却觉得C++/C#太复杂?
- 面试官对你的“烂大街”项目不感兴趣?
你能学到什么?
- ✅️ Wails 基础使用
- ✅️ 实时事件通信
- ✅️ 系统托盘集成
- ✅️ 多线程编程
- ✅️ 附完整源码

🛠️ 环境准备
步骤1:安装Go语言
# 官网下载安装包:https://golang.org/dl/ go version # 验证安装
步骤2:安装Wails框架
go install github.com/wailsapp/wails/v2/cmd/wails@latest wails version # 验证安装
步骤3:创建项目骨架
wails init -n Punktime cd Punktime

🚀 核心功能开发
设计 UI (前端)
-
使用 HTML/CSS/JavaScript实现:
- 时间/倒计时主界面
- 倒计时设置遮罩层
-
示例代码
<!-- ============================================================================ * 主界面结构 * 应用程序的主要显示区域 * ============================================================================ --> <!-- 主容器:显示倒计时/时间 --> <div class="container"> <div class="countdown" id="countdown"></div> </div> <!-- ============================================================================ * 倒计时输入框模态对话框 * 用于设置倒计时时长的弹出窗口 * ============================================================================ --> <!-- 倒计时输入框遮罩层 --> <div id="countdownInputOverlay" class="countdown-input-overlay" style="display: none" > <div class="countdown-input-container"> <div class="countdown-input-title"></div> <div> <!-- 分钟输入框 --> <input type="number" id="minutesInput" class="countdown-input" min="0" max="59" value="25" placeholder="分" /> <span style="color: lightgreen">:</span> <!-- 秒数输入框 --> <input type="number" id="secondsInput" class="countdown-input" min="0" max="59" value="0" placeholder="秒" /> </div> <div class="countdown-input-buttons"> <!-- 确认按钮 --> <button id="confirmCountdown" class="countdown-input-button"> 确定 </button> <!-- 取消按钮 --> <button id="cancelCountdown" class="countdown-input-button"> 取消 </button> </div> </div> </div>
实现计时逻辑(Go后端)
- 核心代码
/** * @description: 计时器更新循环,每秒执行一次的时间/倒计时更新逻辑 * 函数作为计时器管理器的核心循环,负责: * 1. 每秒更新计时器状态和显示内容 * 2. 根据当前显示模式(倒计时/时间)执行不同的更新逻辑 * 3. 处理倒计时结束事件和状态转换 * 4. 通过Wails事件系统向前端发送更新数据 * * 倒计时模式逻辑: * - 运行中:计算剩余时间,倒计时结束时触发timerEnd事件 * - 暂停中:显示暂停时的剩余时间 * - 未开始:显示设置的倒计时总时长 * * 时间模式逻辑: * - 显示当前系统时间(MM:SS格式) * * @example * // 每秒自动执行,无需手动调用 * // 倒计时模式:显示"25:00" → "24:59" → ... → "00:00"(触发结束事件) * // 时间模式:显示当前时间如"14:30" * * @see runtime.EventsEmit 发送事件到前端 * @see time.Since 计算时间间隔 * * @note 使用互斥锁确保线程安全,避免并发访问计时器状态 * @note 倒计时结束时自动重置状态并发送结束事件 * @note 时间格式统一为两位数(如"05:09"而非"5:9") */ func (tm *TimerManager) updateLoop() { for range tm.ticker.C { tm.mu.Lock() if tm.isTimerRunning { tm.timerElapsed = time.Since(tm.timerStartTime) } switch tm.displayMode { case "countdown": if tm.isTimerRunning { remaining := tm.countdownDuration - tm.timerElapsed if remaining <= 0 { remaining = 0 tm.isTimerRunning = true tm.timerElapsed = tm.countdownDuration tm.isPaused = false runtime.EventsEmit(tm.ctx, "timerEnd") timerText := "00:00" runtime.EventsEmit(tm.ctx, "timerUpdate", timerText) } else { minutes := int(remaining.Minutes()) seconds := int(remaining.Seconds()) % 60 timerText := fmt.Sprintf("%02d:%02d", minutes, seconds) runtime.EventsEmit(tm.ctx, "timerUpdate", timerText) } } else { if tm.isPaused { remaining := tm.countdownDuration - tm.timerElapsed if remaining < 0 { remaining = 0 } minutes := int(remaining.Minutes()) seconds := int(remaining.Seconds()) % 60 timerText := fmt.Sprintf("%02d:%02d", minutes, seconds) runtime.EventsEmit(tm.ctx, "timerUpdate", timerText) } else { minutes := int(tm.countdownDuration.Minutes()) seconds := int(tm.countdownDuration.Seconds()) % 60 timerText := fmt.Sprintf("%02d:%02d", minutes, seconds) runtime.EventsEmit(tm.ctx, "timerUpdate", timerText) } } case "time": currentTime := time.Now().Format("15:04") runtime.EventsEmit(tm.ctx, "timeUpdate", currentTime) } tm.mu.Unlock() } }
- 前后端通信
- 前端负责监听更新事件并渲染
- 后端负责触发更新事件并发送数据
// 监听倒计时更新事件 window.runtime.EventsOn("timerUpdate", (data) => { document.getElementById("countdown").textContent = data; }); // 监听时间显示更新事件 window.runtime.EventsOn("timeUpdate", (data) => { document.getElementById("countdown").textContent = data; });
if tm.isTimerRunning { remaining := tm.countdownDuration - tm.timerElapsed if remaining <= 0 { remaining = 0 tm.isTimerRunning = true tm.timerElapsed = tm.countdownDuration tm.isPaused = false runtime.EventsEmit(tm.ctx, "timerEnd") timerText := "00:00" // 发送事件显示更新事件 runtime.EventsEmit(tm.ctx, "timerUpdate", timerText) } else { minutes := int(remaining.Minutes()) seconds := int(remaining.Seconds()) % 60 timerText := fmt.Sprintf("%02d:%02d", minutes, seconds) // 发送事件显示更新事件 runtime.EventsEmit(tm.ctx, "timerUpdate", timerText) }
📦️ 打包发布
wails build

495

被折叠的 条评论
为什么被折叠?



