on the basis oftauri2+vite5+vue3Wrap Multi-Window Practice|Customize Message Alerts|Tray context menu and icon blinking
I've been tinkering with the latest version for a while now.conformVite5Build desktop multi-open window application practice. tauri2.0 compared to version 1.0 api has a relatively large number of changes, and tauri2 support for creatingandroid/iosApps. As for the specific api changes, you can check the documentation on the official website.
/start/migrate/from-tauri-1/
version information
"@tauri-apps/api": ">=2.0.0-rc.0", "@tauri-apps/cli": ">=2.0.0-rc.0", "vue": "^3.3.4", "vite": "^5.3.1"
Create tauri2+vue3 project template
The official website provides multiple ways to create tauri2+vue3 projects.
// Creating Project Templates yarn create tauri-app --rc // Go to the project directory cd tauri-app // Installation of dependencies yarn // Running Projects yarn tauri dev
A variety of popular front-end framework templates are built-in to choose from.
// Running to the desktop yarn tauri dev // Initialize android yarn tauri android init // Run to android yarn tauri android dev
At this point a simple tauri2+vue3 project template is built.
tauri2 encapsulates multi-window management
By encapsulating a tauri multi-window class, you can quickly create a new form by simply passing in configuration parameters, simplifying the invocation.
createWin({ label: 'manage', title: 'Admin Page', url: '/manage', width: 960, height: 750, center: false, x: 320, y: 500, resizable: false, alwaysOnTop: true, })
/** * @desc Tauri2 multi-window package management * @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() // Create Window Parameter Configuration export const windowConfig = { label: null, // Window unique label title: '', // Window Title url: '', // Routing address url width: 1000, // window width height: 640, // Window height minWidth: null, // Minimum window width minHeight: null, // Minimum window height x: null, // Window coordinates relative to the left side of the screen y: null, // Window coordinates relative to the top of the screen center: true, // Window centering resizable: true, // Whether zoom is supported maximized: false, // Maximize Window decorations: false, // Whether the window is decorated with borders and navigation bars alwaysOnTop: false, // sticky (of an Internet forum thread etc) dragDropEnabled: false, // Prohibit system drag and drop visible: false, // hide a window // ... } class Windows { constructor() { // main window this.mainWin = null } // Creating a new window async createWin(options) { ('-=-=-=-=-=Start creating windows') const args = ({}, windowConfig, options) // Determine if a window exists const existWin = await this.getWin() if(existWin) { ('Window already exists>>', existWin) // ... } // Creating Window Objects const win = new WebviewWindow(, args) // Window creation complete/failed ('tauri://created', async() => { ('tauri://created') // Main window or not if(('main') > -1) { // ... } // Maximize or not if( && ) { ('is-maximized') await () } }) ('tauri://error', async(error) => { ('window create error!', error) }) } // Get Window async getWin(label) { return await (label) } // Get all windows async getAllWin() { // return getAll() return await getAllWindows() } // Enable the master process to listen for events async listen() { ('--+--+--+--+- --+Start listening to windows') // Creating a new form await listen('win-create', (event) => { (event) this.createWin() }) // Show Forms await listen('win-show', async(event) => { if(('main') == -1) return await () await () await () }) // Hide Forms await listen('win-hide', async(event) => { if(('main') == -1) return await () }) // Close Form await listen('win-close', async(event) => { await () }) // ... } } export default Windows
Encapsulate some calling methods.
import { emit } from '@tauri-apps/api/event' /** * @desc Creating a new window * @param args {object} {label: 'new', url: '/new', width: 500, height: 300, ...} */ export async function createWin(args) { await emit('win-create', args) } // ... /** * @desc Login Window */ export async function loginWin() { await createWin({ label: 'main_login', title: 'Login', 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: 'About', url: '/about', width: 450, height: 360, }) }
tauri2 create system tray icon | tray blinking message alert | tray context menu
tauri2 create system tray icon to achieve similar QQ message alerts, customize the tray context menu.
In the src-tauri/src directory, create a new tray file.
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(()) }
Introduces a tray configuration in the
// ... mod tray; #[cfg_attr(mobile, tauri::mobile_entry_point)] pub fn run() { tauri::Builder::default() // ... .setup(|app| { #[cfg(all(desktop))] { let handle = (); tray::create_tray(handle)?; } Ok(()) }) .invoke_handler(tauri::generate_handler![greet]) .run(tauri::generate_context!()) .expect("error while running tauri application"); }
- Pallet Message Alerts
Create a new msg window, by getting the position coordinates of the mouse over the tray icon to the msg window x,y parameters
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() { ('start create msgbox...') let webview = new WebviewWindow("msgbox", { url: "/msg", title: "Message notification", width: messageBoxWindowWidth, height: messageBoxWindowHeight, skipTaskbar: true, decorations: false, center: false, resizable: false, alwaysOnTop: true, focus: true, x: + 50, y: + 50, visible: false }) // Pallet message events await ('tauri://window-created', async () => { ('msgbox create') }) await ('tauri://blur', async () => { ('msgbox blur') const win = await ('msgbox') await () }) await ('tauri://error', async(error) => { ('msgbox error!', error) }) // Listening for Tray Events let trayEnterListen = listen('tray_mouseenter', async (event) => { // (event) const win = await ('msgbox') if(!win) return let position = if(win) { await (true) await () await (new LogicalPosition( - messageBoxWindowWidth / 2, - messageBoxWindowHeight)) await () } }) let trayLeaveListen = listen('tray_mouseleave', async (event) => { (event) const win = await ('msgbox') await () }) }
Setting the tray icon to blinkflashTray(true) and cancel blinkingflashTray(false)
<script setup> // ... const flashTimer = ref(false) const flashTray = async(bool) => { let flag = true if(bool) { ('tray').then(async(res) => { clearInterval() = setInterval(() => { if(flag) { (null) }else { // Supports placing custom icons in the default icons folder, set the icons in the following way // ('icons/') // Support for placing custom icons in a custom folder tray, requires configuration parameter "bundle": {"resources": ["tray"]} ('tray/') } flag = !flag }, 500) }) }else { clearInterval() let tray = await ("tray") ('icons/') } } </script>
Or put it in a custom folder.
If placed in the custom folder tray, you will need to configure thefileresourcesFields.
"bundle": { ... "resources": [ "tray" ] },
- Tray context menu
Actually, the window principle is similar to message alerts.
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 = (('logged')) ? 320 : 45 export default async function CreateTraymenu() { ('start create traymenu...') let webview = new WebviewWindow("traymenu", { url: "/menu", title: "Message notification", width: menuBoxWindowWidth, height: menuBoxWindowHeight, skipTaskbar: true, decorations: false, center: false, resizable: false, alwaysOnTop: true, focus: true, x: + 50, y: + 50, visible: false }) // Pallet message events await ('tauri://window-created', async () => { ('traymenu create') }) await ('tauri://blur', async () => { ('traymenu blur') const win = await ('traymenu') await () }) await ('tauri://error', async(error) => { ('traymenu error!', error) }) // Listening for Tray Events let trayEnterListen = listen('tray_contextmenu', async (event) => { (event) const win = await ('traymenu') if(!win) return let position = if(win) { await (true) await () await (new LogicalPosition(, - menuBoxWindowHeight)) await () } }) }
Msg/Template
<!--Tray context menu--> <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 = (('logged')) const handleMainShow = async () => { const traywin = await ('traymenu') await () const homewin = await ('main') await () await () await () } const flashTimer = ref(false) const flashTray = async(bool) => { let flag = true if(bool) { ('tray').then(async(res) => { clearInterval() = setInterval(() => { if(flag) { (null) }else { // (defaultIcon) // Supports placing custom icons in the default icons folder, set the icons in the following way // ('icons/') // Support for placing custom icons in a custom folder tray, requires configuration parameter "bundle": {"resources": ["tray"]} ('tray/') } flag = !flag }, 500) }) }else { clearInterval() let tray = await ("tray") ('icons/') } } </script> <template> <div v-if="logged" class="traymenu"> <p class="item">😍 I'm on the line.</p> <p class="item">😎 invisible (person or online status)</p> <p class="item">😏 take off</p> <p class="item">😱 bustling</p> <p class="item">Turn off all sounds</p> <p class="item" @click="flashTray(true)">Turn on icon blinking</p> <p class="item" @click="flashTray(false)">Turn off icon blinking</p> <p class="item" @click="handleMainShow">👀 Open the main panel</p> <p class="item">💍 abort</p> </div> <div v-else class="traymenu"> <p class="item">💍 abort</p> </div> </template>
In summary is tauri2 + vue3 development multi-window practice, customize the tray icon message reminder, the right-click menu of some simple to share, the function is still relatively rough, mainly for the realization of the functionality of the idea, I hope that the above sharing will help you ha!