基于Tauri2+Vue3搭建桌面端程序|tauri2+vite5多窗口|消息提醒|托盘闪烁

基于tauri2+vite5+vue3封装多窗口实践|自定义消息提醒|托盘右键菜单及图标闪烁

这段时间一直在捣鼓最新版Tauri2.x整合Vite5搭建桌面端多开窗体应用实践。tauri2.0相较于1.0版本api有了比较多的更改,而且tauri2支持创建android/ios应用。至于具体的api变更,大家可以去官网查阅文档资料。

基于Tauri2+Vue3搭建桌面端程序|tauri2+vite5多窗口|消息提醒|托盘闪烁

https://v2.tauri.app/start/migrate/from-tauri-1/

基于Tauri2+Vue3搭建桌面端程序|tauri2+vite5多窗口|消息提醒|托盘闪烁

版本信息

"@tauri-apps/api": ">=2.0.0-rc.0", "@tauri-apps/cli": ">=2.0.0-rc.0", "vue": "^3.3.4", "vite": "^5.3.1"

创建tauri2+vue3项目模板

官网提供了多种方式创建tauri2+vue3项目。

基于Tauri2+Vue3搭建桌面端程序|tauri2+vite5多窗口|消息提醒|托盘闪烁

// 创建项目模板 yarn create tauri-app --rc // 进入项目目录 cd tauri-app // 安装依赖 yarn // 运行项目 yarn tauri dev

内置了多种热门前端框架模板可供选择。

基于Tauri2+Vue3搭建桌面端程序|tauri2+vite5多窗口|消息提醒|托盘闪烁

基于Tauri2+Vue3搭建桌面端程序|tauri2+vite5多窗口|消息提醒|托盘闪烁

// 运行到桌面端 yarn tauri dev // 初始化android yarn tauri android init // 运行到android yarn tauri android dev

基于Tauri2+Vue3搭建桌面端程序|tauri2+vite5多窗口|消息提醒|托盘闪烁

至此一个简单的tauri2+vue3初始化项目模板就搭建好了。

tauri2封装多窗口管理

通过封装一个tauri多窗口类,只需传入配置参数,即可快速创建一个新窗体,简化调用方式。

基于Tauri2+Vue3搭建桌面端程序|tauri2+vite5多窗口|消息提醒|托盘闪烁

createWin({     label: 'manage',     title: '管理页面',     url: '/manage',     width: 960,     height: 750,     center: false,     x: 320,     y: 500,     resizable: false,     alwaysOnTop: true, })

基于Tauri2+Vue3搭建桌面端程序|tauri2+vite5多窗口|消息提醒|托盘闪烁

/**  * @desc    Tauri2多窗口封装管理  * @author: Andy  QQ:282310962  * @time    2024.9  */  import { getAllWindows, getCurrentWindow } from '@tauri-apps/api/window' import { WebviewWindow, getAllWebviewWindows, getCurrentWebviewWindow} from '@tauri-apps/api/webviewWindow' import { relaunch, exit } from '@tauri-apps/plugin-process' import { emit, listen } from '@tauri-apps/api/event'  import { setWin } from './actions'  const appWindow = getCurrentWindow()  // 创建窗口参数配置 export const windowConfig = {     label: null,            // 窗口唯一label     title: '',              // 窗口标题     url: '',                // 路由地址url     width: 1000,            // 窗口宽度     height: 640,            // 窗口高度     minWidth: null,         // 窗口最小宽度     minHeight: null,        // 窗口最小高度     x: null,                // 窗口相对于屏幕左侧坐标     y: null,                // 窗口相对于屏幕顶端坐标     center: true,           // 窗口居中显示     resizable: true,        // 是否支持缩放     maximized: false,       // 最大化窗口     decorations: false,     // 窗口是否装饰边框及导航条     alwaysOnTop: false,     // 置顶窗口     dragDropEnabled: false, // 禁止系统拖放     visible: false,         // 隐藏窗口      // ... }  class Windows {     constructor() {         // 主窗口         this.mainWin = null     }      // 创建新窗口     async createWin(options) {         console.log('-=-=-=-=-=开始创建窗口')          const args = Object.assign({}, windowConfig, options)          // 判断窗口是否存在         const existWin = await this.getWin(args.label)         if(existWin) {             console.log('窗口已存在>>', existWin)             // ...         }         // 创建窗口对象         const win = new WebviewWindow(args.label, args)          // 窗口创建完毕/失败         win.once('tauri://created', async() => {             console.log('tauri://created')             // 是否主窗口             if(args.label.indexOf('main') > -1) {                 // ...             }              // 是否最大化             if(args.maximized && args.resizable) {                 console.log('is-maximized')                 await win.maximize()             }         })          win.once('tauri://error', async(error) => {             console.log('window create error!', error)         })     }      // 获取窗口     async getWin(label) {         return await WebviewWindow.getByLabel(label)     }      // 获取全部窗口     async getAllWin() {         //  return getAll()         return await getAllWindows()     }      // 开启主进程监听事件     async listen() {         console.log('——+——+——+——+——+开始监听窗口')          // 创建新窗体         await listen('win-create', (event) => {             console.log(event)             this.createWin(event.payload)         })          // 显示窗体         await listen('win-show', async(event) => {             if(appWindow.label.indexOf('main') == -1) return             await appWindow.show()             await appWindow.unminimize()             await appWindow.setFocus()         })          // 隐藏窗体         await listen('win-hide', async(event) => {             if(appWindow.label.indexOf('main') == -1) return             await appWindow.hide()         })          // 关闭窗体         await listen('win-close', async(event) => {             await appWindow.close()         })          // ...     } }   export default Windows

