Tauri + Vue 3:前端框架整合實戰
前言:為什麼選 Vue 3?
在上一篇文章中,我們認識了 Tauri 2.0 的基本概念和專案建立方式。現在是時候把前端框架帶進來了。
Vue 3 搭配 Tauri 是一個相當理想的組合。Vue 的 Composition API 讓程式碼組織更靈活,搭配 TypeScript 能提供完整的型別安全。加上 Vue 生態系的 Router 和 Pinia,你幾乎可以用開發 SPA 的方式來開發桌面應用——只不過這次你的「瀏覽器」是一個原生視窗。
建立 Tauri + Vue 3 專案
最快的方式是用 create-tauri-app 直接指定 Vue 模板:
npm create tauri-app@latest my-vue-tauri -- --template vue-ts
cd my-vue-tauri
npm install這會建立一個已經整合好 Vite + Vue 3 + TypeScript 的 Tauri 專案。接著安裝我們需要的套件:
# Vue Router 和 Pinia 狀態管理
npm install vue-router pinia
# Tauri API(用於呼叫系統功能)
npm install @tauri-apps/api @tauri-apps/plugin-notification @tauri-apps/plugin-clipboard-manager整合 Vue Router
桌面應用通常也有多個「頁面」或「視圖」。Vue Router 在這裡完美適用,只是我們用 createWebHashHistory 而不是 createWebHistory,因為 Tauri 的 WebView 不是真正的 HTTP 伺服器。
建立 src/router/index.ts:
import { createRouter, createWebHashHistory } from 'vue-router'
import HomeView from '../views/HomeView.vue'
import SettingsView from '../views/SettingsView.vue'
const router = createRouter({
history: createWebHashHistory(),
routes: [
{
path: '/',
name: 'home',
component: HomeView
},
{
path: '/settings',
name: 'settings',
component: SettingsView
}
]
})
export default router然後在 src/main.ts 中註冊:
import { createApp } from 'vue'
import { createPinia } from 'pinia'
import router from './router'
import App from './App.vue'
const app = createApp(App)
app.use(createPinia())
app.use(router)
app.mount('#app')Pinia 狀態管理
對於桌面應用來說,狀態管理特別重要。使用者的偏好設定、應用程式狀態等都需要集中管理。Pinia 是 Vue 3 官方推薦的狀態管理方案,語法簡潔、TypeScript 支援極佳。
建立一個簡單的應用狀態 store,src/stores/app.ts:
import { defineStore } from 'pinia'
import { ref } from 'vue'
export const useAppStore = defineStore('app', () => {
const title = ref('My Tauri App')
const isMaximized = ref(false)
const theme = ref<'light' | 'dark'>('light')
function toggleTheme() {
theme.value = theme.value === 'light' ? 'dark' : 'light'
}
return { title, isMaximized, theme, toggleTheme }
})使用 Tauri API
Tauri 2.0 的前端 API 透過 @tauri-apps/api 和各種插件提供。要使用這些功能,你需要先在 Tauri 的 capabilities 設定中授權。
設定權限
在 src-tauri/capabilities/default.json 中加入需要的權限:
{
"identifier": "default",
"description": "Default capabilities",
"windows": ["main"],
"permissions": [
"core:default",
"core:window:allow-minimize",
"core:window:allow-maximize",
"core:window:allow-unmaximize",
"core:window:allow-close",
"core:window:allow-start-dragging",
"core:window:allow-is-maximized",
"notification:default",
"notification:allow-notify",
"clipboard-manager:allow-write-text",
"clipboard-manager:allow-read-text"
]
}同時,在 src-tauri/Cargo.toml 中加入插件依賴:
[dependencies]
tauri = { version = "2", features = [] }
tauri-plugin-notification = "2"
tauri-plugin-clipboard-manager = "2"並在 src-tauri/src/lib.rs 中註冊插件:
pub fn run() {
tauri::Builder::default()
.plugin(tauri_plugin_notification::init())
.plugin(tauri_plugin_clipboard_manager::init())
.run(tauri::generate_context!())
.expect("error while running tauri application");
}視窗控制
桌面應用最基本的需求就是控制視窗。以下是在 Vue 元件中操作視窗的範例:
<script setup lang="ts">
import { getCurrentWindow } from '@tauri-apps/api/window'
import { useAppStore } from '../stores/app'
const appWindow = getCurrentWindow()
const store = useAppStore()
async function minimizeWindow() {
await appWindow.minimize()
}
async function toggleMaximize() {
if (await appWindow.isMaximized()) {
await appWindow.unmaximize()
store.isMaximized = false
} else {
await appWindow.maximize()
store.isMaximized = true
}
}
async function closeWindow() {
await appWindow.close()
}
</script>系統通知
使用 Tauri 的通知插件可以發送系統層級的通知:
import {
isPermissionGranted,
requestPermission,
sendNotification
} from '@tauri-apps/plugin-notification'
async function notify(title: string, body: string) {
let hasPermission = await isPermissionGranted()
if (!hasPermission) {
const permission = await requestPermission()
hasPermission = permission === 'granted'
}
if (hasPermission) {
sendNotification({ title, body })
}
}
// 使用方式
await notify('任務完成', '你的檔案已經成功匯出!')剪貼簿操作
import { writeText, readText } from '@tauri-apps/plugin-clipboard-manager'
// 複製文字到剪貼簿
async function copyToClipboard(text: string) {
await writeText(text)
}
// 讀取剪貼簿內容
async function pasteFromClipboard(): Promise<string> {
return await readText()
}自訂標題列
原生視窗的標題列雖然功能完整,但長得就是「系統預設款」。如果你想要一個品牌感更強的應用,自訂標題列是必經之路。
首先,在 tauri.conf.json 中關閉原生標題列裝飾:
{
"app": {
"windows": [
{
"title": "My Vue Tauri App",
"width": 1024,
"height": 768,
"decorations": false
}
]
}
}接著建立自訂標題列元件 src/components/TitleBar.vue:
<script setup lang="ts">
import { getCurrentWindow } from '@tauri-apps/api/window'
import { useAppStore } from '../stores/app'
const appWindow = getCurrentWindow()
const store = useAppStore()
async function handleMinimize() {
await appWindow.minimize()
}
async function handleToggleMaximize() {
const maximized = await appWindow.isMaximized()
if (maximized) {
await appWindow.unmaximize()
} else {
await appWindow.maximize()
}
store.isMaximized = !maximized
}
async function handleClose() {
await appWindow.close()
}
</script>
<template>
<div
class="titlebar"
data-tauri-drag-region
>
<div class="titlebar-title">{{ store.title }}</div>
<div class="titlebar-buttons">
<button @click="handleMinimize" class="btn-minimize">
−
</button>
<button @click="handleToggleMaximize" class="btn-maximize">
{{ store.isMaximized ? '⧉' : '□' }}
</button>
<button @click="handleClose" class="btn-close">
✕
</button>
</div>
</div>
</template>
<style scoped>
.titlebar {
display: flex;
justify-content: space-between;
align-items: center;
height: 36px;
padding: 0 12px;
background: #1a1a2e;
color: #e0e0e0;
user-select: none;
}
.titlebar-title {
font-size: 13px;
font-weight: 500;
}
.titlebar-buttons {
display: flex;
gap: 4px;
}
.titlebar-buttons button {
width: 32px;
height: 28px;
border: none;
background: transparent;
color: #e0e0e0;
font-size: 14px;
cursor: pointer;
border-radius: 4px;
display: flex;
align-items: center;
justify-content: center;
}
.titlebar-buttons button:hover {
background: rgba(255, 255, 255, 0.1);
}
.btn-close:hover {
background: #e81123 !important;
color: white;
}
</style>注意 data-tauri-drag-region 這個屬性——它告訴 Tauri 這個區域可以用來拖曳移動視窗,就像原生標題列一樣。
然後在 App.vue 中使用:
<script setup lang="ts">
import TitleBar from './components/TitleBar.vue'
</script>
<template>
<TitleBar />
<main class="content">
<router-view />
</main>
</template>
<style>
body {
margin: 0;
overflow: hidden;
}
.content {
height: calc(100vh - 36px);
overflow-y: auto;
}
</style>小結
到這裡,你已經建立了一個相當完整的 Tauri + Vue 3 桌面應用骨架:
- Vue Router 管理多頁面導航
- Pinia 集中管理應用狀態
- Tauri API 控制視窗行為
- 系統通知和剪貼簿等原生功能
- 自訂標題列提供品牌化的使用者體驗
這個架構已經足以應對大多數桌面應用的需求。接下來你可以加入更多功能,例如檔案系統操作、資料庫整合(搭配 SQLite)、或是自動更新機制。
Tauri 的哲學是「只給你需要的」,這和 Vue 的漸進式理念不謀而合。從一個簡單的工具開始,隨著需求成長逐步擴展——這才是工程的藝術。
分享這篇文章