跨平台框架怎么选:16 个框架全景对比(2026 版)
选错框架的代价:某团队用 Electron 做笔记应用,上线后用户反馈"启动 5 秒,内存 500MB"。重构用了 3 个月。如果一开始选 Tauri 或 Wails,这个坑完全可以避免。 本文目标:帮你在动手前想清楚。 覆盖范围:16 个框架,4 大技术路线 阅读建议: 在看具体框架前,你需要理解一个核心问题:UI 是怎么画到屏幕上的? 不同的"画法"决定了框架的基因,也决定了它擅长什么、不擅长什么。 原理:框架自己实现一套渲染引擎,拿到系统给的"画布"(Canvas/Surface),一笔一画把 UI 画出来。 类比:你买了一块空白画布,用自己的颜料和画笔画画。画出来的风格完全由你决定,跟画布是什么牌子的没关系。 代表框架:Flutter、Lynx、Qt Quick、GPUI、Dioxus、Slint 优势: 劣势: 原理:框架把你写的代码"翻译"成原生控件调用。你写 类比:你是导演,给演员(原生控件)下指令。演员按照各自平台的"表演风格"来演,iOS 演员演得像 iOS,Android 演员演得像 Android。 代表框架:React Native、.NET MAUI、Uno Platform、NativeScript、Valdi 优势: 劣势: 原理:用 Web 技术栈(HTML/CSS/JS)写 UI,通过 WebView 或内嵌 Chromium 来渲染。 类比:在应用里开了一个"浏览器窗口",你的 UI 实际上是一个网页。 代表框架:Electron、Tauri、Wails、Electrobun 优势: 劣势: Electron vs Tauri vs Electrobun 核心对比: 原理:只共享业务逻辑和数据层,UI 各平台自己写(或用 Compose Multiplatform 部分共享)。 类比:后厨(业务逻辑)是统一的,但前台装修(UI)各店不同。 代表框架:Kotlin Multiplatform (KMP) 优势: 劣势: 技术栈快速匹配: 下面我们按"成熟度从高到低"的顺序介绍每个框架。为了便于理解,我们将框架按技术路线分组呈现。 一句话定位:自绘渲染的"全能选手",跨端一致性最强的主流方案。 技术栈: 适合场景: 不太适合: 真实案例: 代码示例(感受一下 Dart 风格): 入门步骤: 常见坑: 一句话定位:用 React 写原生应用,前端团队的"舒适区扩展"。 技术栈: 适合场景: 不太适合: 真实案例: 代码示例: 入门步骤: 选择初始化方式: 常见坑: 一句话定位:用 Vue/Angular/Vanilla JS 写原生应用,填补非 React 前端技术栈的空白。 技术栈: 适合场景: 不太适合: 真实案例: 代码示例(Vue 风格): 入门步骤: 与 React Native 的对比: 一句话定位:Web 技术栈做桌面应用的"事实标准",简单粗暴但有效。 技术栈: 适合场景: 不太适合: 真实案例: 资源占用参考: 入门步骤: 性能优化技巧: 一句话定位:工业级跨平台方案,嵌入式和桌面的"老大哥"。 技术栈: 适合场景: 不太适合: 真实案例: 代码示例(QML): 许可证说明: 入门步骤: 一句话定位:C# 团队的跨平台方案,微软生态的"官方答案"。 技术栈: 适合场景: 不太适合: 代码示例: 入门步骤: 一句话定位:C# 生态的"全平台方案",比 .NET MAUI 更早、支持 WebAssembly。 技术栈: 与 .NET MAUI 的关键区别: 适合场景: 不太适合: 真实案例: 代码示例: 入门步骤: 安装 .NET SDK 和 Uno Platform 模板: 创建项目: 运行: WebAssembly 优势示例: 一句话定位:Electron 的"轻量替代品",用系统 WebView + Rust 后端。 技术栈: 与 Electron 的关键区别: 适合场景: 不太适合: 入门步骤: Rust 后端示例: 一句话定位:Go + WebView 的桌面应用方案,填补 Go 技术栈空白,比 Tauri 学习曲线更低。 技术栈: 核心优势: 桌面 WebView 方案全面对比: 适合场景: 不太适合: 真实案例: 代码示例(完整的类型安全流程): 步骤 1:后端 Go 方法 步骤 2:Wails 自动生成 TypeScript 类型 步骤 3:前端调用(完全类型安全) 快速开始(5 分钟): Wails v2 vs v3(2025 重大更新): Wails v3 正在开发中,主要改进: 性能优化技巧: 使用 Go 的并发优势: 使用事件系统(前后端通信): 按需构建(减小包体): 常见问题: Wails vs Tauri 选择指南: 一句话定位:Android 团队扩展 iOS 的"最小阻力路径",逻辑共享优先。 技术栈: UI 方案: 核心概念: 适合场景: 不太适合: 代码示例: 入门步骤: 一句话定位:字节跳动的跨端方案,用 Web 语法写原生渲染的 UI。 技术栈: 核心特点: 适合场景: 不太适合: 代码示例: 入门步骤: 一句话定位:TypeScript 编译成原生视图,追求 TS 开发体验 + 原生性能。 技术栈: 核心理念: 适合场景: 不太适合: 入门步骤: 一句话定位:比 Electron 更轻量的桌面方案,用 Bun + 系统 WebView/CEF。 技术栈: 与 Electron/Tauri 对比: 适合场景: 入门步骤: 一句话定位:Rust 版的 React,用 React-like 语法写全平台 UI,Rust 生态的"全能选手"。 技术栈: 核心优势: 与其他 Rust GUI 框架的对比: 适合场景: 不太适合: 真实案例: 代码示例(感受 Rust + React 的组合): 基础计数器: 组件复用(像 React 一样): 异步数据获取(类似 React Query): 多渲染后端示例: 入门步骤: 安装 Rust 和 Dioxus CLI: 创建项目(自动配置): 开发模式(带热重载): 构建生产版本: Dioxus 0.5 的重大改进(2024): 性能优化技巧: 利用 Rust 的零成本抽象: 使用 memo 避免重渲染: WASM 优化: TUI 应用示例(独特优势): 常见坑: 生命周期标注: 异步运行时: 跨平台样式: Rust GUI 框架选择指南: 未来展望: 一句话定位:嵌入式和桌面 GUI 框架,填补"Qt 太重,Flutter 太大"的空白。 技术栈: 核心特点: 极致轻量 多语言支持 设计师友好 与 Qt 的对比(嵌入式场景): 适合场景: 不太适合: 真实案例: 代码示例(感受 Slint 的 DSL): UI 文件( Rust 调用: C++ 调用(嵌入式团队友好): 入门步骤: 安装 Slint(Rust 项目): 创建 UI 文件: 配置 build.rs(自动编译 .slint 文件): 运行: 可视化设计工具: 嵌入式示例(软件渲染,适合无 GPU 设备): 常见坑: 什么时候选 Slint 而不是 Qt? 选 Slint 如果: 选 Qt 如果: 一句话定位:Zed 编辑器的 UI 框架,Rust 生态的高性能 GUI 方案。 技术栈: 核心特点: 适合场景: 不太适合: 代码示例: 入门步骤: 指标说明: 不想看详细分析?根据你的情况直接查表: 推荐:Flutter / Lynx 理由: 备选:Qt Quick(如果团队熟悉 C++) 快速决策: 推荐:.NET MAUI 理由: 备选:Qt(如果需要嵌入式支持)/ Electron(如果有 Web 版需求) 推荐:KMP(逻辑共享 + 原生 UI) 理由: 进阶:如果想共享部分 UI → KMP + Compose Multiplatform 推荐:React Native / KMP(原生 UI) 理由: 备选:.NET MAUI、纯原生 推荐:Tauri(桌面)/ Valdi(移动) 理由: 备选:KMP + 原生 UI 推荐:Flutter 理由: 备选:Qt(工业场景)、各平台分别开发 推荐: 理由: 选择建议: 推荐:Slint(首选)/ Qt(工业级) 理由: 选择建议: 推荐:NativeScript 理由: 备选:Flutter(如果愿意学 Dart) 推荐:Uno Platform 理由: 备选:Blazor WebAssembly(纯 Web)+ .NET MAUI(原生) 在最终决定前,问自己这些问题: 基础问题: 新增考虑点(针对新框架): 成熟稳定层(生产环境可放心使用): 快速上升层(已有成功案例,值得认真考虑): 新锐探索层(有潜力,需承担早期风险): 自绘渲染持续演进 Rust 生态全面爆发(重要趋势) WebView 方案的"语言多样化" 逻辑共享成为共识 WebAssembly 的崛起 类型安全成为标配 前端框架语法的多样化 嵌入式 GUI 的轻量化 选框架不是选"最好的",而是选"最适合的"。 如果你只记住一件事,那就是: 2026 关键变化总结: 选型建议(按风险偏好): 祝选型顺利! 成熟框架: 新兴框架: 对比文章: 生产实践案例: 技术深度解析:跨平台不是"能不能跑",而是"用哪条技术路线换哪种确定性"。
第一章:先搞懂底层逻辑
1.1 四种技术路线
路线一:自绘渲染(Self-rendering)
┌─────────────────────────────────────┐
│ 你的应用代码 │
├─────────────────────────────────────┤
│ 框架的渲染引擎 │ ← 这一层是框架自己实现的
├─────────────────────────────────────┤
│ 系统图形 API (Metal/Vulkan/GL) │
├─────────────────────────────────────┤
│ GPU │
└─────────────────────────────────────┘路线二:原生控件映射(Native Bridging)
<Button>,框架帮你调用 iOS 的 UIButton 或 Android 的 MaterialButton。┌─────────────────────────────────────┐
│ 你的应用代码 │
├─────────────────────────────────────┤
│ 框架的桥接层 (Bridge) │ ← 翻译 + 通信
├─────────────────────────────────────┤
│ 原生控件 (UIKit / Android Views) │
├─────────────────────────────────────┤
│ 系统 │
└─────────────────────────────────────┘路线三:WebView/Chromium 方案
┌─────────────────────────────────────┐
│ 你的 Web 应用 (HTML/CSS/JS) │
├─────────────────────────────────────┤
│ WebView / Chromium / 系统浏览器 │
├────────────────┬────────────────────┤
│ 后端进程 │ 系统 API 调用 │
│ (Node/Rust) │ │
└────────────────┴────────────────────┘维度 Electron Tauri Electrobun 渲染引擎 内嵌 Chromium 系统 WebView 系统 WebView/CEF 后端语言 Node.js Rust Bun (TypeScript) 包体大小 150MB+ 3-10MB 10-30MB 启动速度 慢(初始化大) 快 中等 适合团队 前端团队 愿意学 Rust 前端团队 路线四:逻辑共享优先(Shared Logic First)
┌──────────────────────────────────────────────────┐
│ 共享层 (Kotlin) │
│ 网络、数据库、业务逻辑、状态管理 │
├─────────────────┬────────────────┬───────────────┤
│ Android UI │ iOS UI │ Desktop UI │
│ (Compose) │ (SwiftUI) │ (Compose) │
└─────────────────┴────────────────┴───────────────┘1.2 一张图看懂路线选择
你的核心诉求是什么?
│
┌─────────────────┼─────────────────┐
▼ ▼ ▼
跨端一致性 原生体验 开发效率
视觉完全统一 系统深度集成 快速上线
│ │ │
▼ ▼ ▼
自绘渲染 原生映射 WebView 方案
Flutter/Lynx/ RN/MAUI/Uno/ Electron/Tauri/
Dioxus/Slint/Qt NativeScript/KMP Wails/Electrobun你的团队主要用什么语言?
│
├─ JavaScript/TypeScript
│ ├─ React → React Native / Lynx
│ ├─ Vue/Angular → NativeScript
│ └─ 任意框架 → Electron / Tauri / Wails / Electrobun
│
├─ Dart → Flutter
│
├─ C# → .NET MAUI / Uno Platform(需要 WASM)
│
├─ C++ → Qt / Slint(嵌入式)
│
├─ Go → Wails(桌面)
│
├─ Kotlin → KMP
│
└─ Rust
├─ Web 前端 → Tauri
├─ 全栈(含 UI)→ Dioxus
├─ 嵌入式 → Slint
└─ 极致性能 → GPUI第二章:16 个框架逐一拆解
2.1 Flutter(Google,2018 稳定版)
// 一个简单的计数器页面
class CounterPage extends StatefulWidget {
@override
_CounterPageState createState() => _CounterPageState();
}
class _CounterPageState extends State<CounterPage> {
int _count = 0;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('计数器')),
body: Center(
child: Text('点击了 $_count 次', style: TextStyle(fontSize: 24)),
),
floatingActionButton: FloatingActionButton(
onPressed: () => setState(() => _count++),
child: Icon(Icons.add),
),
);
}
}flutter doctorflutter create my_appcd my_app && flutter run--split-debug-info 和 --obfuscate 可减小约 30%Info.plist 里的权限说明清晰2.2 React Native(Meta,2015)
// React Native 的代码对 React 开发者很熟悉
import React, { useState } from 'react';
import { View, Text, TouchableOpacity, StyleSheet } from 'react-native';
export default function Counter() {
const [count, setCount] = useState(0);
return (
<View style={styles.container}>
<Text style={styles.text}>点击了 {count} 次</Text>
<TouchableOpacity style={styles.button} onPress={() => setCount(c => c + 1)}>
<Text style={styles.buttonText}>+1</Text>
</TouchableOpacity>
</View>
);
}
const styles = StyleSheet.create({
container: { flex: 1, justifyContent: 'center', alignItems: 'center' },
text: { fontSize: 24, marginBottom: 20 },
button: { backgroundColor: '#007AFF', padding: 15, borderRadius: 8 },
buttonText: { color: 'white', fontSize: 18 },
});npx create-expo-app my-app(Expo 托管方案)npx react-native init MyApp(裸 RN)npx expo start 或 npx react-native run-ios2.3 NativeScript(Progress Software,2014)
<template>
<Page>
<ActionBar title="计数器"/>
<StackLayout class="p-20">
<Label :text="`点击了 ${count} 次`" class="text-center text-2xl mb-4"/>
<Button text="+1" @tap="count++" class="btn btn-primary"/>
</StackLayout>
</Page>
</template>
<script>
export default {
data() {
return {
count: 0
}
}
}
</script>npm install -g @nativescript/clins create my-app --vue 或 --angularns run ios 或 ns run android维度 React Native NativeScript 框架支持 React Vue/Angular/Vanilla 原生访问 通过桥接 直接访问 性能 有桥接开销 理论上更快 生态 更大 较小 2.4 Electron(GitHub/OpenJS Foundation,2013)
npm init -ynpm install -D electronmain.js:const { app, BrowserWindow } = require('electron');
app.whenReady().then(() => {
const win = new BrowserWindow({ width: 800, height: 600 });
win.loadFile('index.html');
});package.json:"start": "electron ."npm startBrowserWindow 的 show: false + ready-to-show 事件避免白屏contextIsolation 提升安全性2.5 Qt / Qt Quick(The Qt Company,1995/2010)
// QML 声明式 UI,类似 JSON 但带逻辑
import QtQuick 2.15
import QtQuick.Controls 2.15
ApplicationWindow {
width: 400
height: 300
visible: true
title: "计数器"
Column {
anchors.centerIn: parent
spacing: 20
Text {
text: "点击了 " + counter + " 次"
font.pixelSize: 24
}
Button {
text: "+1"
onClicked: counter++
}
}
property int counter: 0
}2.6 .NET MAUI(Microsoft,2022)
// .NET MAUI 的 XAML + C# 模式
// MainPage.xaml
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui">
<VerticalStackLayout Spacing="20" VerticalOptions="Center">
<Label x:Name="CounterLabel" Text="点击了 0 次" FontSize="24" HorizontalOptions="Center"/>
<Button Text="+1" Clicked="OnCounterClicked" HorizontalOptions="Center"/>
</VerticalStackLayout>
</ContentPage>
// MainPage.xaml.cs
public partial class MainPage : ContentPage
{
int count = 0;
public MainPage() => InitializeComponent();
void OnCounterClicked(object sender, EventArgs e)
{
count++;
CounterLabel.Text = $"点击了 {count} 次";
}
}dotnet workload install mauidotnet new maui -n MyApp2.7 Uno Platform(Uno Platform,2018)
维度 .NET MAUI Uno Platform 发布时间 2022 2018 WebAssembly 不支持 支持(核心优势) API 来源 Xamarin.Forms 演进 WinUI/UWP Windows 优先度 中等 高(WinUI 语法) Linux 支持 有限 通过 Skia 支持 <!-- MainPage.xaml - 与 WinUI 语法兼容 -->
<Page x:Class="MyApp.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<StackPanel Spacing="20" HorizontalAlignment="Center" VerticalAlignment="Center">
<TextBlock x:Name="CounterText" Text="点击了 0 次" FontSize="24"/>
<Button Content="+1" Click="OnCounterClicked"/>
</StackPanel>
</Page>// MainPage.xaml.cs
public sealed partial class MainPage : Page
{
private int _count = 0;
public MainPage()
{
this.InitializeComponent();
}
private void OnCounterClicked(object sender, RoutedEventArgs e)
{
_count++;
CounterText.Text = $"点击了 {_count} 次";
}
}dotnet new install Uno.Templatesdotnet new unoapp -o MyAppdotnet run --project MyApp.Wasm# 构建 WebAssembly 版本
dotnet publish MyApp.Wasm -c Release
# 直接部署到 Web 服务器,无需应用商店审核
# 用户通过浏览器访问即可使用2.8 Tauri(Tauri Programme,2022 v1.0)
维度 Electron Tauri 包体(空项目) ~150MB ~3MB 内存(空项目) ~100MB ~30MB 后端语言 Node.js Rust WebView 内嵌 Chromium 系统自带 跨端一致性 高(同一个 Chromium) 中(系统 WebView 版本不同) npm create tauri-app@latestnpm run tauri devnpm run tauri build// src-tauri/src/main.rs
#[tauri::command]
fn greet(name: &str) -> String {
format!("Hello, {}!", name)
}
fn main() {
tauri::Builder::default()
.invoke_handler(tauri::generate_handler![greet])
.run(tauri::generate_context!())
.expect("error while running tauri application");
}// 前端调用
import { invoke } from '@tauri-apps/api/tauri';
const greeting = await invoke('greet', { name: 'World' });2.9 Wails(Wails Project,2019 / v2 2022)【重点推荐】
优势 说明 对比 学习曲线低 Go 比 Rust 容易学 比 Tauri 门槛低 50% 类型安全 自动生成 TS 类型 编译时发现错误 并发能力强 goroutine 原生支持 适合高并发场景 包体适中 10-15MB 比 Electron 小 90% 编译快 Go 编译速度快 比 Rust 快 5-10 倍 维度 Electron Tauri Wails Electrobun 后端语言 Node.js Rust Go Bun (TS) 学习曲线 低(JS/TS) 高(Rust陡) 低(Go易学) 低(TS) 包体大小 150MB 3MB 10MB 15MB 内存占用 100MB 30MB 45MB 50MB 编译速度 无需编译 慢(Rust) 快(Go) 快 并发模型 事件循环 异步+线程 goroutine 异步 类型安全 JS→TS 手动定义 自动生成TS TS 原生 生态成熟度 5/5 4/5 3/5 2/5 // app.go - 定义后端方法
type App struct {
ctx context.Context
}
func (a *App) Greet(name string) string {
return fmt.Sprintf("Hello %s!", name)
}
func (a *App) ProcessFile(path string) error {
// 利用 Go 的 goroutine 并发处理
go func() {
// 后台处理文件
}()
return nil
}// wailsjs/go/models.ts - 自动生成,无需手写
export namespace main {
export class App {
static Greet(name: string): Promise<string>;
static ProcessFile(path: string): Promise<void>;
}
}import { Greet } from '../wailsjs/go/main/App';
const result = await Greet("World"); // ✅ 类型正确
// await Greet(123); // ❌ TypeScript 编译错误核心优势:前后端接口不匹配在编译时就能发现,而不是运行时报错。
# 1. 安装 CLI
go install github.com/wailsapp/wails/v2/cmd/wails@latest
# 2. 检查环境
wails doctor
# 3. 创建项目(选择模板:react/vue/svelte)
wails init -n myapp -t react
# 4. 开发(热重载)
cd myapp && wails dev
# 5. 构建
wails build # 输出: myapp.app / myapp.exe / myapp// 并行处理多个任务
func (a *App) ProcessMultipleFiles(files []string) {
var wg sync.WaitGroup
for _, file := range files {
wg.Add(1)
go func(f string) {
defer wg.Done()
// 处理文件
}(file)
}
wg.Wait()
}// 后端发送事件
runtime.EventsEmit(a.ctx, "progress", Progress{
Current: 50,
Total: 100,
})// 前端监听事件
import { EventsOn } from '../wailsjs/runtime';
EventsOn('progress', (data) => {
console.log(`Progress: ${data.current}/${data.total}`);
});# 只构建当前平台
wails build
# 跨平台构建
wails build -platform darwin/amd64,darwin/arm64,windows/amd64问题 解决方案 Windows 缺少 WebView2 引导用户安装 WebView2 Runtime 跨平台 WebView 差异 测试各平台,使用 polyfill Go 依赖管理 运行 go mod tidy前端资源路径错误 检查 wails.json 配置维度 选 Wails 选 Tauri 团队技能 熟悉 Go / 不想学 Rust 愿意学 Rust 后端需求 高并发(goroutine) 一般 包体要求 10MB 可接受 要求最小(3MB) 编译速度 要求快 可接受慢 类型安全 要自动生成 手动定义可接受 生态成熟度 可接受成长期 要求更成熟 2.10 Kotlin Multiplatform / KMP(JetBrains,2023 稳定版)
commonMain(纯 Kotlin,编译到各平台)┌────────────────────────────────────────────────┐
│ commonMain │
│ expect fun getPlatformName(): String │ ← 声明接口
├──────────────────────┬─────────────────────────┤
│ androidMain │ iosMain │
│ actual fun get..() │ actual fun get..() │ ← 各平台实现
│ = "Android" │ = "iOS" │
└──────────────────────┴─────────────────────────┘// commonMain - 共享的网络请求逻辑
class UserRepository(private val api: UserApi) {
suspend fun getUser(id: String): User {
return api.fetchUser(id)
}
}
// 在 Android 和 iOS 中都可以直接使用
val repo = UserRepository(api)
val user = repo.getUser("123")shared/src/commonMain 中编写共享逻辑shared 模块2.11 Lynx(ByteDance,2024 开源)
// Lynx 的语法对 React 开发者很熟悉
import { Component, View, Text, Image } from '@anthropic/lynx';
export default class App extends Component {
state = { count: 0 };
render() {
return (
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
<Text style={{ fontSize: 24 }}>点击了 {this.state.count} 次</Text>
<View
style={{ padding: 15, backgroundColor: '#007AFF', borderRadius: 8 }}
onClick={() => this.setState({ count: this.state.count + 1 })}
>
<Text style={{ color: 'white' }}>+1</Text>
</View>
</View>
);
}
}2.12 Valdi(Snapchat,2024 Beta)
2.13 Electrobun(2024 早期)
维度 Electron Tauri Electrobun 后端 Node.js Rust Bun (TS) 学习成本 低 中(要学 Rust) 低 包体 大 小 中 成熟度 高 中 早期 2.14 Dioxus(Dioxus Labs,2021 / v0.5 2024)【重点推荐】
优势 说明 独特性 React-like 语法 前端开发者易上手 Rust GUI 中最像 React 多渲染后端 Web/Desktop/Mobile/TUI 一套代码多平台 WASM 性能 接近原生的 Web 性能 比 JS 快 2-10 倍 类型安全 Rust 编译时检查 内存安全 + 线程安全 TUI 支持 终端 UI 独特优势 其他框架都不支持 维度 Dioxus GPUI Tauri egui 语法风格 React-like Rust 原生 Web 前端 即时模式 学习曲线 低(前端易上手) 高(需熟练 Rust) 低(会 Web 即可) 中等 移动端支持 开发中 无 v2 支持 有限 Web 支持 5/5 完整 WASM 无 5/5 完整 3/5 有限 TUI 支持 5/5 独特优势 无 无 无 组件生态 3/5 成长中 2/5 早期 5/5(npm生态) 3/5 渲染性能 4/5 强 5/5 极强 3/5 中等 4/5 强 成熟度 3/5 成长中 3/5 成长中 4/5 稳定 4/5 稳定 use dioxus::prelude::*;
fn main() {
dioxus_desktop::launch(App);
}
fn App(cx: Scope) -> Element {
let mut count = use_state(cx, || 0);
cx.render(rsx! {
div {
style: "display: flex; flex-direction: column; align-items: center; gap: 20px;",
h1 { "计数器" }
p {
style: "font-size: 24px;",
"点击了 {count} 次"
}
button {
onclick: move |_| count += 1,
style: "padding: 10px 20px; font-size: 18px;",
"+1"
}
}
})
}// 可复用的 Button 组件
#[component]
fn MyButton<'a>(
cx: Scope<'a>,
onclick: EventHandler<'a, MouseEvent>,
children: Element<'a>,
) -> Element<'a> {
cx.render(rsx! {
button {
class: "custom-button",
onclick: move |evt| onclick.call(evt),
children
}
})
}
// 使用组件
fn App(cx: Scope) -> Element {
cx.render(rsx! {
MyButton {
onclick: |_| println!("Clicked!"),
"点击我"
}
})
}use dioxus::prelude::*;
fn App(cx: Scope) -> Element {
let user_data = use_future(cx, (), |_| async move {
// 异步请求数据
reqwest::get("https://api.example.com/user")
.await?
.json::<User>()
.await
});
cx.render(match user_data.value() {
None => rsx! { p { "加载中..." } },
Some(Ok(user)) => rsx! {
div {
h1 { "欢迎, {user.name}" }
p { "邮箱: {user.email}" }
}
},
Some(Err(e)) => rsx! { p { "错误: {e}" } },
})
}// 同一套代码,不同渲染后端
// 1. 桌面应用(WebView)
fn main() {
dioxus_desktop::launch(App);
}
// 2. Web 应用(WASM)
fn main() {
dioxus_web::launch(App);
}
// 3. 终端 UI(TUI)
fn main() {
dioxus_tui::launch(App);
}
// 4. 服务端渲染(SSR)
fn main() {
let html = dioxus_ssr::render(&App(cx));
// 返回 HTML 字符串
}# 安装 Rust
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
# 安装 Dioxus CLI
cargo install dioxus-clidx new my-app
# 选择模板:web, desktop, mobile, TUIcd my-app
dx serve # Web
# 或
dx serve --platform desktop # 桌面dx build --release// 组件会在编译时优化
#[inline(always)]
#[component]
fn FastComponent(cx: Scope) -> Element {
// 编译器会内联这个组件
}let expensive = use_memo(cx, (dep1, dep2), |(d1, d2)| {
// 只在 dep1 或 dep2 变化时重新计算
heavy_computation(d1, d2)
});# 构建优化的 WASM
dx build --release --platform web
# 生成的 WASM 包通常只有几百 KB// 用同样的代码创建漂亮的终端 UI
use dioxus::prelude::*;
use dioxus_tui::Config;
fn main() {
dioxus_tui::launch_cfg(
App,
Config::new().with_rendering_mode(RenderingMode::Ansi),
);
}
fn App(cx: Scope) -> Element {
let mut count = use_state(cx, || 0);
cx.render(rsx! {
div {
border_width: "1px",
padding: "2",
h1 { "Terminal Counter" }
p { "Count: {count}" }
button {
onclick: move |_| count += 1,
"Increment"
}
}
})
}use_future 而不是手动管理需求 推荐框架 理由 Web + 桌面共享代码 Dioxus WASM + 多后端 前端团队用 Rust 后端 Tauri 前后端分离 React 开发者转 Rust Dioxus 语法相似 需要 TUI(终端界面) Dioxus 独特支持 追求极致性能(编辑器) GPUI 为 Zed 设计 嵌入式设备 Slint 轻量级 要 npm 生态 Tauri Web 前端 2.15 Slint(SixtyFPS GmbH,2020 / v1.0 2023)
.slint 文件)维度 Qt (Qt Quick) Slint 最小包体 ~10-20MB ~300KB 内存占用 ~20-50MB ~2-10MB 启动速度 慢 快 MCU 支持 需要 Qt for MCUs(商业版) 开源版支持 许可证 LGPL/GPL 或商业 GPL/商业(企业版) 学习曲线 中 低 工业案例 5/5 极多 3/5 成长中 .slint 声明式语法):// counter.slint
import { Button, VerticalBox } from "std-widgets.slint";
export component Counter {
in-out property <int> counter: 0;
VerticalBox {
Text {
text: "点击了 \{counter} 次";
font-size: 24px;
}
Button {
text: "+1";
clicked => {
counter += 1;
}
}
}
}// main.rs
slint::slint! {
import { Counter } from "counter.slint";
}
fn main() {
let ui = Counter::new().unwrap();
// 可以从 Rust 代码访问和修改属性
ui.set_counter(0);
// 监听属性变化
ui.on_counter_changed(|value| {
println!("Counter changed to: {}", value);
});
ui.run().unwrap();
}// main.cpp
#include "counter.h"
int main() {
auto ui = Counter::create();
// C++ API 类型安全
ui->set_counter(0);
// 回调
ui->on_counter_changed([](int value) {
std::cout << "Counter: " << value << std::endl;
});
ui->run();
}cargo new my-app
cd my-app
cargo add slint# 创建 ui/counter.slint
mkdir ui// build.rs
fn main() {
slint_build::compile("ui/counter.slint").unwrap();
}cargo run# 安装 Slint UI Designer
cargo install slint-viewer
# 实时预览 .slint 文件
slint-viewer ui/counter.slintuse slint::platform::software_renderer::{MinimalSoftwareWindow, RepaintBufferType};
fn main() {
slint::platform::set_platform(Box::new(MyPlatform::new())).unwrap();
let ui = Counter::new().unwrap();
// 渲染到帧缓冲区
let window = ui.window();
window.set_size(slint::PhysicalSize::new(800, 480));
// 自定义事件循环(适合 bare-metal 环境)
loop {
slint::platform::update_timers_and_animations();
window.draw_if_needed(|renderer| {
// 渲染到你的帧缓冲区
});
}
}.slint 语法需要学习,但比 QML 简单2.16 GPUI(Zed Industries,2024)
// GPUI 的 Rust 风格 UI
use gpui::*;
struct Counter {
count: i32,
}
impl Render for Counter {
fn render(&mut self, cx: &mut ViewContext<Self>) -> impl IntoElement {
div()
.flex()
.flex_col()
.items_center()
.child(format!("Count: {}", self.count))
.child(
button("Increment")
.on_click(cx.listener(|this, _, _| this.count += 1))
)
}
}curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | shcargo new my_appcargo run第三章:横向对比
3.1 核心信息对照表
框架 渲染方式 语言 平台覆盖 生态成熟度 一句话定位 Flutter 自绘 Dart 移动+桌面+Web 5/5 成熟 全能选手,跨端一致性最强 React Native 原生映射 JS/TS 移动为主 5/5 成熟 前端团队的原生应用方案 NativeScript 原生映射 JS/TS+Vue/Angular 移动 3/5 成长中 Vue/Angular 写原生应用 Electron WebView JS/TS 桌面 5/5 成熟 Web 做桌面的事实标准 Qt Quick 自绘 C++/QML 全平台+嵌入式 5/5 成熟 工业级、嵌入式首选 .NET MAUI 原生映射 C# 全平台 4/5 稳定 C# 团队的官方方案 Uno Platform 原生/WASM C# 全平台+Web 4/5 稳定 C# + WebAssembly Tauri 系统WebView+Rust Rust+Web 桌面+移动 4/5 稳定 轻量级 Electron 替代 Wails 系统WebView+Go Go+Web 桌面 3/5 成长中 Go 技术栈做桌面 KMP 原生/Compose Kotlin 移动+桌面 4/5 稳定 Android 团队扩 iOS Lynx 自绘 JS/TS 移动+Web 3/5 成长中 高性能+Web语法 Valdi 编译到原生 TypeScript 移动 2/5 早期 TS 编译到原生 Electrobun 系统WebView/CEF TypeScript 桌面 2/5 早期 轻量桌面方案 Dioxus 自绘/多后端 Rust 全平台+TUI 3/5 成长中 Rust 版 React Slint 自绘 Rust/C++/JS 桌面+嵌入式 3/5 成长中 轻量嵌入式 GUI GPUI 自绘 Rust 桌面 2/5 早期 Rust 高性能 GUI 3.2 指标矩阵
说明:以下评价基于渲染原理和生态现状的一般判断,实际表现取决于具体实现。评分采用 1-5 分制,5 分最高。
框架 包体/启动 性能上限 原生体验 跨端一致 开发效率 生产风险 Flutter 3 中等 5 极强 3 一般 5 极强 5 极高 低 React Native 3 中等 4 强 5 极强 3 一般 5 极高 低 NativeScript 3 中等 4 强 5 极强 3 一般 4 高 中 Electron 2 大/慢 3 中等 3 一般 5 极强 5 极高 低 Qt Quick 3 中等 5 极强 3 一般 5 极强 3 中等 低 .NET MAUI 3 中等 4 强 5 极强 3 一般 4 高 低 Uno Platform 3 中等 4 强 4 强 4 强 4 高 中 Tauri 5 小/快 4 强 3 一般 4 强 4 高 中 Wails 4 小/快 4 强 3 一般 4 强 5 极高 中 KMP 视UI方案 视UI方案 5 极强 3 一般 4 高 中 Lynx 4 小/快 5 极强 3 一般 5 极强 4 高 高 Valdi 4 小/快 5 极强 5 极强 3 一般 3 中等 高 Electrobun 4 小/快 3 中等 3 一般 4 强 4 高 高 Dioxus 4 小/快 5 极强 3 一般 4 强 4 高 高 Slint 5 小/快 4 强 3 一般 5 极强 3 中等 中 GPUI 4 小/快 5 极强 3 一般 3 一般 3 中等 高 第四章:场景化选型指南
快速决策表
按技术栈选择
你的技术栈 首选 备选 理由 React React Native Lynx 复用 React 技能 Vue/Angular NativeScript Flutter 直接用 Vue/Angular Go Wails - 唯一的 Go 桌面方案 Rust(有前端) Tauri Dioxus 前后端分离 Rust(纯 Rust) Dioxus GPUI React-like 语法 C# .NET MAUI Uno Platform 微软生态 C++ Qt Slint 工业级/嵌入式 Kotlin KMP Flutter Android 团队扩展 按需求选择
你的需求 推荐框架 原因 极致跨端一致性 Flutter, Qt 自绘渲染 极小包体(< 5MB) Tauri, Slint 系统 WebView/轻量 原生体验优先 React Native, .NET MAUI 原生控件 嵌入式设备 Slint, Qt 资源占用低 需要 WebAssembly Uno Platform, Dioxus 浏览器运行 需要终端 UI(TUI) Dioxus 独特优势 快速原型 Electron, Flutter 工具链成熟 场景 A:移动端为主,重动效、品牌视觉统一
典型产品:电商首页、社交 feed、游戏化应用
场景 B:桌面应用(按技术栈)
团队技术栈 首选方案 优势 典型产品 纯前端团队 Electron 生态最成熟,工具链完善 VS Code, Slack 前端 + 在意包体 Tauri 包体小(3MB),启动快 系统工具 Go 后端团队 Wails 无需学 Rust,类型安全 运维面板,数据处理 Rust 团队 Tauri 安全性高,插件生态好 开发工具 想尝新 Electrobun Bun 运行时,TS 全栈 原型项目 场景 C:企业内部应用,C# 团队,长期维护
典型产品:ERP、CRM、内部审批系统
场景 D:Android 团队扩展 iOS
典型产品:已有 Android 应用,想扩展到 iOS
场景 E:需要深度系统集成
典型产品:文件管理器、系统工具、相机应用
场景 F:极度关注包体大小
典型产品:Lite 版应用、下沉市场、低端设备
场景 G:全平台覆盖(移动 + 桌面 + Web)
典型产品:跨平台协作工具、内容消费应用
场景 H:Rust 技术栈做桌面应用
典型产品:开发工具、性能敏感型应用
场景 I:嵌入式设备 GUI
典型产品:智能家居面板、车载 HMI、工业控制、医疗设备
场景 J:Vue/Angular 团队做移动应用
典型产品:企业内部应用、内容展示应用
场景 K:C# 团队,需要 WebAssembly
典型产品:需要 Web 版的企业应用、渐进式 Web 应用
第五章:选型方法论
5.1 三步选型法
Step 1: 确定渲染路线
│
├── 需要跨端视觉完全一致 → 自绘渲染(Flutter/Lynx/Qt)
├── 需要原生体验优先 → 原生映射(RN/MAUI/KMP)
└── 需要快速上线、前端技术栈 → WebView(Electron/Tauri)
Step 2: 确定平台覆盖
│
├── 移动端为主 → Flutter/RN/Lynx/KMP
├── 桌面端为主 → Electron/Tauri/Qt/GPUI
└── 全平台 → Flutter/Qt
Step 3: 匹配团队技能
│
├── Dart → Flutter
├── JS/TS + React → React Native / Lynx / Dioxus(想学 Rust)
├── JS/TS + Vue/Angular → NativeScript
├── JS/TS + 任意框架 → Electron / Tauri / Wails / Electrobun
├── C# → .NET MAUI / Uno Platform(需要 WASM)
├── C++ → Qt / Slint(嵌入式)
├── Go → Wails
├── Kotlin → KMP
└── Rust → Tauri(Web前端) / Dioxus(全栈) / GPUI(纯Rust) / Slint(嵌入式)5.2 决策检查清单
第六章:趋势观察
6.1 当前格局(2026 更新)
6.2 趋势预判
总结
先想清楚你的核心诉求是什么——跨端一致性、原生体验、还是开发效率?然后在对应的技术路线里,选一个匹配团队技能的框架。
变化 具体表现 影响 1. 桌面方案多元化 Electron/Tauri/Wails/Electrobun 每个后端语言都有选择 2. Rust GUI 成熟 Tauri/Dioxus/Slint/GPUI 覆盖全场景 3. 前端多样化 React/Vue/Angular 都有方案 不再是 React 独大 4. WASM 普及 Uno/Dioxus 支持 浏览器运行原生性能 5. 嵌入式轻量化 Slint 挑战 Qt 低端设备新选择 稳妥派(生产环境)
├─ 移动端:Flutter, React Native
├─ 桌面端:Electron, Qt
└─ C# 生态:.NET MAUI, Uno Platform
平衡派(值得尝试)
├─ Go 桌面:Wails
├─ Rust 全栈:Dioxus
└─ 逻辑共享:KMP
激进派(原型/小项目)
├─ Lynx, Valdi(移动端新思路)
├─ Electrobun(桌面 Bun 方案)
└─ Slint(嵌入式轻量)参考资源
官方文档
延伸阅读