基于Tauri2+Vue3搭建桌面端程序|tauri2+vite5多窗口|消息提醒|托盘闪烁

actions.js封装一些调用方法。

import { emit } from '@tauri-apps/api/event'  /**  * @desc 创建新窗口  * @param args {object} {label: 'new', url: '/new', width: 500, height: 300, ...}  */  export async function createWin(args) {     await emit('win-create', args) }  // ...  /**  * @desc 登录窗口  */  export async function loginWin() {     await createWin({         label: 'main_login',         title: '登录',         url: '/login',         width: 400,         height: 320,         resizable: false,         alwaysOnTop: true     }) }  export async function mainWin() {     await createWin({         label: 'main',         title: 'TAURI-WINDOWMANAGER',         url: '/',         width: 800,         height: 600,         minWidth: 500,         minHeight: 360,     }) }  export async function aboutWindow() {     await createWin({         label: 'about',         title: '关于',         url: '/about',         width: 450,         height: 360,     }) }

tauri2创建系统托盘图标|托盘闪烁消息提醒|托盘右键菜单

tauri2创建系统托盘图标,实现类似QQ消息提醒,自定义托盘右键菜单。

基于Tauri2+Vue3搭建桌面端程序|tauri2+vite5多窗口|消息提醒|托盘闪烁

基于Tauri2+Vue3搭建桌面端程序|tauri2+vite5多窗口|消息提醒|托盘闪烁

在src-tauri/src目录下,新建一个tray.rs托盘文件。

基于Tauri2+Vue3搭建桌面端程序|tauri2+vite5多窗口|消息提醒|托盘闪烁

use tauri::{     tray::{MouseButton, TrayIconBuilder, TrayIconEvent}, Emitter, Manager, Runtime }; use std::thread::{sleep}; use std::time::Duration;  pub fn create_tray<R: Runtime>(app: &tauri::AppHandle<R>) -> tauri::Result<()> {     let _ = TrayIconBuilder::with_id("tray")         .tooltip("tauri")         .icon(app.default_window_icon().unwrap().clone())         .on_tray_icon_event(|tray, event| match event {             TrayIconEvent::Click {                 id: _,                 position,                 rect: _,                 button,                 button_state: _,             } => match button {                 MouseButton::Left {} => {                     // ...                 }                 MouseButton::Right {} => {                     tray.app_handle().emit("tray_contextmenu", position).unwrap();                 }                 _ => {}             },             TrayIconEvent::Enter {                 id: _,                 position,                 rect: _,             } => {                 tray.app_handle().emit("tray_mouseenter", position).unwrap();             }             TrayIconEvent::Leave {                 id: _,                 position,                 rect: _,             } => {                 // sleep(Duration::from_millis(500));                 tray.app_handle().emit("tray_mouseleave", position).unwrap();             }             _ => {}         })         .build(app);     Ok(()) }

在lib.rs中引入托盘配置。

// ...  mod tray;  #[cfg_attr(mobile, tauri::mobile_entry_point)] pub fn run() {     tauri::Builder::default()         // ...         .setup(|app| {             #[cfg(all(desktop))]             {                 let handle = app.handle();                 tray::create_tray(handle)?;             }             Ok(())         })         .invoke_handler(tauri::generate_handler![greet])         .run(tauri::generate_context!())         .expect("error while running tauri application"); }

  • 托盘消息提醒

基于Tauri2+Vue3搭建桌面端程序|tauri2+vite5多窗口|消息提醒|托盘闪烁

基于Tauri2+Vue3搭建桌面端程序|tauri2+vite5多窗口|消息提醒|托盘闪烁

新建一个msg新窗口,通过获取鼠标滑过托盘图标的position坐标给到msg窗口x,y参数

import { WebviewWindow } from '@tauri-apps/api/webviewWindow' import { emit, listen } from '@tauri-apps/api/event' import { LogicalPosition } from '@tauri-apps/api/window'  export let messageBoxWindowWidth = 280 export let messageBoxWindowHeight = 100  export default async function CreateMsgBox() {     console.log('start create msgbox...')      let webview = new WebviewWindow("msgbox", {         url: "/msg",         title: "消息通知",         width: messageBoxWindowWidth,         height: messageBoxWindowHeight,         skipTaskbar: true,         decorations: false,         center: false,         resizable: false,         alwaysOnTop: true,         focus: true,         x: window.screen.width + 50,         y: window.screen.height + 50,         visible: false     })      // 托盘消息事件     await webview.listen('tauri://window-created', async () => {         console.log('msgbox create')     })     await webview.listen('tauri://blur', async () => {         console.log('msgbox blur')         const win = await WebviewWindow.getByLabel('msgbox')         await win.hide()     })     await webview.listen('tauri://error', async(error) => {         console.log('msgbox error!', error)     })       // 监听托盘事件     let trayEnterListen = listen('tray_mouseenter', async (event) => {         // console.log(event)          const win = await WebviewWindow.getByLabel('msgbox')         if(!win) return          let position = event.payload         if(win) {             await win.setAlwaysOnTop(true)             await win.setFocus()             await win.setPosition(new LogicalPosition(position.x - messageBoxWindowWidth / 2, window.screen.availHeight - messageBoxWindowHeight))             await win.show()         }     })     let trayLeaveListen = listen('tray_mouseleave', async (event) => {         console.log(event)         const win = await WebviewWindow.getByLabel('msgbox')         await win.hide()     }) }

封装设置托盘图标闪烁 flashTray(true) 和取消闪烁 flashTray(false) 

<script setup>     // ...      const flashTimer = ref(false)     const flashTray = async(bool) => {         let flag = true         if(bool) {             TrayIcon.getById('tray').then(async(res) => {                 clearInterval(flashTimer.value)                 flashTimer.value = setInterval(() => {                     if(flag) {                         res.setIcon(null)                     }else {                         // 支持把自定义图标放在默认icons文件夹,通过如下方式设置图标                         // res.setIcon('icons/msg.png')                         // 支持把自定义图标放在自定义文件夹tray,需要配置tauri.conf.json参数 "bundle": {"resources": ["tray"]}                         res.setIcon('tray/msg.png')                     }                     flag = !flag                 }, 500)             })         }else {             clearInterval(flashTimer.value)             let tray = await TrayIcon.getById("tray")             tray.setIcon('icons/icon.png')         }     } </script>

基于Tauri2+Vue3搭建桌面端程序|tauri2+vite5多窗口|消息提醒|托盘闪烁

托盘图标也支持放在自定义文件夹。

基于Tauri2+Vue3搭建桌面端程序|tauri2+vite5多窗口|消息提醒|托盘闪烁

比如:托盘图标放在自定义文件夹tray,则需要配置tauri.conf.json文件resources字段。

"bundle": {     ...     "resources": [       "tray"     ] },

  • 托盘右键菜单

基于Tauri2+Vue3搭建桌面端程序|tauri2+vite5多窗口|消息提醒|托盘闪烁

基于Tauri2+Vue3搭建桌面端程序|tauri2+vite5多窗口|消息提醒|托盘闪烁

其实右键菜单窗口和消息提醒窗口原理差不多。

import { ref } from 'vue' import { WebviewWindow } from '@tauri-apps/api/webviewWindow' import { emit, listen } from '@tauri-apps/api/event' import { PhysicalPosition, LogicalPosition } from '@tauri-apps/api/window' import { TrayIcon } from '@tauri-apps/api/tray' import { invoke } from '@tauri-apps/api/core'  export let menuBoxWindowWidth = 150 export let menuBoxWindowHeight = JSON.parse(localStorage.getItem('logged')) ? 320 : 45  export default async function CreateTraymenu() {     console.log('start create traymenu...')          let webview = new WebviewWindow("traymenu", {         url: "/menu",         title: "消息通知",         width: menuBoxWindowWidth,         height: menuBoxWindowHeight,         skipTaskbar: true,         decorations: false,         center: false,         resizable: false,         alwaysOnTop: true,         focus: true,         x: window.screen.width + 50,         y: window.screen.height + 50,         visible: false     })      // 托盘消息事件     await webview.listen('tauri://window-created', async () => {         console.log('traymenu create')     })     await webview.listen('tauri://blur', async () => {         console.log('traymenu blur')         const win = await WebviewWindow.getByLabel('traymenu')         await win.hide()     })     await webview.listen('tauri://error', async(error) => {         console.log('traymenu error!', error)     })       // 监听托盘事件     let trayEnterListen = listen('tray_contextmenu', async (event) => {         console.log(event)          const win = await WebviewWindow.getByLabel('traymenu')         if(!win) return          let position = event.payload         if(win) {             await win.setAlwaysOnTop(true)             await win.setFocus()             await win.setPosition(new LogicalPosition(position.x, position.y - menuBoxWindowHeight))             await win.show()         }     }) }

<!--托盘右键菜单--> <script setup> import { ref } from 'vue' import { WebviewWindow } from "@tauri-apps/api/webviewWindow" import { TrayIcon } from '@tauri-apps/api/tray' import { invoke } from '@tauri-apps/api/core'      const logged = JSON.parse(localStorage.getItem('logged'))      const handleMainShow = async () => {         const traywin = await WebviewWindow.getByLabel('traymenu')         await traywin.hide()          const homewin = await WebviewWindow.getByLabel('main')         await homewin.show()         await homewin.unminimize()         await homewin.setFocus()     }      const flashTimer = ref(false)     const flashTray = async(bool) => {         let flag = true         if(bool) {             TrayIcon.getById('tray').then(async(res) => {                 clearInterval(flashTimer.value)                 flashTimer.value = setInterval(() => {                     if(flag) {                         res.setIcon(null)                     }else {                         // res.setIcon(defaultIcon)                         // 支持把自定义图标放在默认icons文件夹,通过如下方式设置图标                         // res.setIcon('icons/msg.png')                         // 支持把自定义图标放在自定义文件夹tray,需要配置tauri.conf.json参数 "bundle": {"resources": ["tray"]}                         res.setIcon('tray/msg.png')                     }                     flag = !flag                 }, 500)             })         }else {             clearInterval(flashTimer.value)             let tray = await TrayIcon.getById("tray")             tray.setIcon('icons/icon.png')         }     } </script>  <template>     <div v-if="logged" class="traymenu">         <p class="item">😍 我在线上</p>         <p class="item">😎 隐身</p>         <p class="item">😏 离开</p>         <p class="item">😱 忙碌</p>         <p class="item">关闭所有声音</p>         <p class="item" @click="flashTray(true)">开启图标闪烁</p>         <p class="item" @click="flashTray(false)">关闭图标闪烁</p>         <p class="item" @click="handleMainShow">👀 打开主面板</p>         <p class="item">💍 退出</p>     </div>     <div v-else class="traymenu">         <p class="item">💍 退出</p>     </div> </template>

综上就是tauri2+vue3开发多窗口实践,自定义托盘图标消息提醒,右键菜单的一些简单分享,效果还是比较粗糙,主要是为了实现功能思路,希望以上分享对大家有所帮助哈!

基于Tauri2+Vue3搭建桌面端程序|tauri2+vite5多窗口|消息提醒|托盘闪烁

 

发表评论

评论已关闭。

相关文章