asp 网站卡死,中国建设银行网站软件,工会网站群建设,建设通网站上的业绩能否删除掉本文是对视频 Tauri入门教程[1]的学习与记录 Tauri官网[2] 对 node版本有要求 创建项目及目录介绍: 项目的目录结构如下 可以安装推荐的插件 执行npm run tauri build出错,根据 https://github.com/tauri-apps/tauri/issues/7430 执行 yarn add -D tauri-apps/cli y… 本文是对视频 Tauri入门教程[1]的学习与记录 Tauri官网[2] 对 node版本有要求 创建项目及目录介绍: 项目的目录结构如下 可以安装推荐的插件 执行npm run tauri build出错,根据 https://github.com/tauri-apps/tauri/issues/7430 执行 yarn add -D tauri-apps/cli yarn install 也有其他办法, 可参考[3] 然后再执行npm run tauri build就可以了~ 跟后端无关的调试, 可以直接 npm run dev 页面调用Rust方法 前端使用invoke,调用Rust 这样算前后端不分离的,不需要Rust提供接口,Vue去调. 直接就能直接Rust的方法 以浮点型计算为例,如果前端计算,精度相差非常大(JS的问题),一般交给后端做 (这里其实描述有误) Greet.Vue修改为: script setup langtsimport { onMounted } from vue;//const count ref(0)onMounted(() { const a 0.07; const b 100; console.log(a * b);})/scripttemplate/templatestyle scoped/style 把a,b这两个参数传给rust, 然后返回一个计算好的方法. 相关文档: https://tauri.app/v1/guides/features/command 可用的Greet.Vue: script setup langtsimport { onMounted } from vue;// When using the Tauri API npm package:import { invoke } from tauri-apps/api/tauri;defineProps{ meg: string }();//const count ref(0)onMounted(() { // console.log(a * b);})const myCustomCommand () { const a 0.07; const b 100; // Invoke the command invoke(my_custom_command, { a, b }).then((message) console.log(message)); // .then((message 接收结果};/scripttemplate button clickmyCustomCommand点此按钮触发Rust方法/button/templatestyle scoped/style main.rs: // Prevents additional console window on Windows in release, DO NOT REMOVE!!#![cfg_attr(not(debug_assertions), windows_subsystem windows)]// Learn more about Tauri commands at https://tauri.app/v1/guides/features/command// #[tauri::command]// fn greet(name: str) - String {// format!(Hello, {}! Youve been greeted from Rust!, name)// }#[tauri::command]fn my_custom_command(a: f32, b: f32) -f32 { println!(开始计算); let c a*b; println!(值为:{},c); c}fn main() { tauri::Builder::default() .invoke_handler(tauri::generate_handler![my_custom_command]) .run(tauri::generate_context!()) .expect(error while running tauri application);} 可能会有同步和异步的情况,所以为了更易读,可以这样改写前端代码: const myCustomCommand async () { const a 0.07; const b 100; // Invoke the command let c await invoke(my_custom_command, { a, b }); console.log(c);}; 效果一致 事件系统 https://tauri.app/v1/guides/features/events 可以把事件 理解成一个通道,可以前端给后端发消息,也可以后端给前端发消息. invoke只能前端主动调用后端,类似http. 事件系统类似websocket,后端也可以主动给前端发消息,双向的 没这个特性的话,有的场景下就只能前端不停轮询,不够优雅 https://tauri.app/v1/api/js/event 可用的代码: Greet.vue: script setup langtsimport { onMounted } from vue;// When using the Tauri API npm package:import { invoke } from tauri-apps/api/tauri;import { listen } from tauri-apps/api/eventdefineProps{ meg: string }();//const count ref(0)onMounted(() { // console.log(a * b);})const myCustomCommand async () { const a 0.07; const b 100; // Invoke the command let c await invoke(my_custom_command, { a, b }); console.log(c);};const initProcess async () { await invoke(init_process); // 注意方式,下划线 await listenstring(event-name, (event) { console.log(event); });};/scripttemplate button clickmyCustomCommand点此按钮触发Rust方法/button button clickinitProcess启动事件,后端主动请求前端/button/templatestyle scoped/style main.rs: // Prevents additional console window on Windows in release, DO NOT REMOVE!!#![cfg_attr(not(debug_assertions), windows_subsystem windows)]// Learn more about Tauri commands at https://tauri.app/v1/guides/features/command// #[tauri::command]// fn greet(name: str) - String {// format!(Hello, {}! Youve been greeted from Rust!, name)// }#[tauri::command]fn my_custom_command(a: f32, b: f32) -f32 { println!(开始计算); let c a*b; println!(值为:{},c); c}use tauri::{Manager, Window};// the payload type must implement Serialize and Clone.#[derive(Clone, serde::Serialize)]struct Payload { message: String,}// init a background process on the command, and emit periodic events only to the window that used the command#[tauri::command]fn init_process(window: Window) { println!(到了事件处理方法里面); std::thread::spawn(move || { loop { window.emit(event-name, Payload { message: Tauri is awesome!.into() }).unwrap(); } });}fn main() { tauri::Builder::default() .invoke_handler(tauri::generate_handler![my_custom_command, init_process]) // 要记得把init_process加进来,不然会报错 Unhandled Promise Rejection: command init_process not found .run(tauri::generate_context!()) .expect(error while running tauri application);} 会不停请求,加一个sleep 500毫秒 在rust代码中修改init_process: use std::{thread,time};// init a background process on the command, and emit periodic events only to the window that used the command#[tauri::command]fn init_process(window: Window) { println!(到了事件处理方法里面); std::thread::spawn(move || loop { window.emit(event-name, Payload { message: Tauri is awesome!.into() }).unwrap(); thread::sleep(time::Duration::from_millis(500)); } );} http接口请求 如果只是单机软件,压根不需要该功能~ https://tauri.app/v1/api/js/http 实测好用的四个有免费API接口的网站[4] 这个还可以 https://api.qqsuu.cn/ 找一个免费公开的天气接口[5]作为试验 申请apikey 天气接口要花钱,换一个,用 网站TDK描述查询 查询网站标题关键词描述等等 例如 https://api.qqsuu.cn/api/dm-info?urlhttps://dashen.techapiKeyxxxxxxxx { code: 200, msg: 查询成功, url: dashen.tech, title: 清澄秋爽|苹果树下的思索者书写是对思维的缓存, description: 崔某人的碎碎念,通才基础上的专才, keywords: mysql,golang,算法} 修改tauri.conf.json 文件allowlist为: allowlist: { all: true, http: { scope: [https://api.qqsuu.cn/*] }, shell: { all: false, open: true } }, 否则会报错 这样就可以调用 https://api.qqsuu.cn/*下面所有的接口了~ 参考文档上的这段: import { fetch } from tauri-apps/api/http;const response await fetch(http://localhost:3003/users/2, { method: GET, timeout: 30,}); Greet.vue相应修改为: script setup langtsimport { onMounted } from vue;// When using the Tauri API npm package:import { invoke } from tauri-apps/api/tauri;import { listen } from tauri-apps/api/eventimport { fetch } from tauri-apps/api/http;defineProps{ meg: string }();//const count ref(0)onMounted(() { // console.log(a * b);})const myCustomCommand async () { const a 0.07; const b 100; // Invoke the command let c await invoke(my_custom_command, { a, b }); console.log(c);};const initProcess async () { await invoke(init_process); // 注意方式,下划线 await listenstring(event-name, (event) { console.log(event); });};const response async () { let data await fetch(https://api.qqsuu.cn/api/dm-info?urlhttps://dashen.techapiKeyxxxxxxx, { method: GET, timeout: 30,});console.log(data);}/scripttemplate button clickmyCustomCommand点此按钮触发Rust方法/button button clickinitProcess启动事件,后端主动请求前端/button button clickresponse获取网站信息/button/templatestyle scoped/style 文件系统 将本地文件转为url 对文件的读写删改等 文档: https://tauri.app/v1/api/js/fs tauri.conf.json默认开启文件系统相关的权限,无需修改了 但需要在allowlist新增: fs: { scope: [$APPDATA/databases/*] } 其中 $APPCONFIG, $APPDATA, $APPLOCALDATA, $APPCACHE, $APPLOG, $AUDIO, $CACHE, $CONFIG, $DATA, $LOCALDATA, $DESKTOP, $DOCUMENT, $DOWNLOAD, $EXE, $FONT, $HOME, $PICTURE, $PUBLIC, $RUNTIME, $TEMPLATE, $VIDEO, $RESOURCE, $APP, $LOG, $TEMP. 这些变量,都指的是哪个路径,详见文档 在Tauri中一些特殊的变量具有特殊的含义代表了系统的某些目录或者文件夹。具体来说 $APPCONFIG: 应用程序的配置文件。 $APPDATA: 应用程序的数据文件。 $APPLOCALDATA: 应用程序的本地数据文件。 $APPCACHE: 应用程序的缓存文件。 $APPLOG: 应用程序的日志文件。 $AUDIO: 系统音频文件。 $CACHE: 系统缓存文件。 $CONFIG: 系统配置文件。 $DATA: 系统数据文件。 $LOCALDATA: 系统本地数据文件。 $DESKTOP: 系统桌面文件。 $DOCUMENT: 用户文档文件。 $DOWNLOAD: 下载文件夹。 $EXE: 可执行文件。 $FONT: 系统字体文件。 $HOME: 用户主目录。 $PICTURE: 图片文件夹。 $PUBLIC: 公共文件夹。 $RUNTIME: 运行时文件夹。 $TEMPLATE: 模板文件夹。 $VIDEO: 视频文件。 $RESOURCE: 资源文件夹。 $APP: 应用程序文件夹。 $LOG: 日志文件夹。 $TEMP: 临时文件夹。 (前端提供的api, 不能使用绝对路径.如果需要使用Rust) 下面是一个用前端接口读取文件的示例: 此处修改为 fs: { scope: [$RESOURCE/*] }, 在src-tauri目录下新建一个img文件夹,拷贝几张图片过去 Unhandled Promise Rejection: path: /Users/fliter/tauri-app/src-tauri/target/debug/avatar.png: No such file or directory (os error 2) 如果这个目录下有一张叫avatar.png的图片,那可以以字节数组的形式读取出来. 这种方式还是比较麻烦,还支持 将本地文件转为url https://tauri.app/v1/api/js/tauri 将tauri.conf.json文件中的security改为 csp: default-src self; img-src self asset: https://asset.localhost 同时需要在allowlist下新增 protocol: { asset: true, assetScope: [$RESOURCE/*] }, Greet.vue: script setup langtsimport { ref, onMounted } from vue;// When using the Tauri API npm package:import { invoke } from tauri-apps/api/tauri;import { listen } from tauri-apps/api/eventimport { fetch } from tauri-apps/api/http;import { readBinaryFile, BaseDirectory } from tauri-apps/api/fs;import { appDataDir, desktopDir,join } from tauri-apps/api/path;import { convertFileSrc } from tauri-apps/api/tauri;defineProps{ meg: string }();const imgSrc ref();//const count ref(0)onMounted(() { // console.log(a * b);})const myCustomCommand async () { const a 0.07; const b 100; // Invoke the command let c await invoke(my_custom_command, { a, b }); console.log(c);};const initProcess async () { await invoke(init_process); // 注意方式,下划线 await listenstring(event-name, (event) { console.log(event); });};const response async () { let data await fetch(https://api.qqsuu.cn/api/dm-info?urlhttps://dashen.techapiKeyxxxxxxx, { method: GET, timeout: 30,});console.log(data);}const readImg async () {// Read the image file in the $RESOURCEDIR/avatar.png pathconst contents await readBinaryFile(avatar.png, { dir: BaseDirectory.Resource }); console.log(contents);}const readImgTwo async () {//const appDataDirPath await appDataDir();const desktopDirPath await desktopDir(); // 需要在上面的import中导入//console.log(appDataDirPath)console.log(desktopDirPath);const filePath await join(desktopDirPath, c.png);const assetUrl convertFileSrc(filePath);imgSrc.value assetUrl;}/scripttemplate button clickmyCustomCommand点此按钮触发Rust方法/button button clickinitProcess启动事件,后端主动请求前端/button button clickresponse获取网站信息/button button clickreadImg读取图片/button button clickreadImgTwo读取图片2/button img :srcimgSrc alt/templatestyle scoped/style 这是因为allowlist里面写的是$RESOURCE/,但代码里用的是desktopDir,所以需要将assetScope设置为$DESKTOP/* (或增加$DESKTOP/*),即 assetScope: [$RESOURCE/*,$DESKTOP/*] dialog对话框 https://tauri.app/v1/api/js/dialog 需要启用部分api 但因为allowlist写了all: true,,所以~ 以这个example为例 import { ask } from tauri-apps/api/dialog;const yes await ask(Are you sure?, Tauri);const yes2 await ask(This action cannot be reverted. Are you sure?, { title: Tauri, type: warning }); Greet.vue: script setup langtsimport { ref, onMounted } from vue;// When using the Tauri API npm package:import { invoke } from tauri-apps/api/tauri;import { listen } from tauri-apps/api/eventimport { fetch } from tauri-apps/api/http;import { readBinaryFile, BaseDirectory } from tauri-apps/api/fs;import { desktopDir, join } from tauri-apps/api/path;import { convertFileSrc } from tauri-apps/api/tauri;import { ask } from tauri-apps/api/dialog;defineProps{ meg: string }();const imgSrc ref();//const count ref(0)onMounted(() { // console.log(a * b);})const myCustomCommand async () { const a 0.07; const b 100; // Invoke the command let c await invoke(my_custom_command, { a, b }); console.log(c);};const initProcess async () { await invoke(init_process); // 注意方式,下划线 await listenstring(event-name, (event) { console.log(event); });};const response async () { let data await fetch(https://api.qqsuu.cn/api/dm-info?urlhttps://dashen.techapiKeyxxxxxxxx, { method: GET, timeout: 30, }); console.log(data);}const readImg async () { // Read the image file in the $RESOURCEDIR/avatar.png path const contents await readBinaryFile(avatar.png, { dir: BaseDirectory.Resource }); console.log(contents);}const readImgTwo async () { //const appDataDirPath await appDataDir(); const desktopDirPath await desktopDir(); // 需要在上面的import中导入 //console.log(appDataDirPath) console.log(desktopDirPath); const filePath await join(desktopDirPath, c.png); const assetUrl convertFileSrc(filePath); imgSrc.value assetUrl;}const dialogOne async () { const yes await ask(Are you sure?, Tauri); console.log(yes);}const dialogTwo async () { const yes2 await ask(This action cannot be reverted. Are you sure?, { title: Tauri, type: warning }); console.log(yes2);}/scripttemplate button clickmyCustomCommand点此按钮触发Rust方法/button button clickinitProcess启动事件,后端主动请求前端/button button clickresponse获取网站信息/button button clickreadImg读取图片/button button clickreadImgTwo读取图片2/button button clickdialogOne弹框1/button button clickdialogTwo弹框2/button img :srcimgSrc alt/templatestyle scoped/style 再以选择文件夹为例: import { open } from tauri-apps/api/dialog;import { appDir } from tauri-apps/api/path;// Open a selection dialog for directoriesconst selected await open({ directory: true, multiple: true, defaultPath: await appDir(),});if (Array.isArray(selected)) { // user selected multiple directories} else if (selected null) { // user cancelled the selection} else { // user selected a single directory} Greet.vue: script setup langtsimport { ref, onMounted } from vue;// When using the Tauri API npm package:import { invoke } from tauri-apps/api/tauri;import { listen } from tauri-apps/api/eventimport { fetch } from tauri-apps/api/http;import { readBinaryFile, BaseDirectory } from tauri-apps/api/fs;import { desktopDir, join } from tauri-apps/api/path;import { convertFileSrc } from tauri-apps/api/tauri;import { ask } from tauri-apps/api/dialog;import { open } from tauri-apps/api/dialog;import { appDir } from tauri-apps/api/path;defineProps{ meg: string }();const imgSrc ref();//const count ref(0)onMounted(() { // console.log(a * b);})const myCustomCommand async () { const a 0.07; const b 100; // Invoke the command let c await invoke(my_custom_command, { a, b }); console.log(c);};const initProcess async () { await invoke(init_process); // 注意方式,下划线 await listenstring(event-name, (event) { console.log(event); });};const response async () { let data await fetch(https://api.qqsuu.cn/api/dm-info?urlhttps://dashen.techapiKeyxxxxxxx, { method: GET, timeout: 30, }); console.log(data);}const readImg async () { // Read the image file in the $RESOURCEDIR/avatar.png path const contents await readBinaryFile(avatar.png, { dir: BaseDirectory.Resource }); console.log(contents);}const readImgTwo async () { //const appDataDirPath await appDataDir(); const desktopDirPath await desktopDir(); // 需要在上面的import中导入 //console.log(appDataDirPath) console.log(desktopDirPath); const filePath await join(desktopDirPath, c.png); const assetUrl convertFileSrc(filePath); imgSrc.value assetUrl;}const dialogOne async () { const yes await ask(Are you sure?, Tauri); console.log(yes);}const dialogTwo async () { const yes2 await ask(This action cannot be reverted. Are you sure?, { title: Tauri, type: warning }); console.log(yes2);}const selectDir async () { // Open a selection dialog for directoriesconst selected await open({ directory: true, multiple: true, defaultPath: await appDir(),});if (Array.isArray(selected)) { // user selected multiple directories} else if (selected null) { // user cancelled the selection} else { // user selected a single directory}console.log(selected);}/scripttemplate button clickmyCustomCommand点此按钮触发Rust方法/button button clickinitProcess启动事件,后端主动请求前端/button button clickresponse获取网站信息/button button clickreadImg读取图片/button button clickreadImgTwo读取图片2/button button clickdialogOne弹框1/button button clickdialogTwo弹框2/button button clickselectDir选择文件/button img :srcimgSrc alt/templatestyle scoped/style 自定义窗口及配置 https://tauri.app/v1/guides/features/window-customization 复制css代码到style标签之间 .titlebar { height: 30px; background: #329ea3; user-select: none; display: flex; justify-content: flex-end; position: fixed; top: 0; left: 0; right: 0;}.titlebar-button { display: inline-flex; justify-content: center; align-items: center; width: 30px; height: 30px;}.titlebar-button:hover { background: #5bbec3;} 复制html代码到 标签之间 div data-tauri-drag-region classtitlebar div classtitlebar-button idtitlebar-minimize img srchttps://api.iconify.design/mdi:window-minimize.svg altminimize / /div div classtitlebar-button idtitlebar-maximize img srchttps://api.iconify.design/mdi:window-maximize.svg altmaximize / /div div classtitlebar-button idtitlebar-close img srchttps://api.iconify.design/mdi:close.svg altclose / /div/div js段引入 import { appWindow } from tauri-apps/api/window 修改html部分的代码,增加一个 clickminimize(),使其能够对得上 Greet.vue 完整代码: script setup langtsimport { ref, onMounted } from vue;// When using the Tauri API npm package:import { invoke } from tauri-apps/api/tauri;import { listen } from tauri-apps/api/eventimport { fetch } from tauri-apps/api/http;import { readBinaryFile, BaseDirectory } from tauri-apps/api/fs;import { desktopDir, join } from tauri-apps/api/path;import { convertFileSrc } from tauri-apps/api/tauri;import { ask } from tauri-apps/api/dialog;import { open } from tauri-apps/api/dialog;import { appDir } from tauri-apps/api/path;import { appWindow } from tauri-apps/api/windowdefineProps{ meg: string }();const imgSrc ref();//const count ref(0)onMounted(() { // console.log(a * b);})const myCustomCommand async () { const a 0.07; const b 100; // Invoke the command let c await invoke(my_custom_command, { a, b }); console.log(c);};const initProcess async () { await invoke(init_process); // 注意方式,下划线 await listenstring(event-name, (event) { console.log(event); });};const response async () { let data await fetch(https://api.qqsuu.cn/api/dm-info?urlhttps://dashen.techapiKeyxxxxxxx, { method: GET, timeout: 30, }); console.log(data);}const readImg async () { // Read the image file in the $RESOURCEDIR/avatar.png path const contents await readBinaryFile(avatar.png, { dir: BaseDirectory.Resource }); console.log(contents);}const readImgTwo async () { //const appDataDirPath await appDataDir(); const desktopDirPath await desktopDir(); // 需要在上面的import中导入 //console.log(appDataDirPath) console.log(desktopDirPath); const filePath await join(desktopDirPath, c.png); const assetUrl convertFileSrc(filePath); imgSrc.value assetUrl;}const dialogOne async () { const yes await ask(Are you sure?, Tauri); console.log(yes);}const dialogTwo async () { const yes2 await ask(This action cannot be reverted. Are you sure?, { title: Tauri, type: warning }); console.log(yes2);}const selectDir async () { // Open a selection dialog for directories const selected await open({ directory: true, multiple: true, defaultPath: await appDir(), }); if (Array.isArray(selected)) { // user selected multiple directories } else if (selected null) { // user cancelled the selection } else { // user selected a single directory } console.log(selected);}const minimize () { appWindow.minimize();};const maximize () { appWindow.toggleMaximize();};const close () { appWindow.close();};/scripttemplate div data-tauri-drag-region classtitlebar div clickminimize() classtitlebar-button idtitlebar-minimize img srchttps://api.iconify.design/mdi:window-minimize.svg altminimize / /div div clickmaximize() classtitlebar-button idtitlebar-maximize img srchttps://api.iconify.design/mdi:window-maximize.svg altmaximize / /div div clickclose() classtitlebar-button idtitlebar-close img srchttps://api.iconify.design/mdi:close.svg altclose / /div /div button clickmyCustomCommand点此按钮触发Rust方法/button button clickinitProcess启动事件,后端主动请求前端/button button clickresponse获取网站信息/button button clickreadImg读取图片/button button clickreadImgTwo读取图片2/button button clickdialogOne弹框1/button button clickdialogTwo弹框2/button button clickselectDir选择文件/button img :srcimgSrc alt/templatestyle scoped.titlebar { height: 30px; background: #329ea3; user-select: none; display: flex; justify-content: flex-end; position: fixed; top: 0; left: 0; right: 0;}.titlebar-button { display: inline-flex; justify-content: center; align-items: center; width: 30px; height: 30px;}.titlebar-button:hover { background: #5bbec3;}/style 尝试去掉左侧的按钮. 需要修改窗口的配置 https://tauri.app/v1/api/config#windowconfig 搜索 decorations, Whether the window should have borders and bars., 默认是true 在tauri.conf.json的windows部分新增 decorations:false windows: [ { fullscreen: false, resizable: true, title: tauri-app, width: 800, height: 600, decorations:false } 这样左上方的按钮就没有了 一些其他配置: X,Y为距离左上方(0,0)坐标的偏移值 系统托盘 https://tauri.app/v1/guides/features/system-tray 把 systemTray: { iconPath: icons/icon.png, iconAsTemplate: true } 复制到tauri.conf.json最后 Mac上和Windows上应该有较大差异,先略过 开屏界面 像Jetbrains全家桶,PS等软件,打开时都有个开屏界面 (我猜很大原因是软件较大,启动耗时较长,加个开屏界面可以看上去消减用户的等待时间) https://tauri.app/v1/guides/features/splashscreen 要先把主界面隐藏,然后添加一个(开屏)界面的配置 windows: [ { title: Tauri App, width: 800, height: 600, resizable: true, fullscreen: false, visible: false // Hide the main window by default }, // Add the splashscreen window { width: 400, height: 200, decorations: false, url: splashscreen.html, label: splashscreen }] 即 windows: [ { fullscreen: false, resizable: true, title: tauri-app, width: 800, height: 600, decorations: false, visible: false // 隐藏主界面 }, { width: 400, height: 200, decorations: false, url: splashscreen.html, label: splashscreen } ] label 为界面标识,url 为界面路径(一个html文件,可以用vue去写). 目前读取的目录是在distDir: ../dist,可以在public目录下创建这个html文件,因为打包时会包含进去 在public下新建splashscreen.html文件: !DOCTYPE htmlhtml langenhead meta charsetUTF-8 meta http-equivX-UA-Compatible contentIE-edge meta nameviewport contentwidthdevice-width, initial-scale1.0 titleDocument/title/headbody div开屏界面/div/body/html 需要用到Rust了(其实使用前端API也能做到) 等Rust代码执行完后,关闭开屏界面,打开主界面 在main.rs中新增: // Create the command:// This command must be async so that it doesnt run on the main thread.#[tauri::command]async fn close_splashscreen(window: Window) { // Close splashscreen window.get_window(splashscreen).expect(no window labeled splashscreen found).close().unwrap(); // Show main window window.get_window(main).expect(no window labeled main found).show().unwrap();} 同时将close_splashscreen加入到tauri::Builder::default()的数组中, 完整rust代码: // Prevents additional console window on Windows in release, DO NOT REMOVE!!#![cfg_attr(not(debug_assertions), windows_subsystem windows)]// Learn more about Tauri commands at https://tauri.app/v1/guides/features/command// #[tauri::command]// fn greet(name: str) - String {// format!(Hello, {}! Youve been greeted from Rust!, name)// }use std::{thread,time};#[tauri::command]fn my_custom_command(a: f32, b: f32) -f32 { println!(开始计算); let c a*b; println!(值为:{},c); c}use tauri::{Manager, Window};// the payload type must implement Serialize and Clone.#[derive(Clone, serde::Serialize)]struct Payload { message: String,}// init a background process on the command, and emit periodic events only to the window that used the command#[tauri::command]fn init_process(window: Window) { println!(到了事件处理方法里面); std::thread::spawn(move || loop { window.emit(event-name, Payload { message: Tauri is awesome!.into() }).unwrap(); thread::sleep(time::Duration::from_millis(500)); } );}// Create the command:// This command must be async so that it doesnt run on the main thread.#[tauri::command]async fn close_splashscreen(window: Window) { // Close splashscreen window.get_window(splashscreen).expect(no window labeled splashscreen found).close().unwrap(); // Show main window window.get_window(main).expect(no window labeled main found).show().unwrap();}fn main() { tauri::Builder::default() .invoke_handler(tauri::generate_handler![my_custom_command, init_process,close_splashscreen]) // 要记得把init_process加进来,不然会报错 Unhandled Promise Rejection: command init_process not found .run(tauri::generate_context!()) .expect(error while running tauri application);} 再之后需要前端去调用这个Rust方法 为了能看到效果,需要加一个定时器 Greet.vue中: onMounted(() { // console.log(a * b); setTimeout(() { invoke(close_splashscreen) }, 3000)}) 执行 npm run tauri dev, 而后会进入到主界面 多窗口 https://tauri.app/v1/guides/features/multiwindow 静态窗口: 打开软件时直接弹出两个窗口(这种很少见) 动态窗口 还是写一个按钮事件来触发 const newWindow () {const webview new WebviewWindow(theUniqueLabel, { url: test.html,})// since the webview window is created asynchronously,// Tauri emits the tauri://created and tauri://error to notify you of the creation responsewebview.once(tauri://created, function () { // webview window successfully created 窗口创建成功时触发的逻辑 console.log(创建成功)})webview.once(tauri://error, function (e) { // an error occurred during webview window creation 窗口创建失败时触发的逻辑 console.log(创建失败,e)})}// ... button clicknewWindow新建窗口/button 另外在public下新建一个test.html: !DOCTYPE htmlhtml langenhead meta charsetUTF-8 meta http-equivX-UA-Compatible contentIE-edge meta nameviewport contentwidthdevice-width, initial-scale1.0 titleDocument/title/headbody div新建窗口/div/body/html 现在想要实现打开新窗口时,隐藏原来的主界面. 实现办法是点击按钮触发创建新窗口操作时,先把主界面隐藏掉,等新窗口创建成功,再把主界面关掉 (如果在新窗口没有创建出来前就直接close,直接退出程序了) 可以通过label指定具体的页面 还可以通过在json文件中,配置相应的参数 如: { width: 200, height: 100, decorations: false, url: test.html, label: test, visible: false } WiX打包 Windows系统打包: https://tauri.app/v1/guides/building/windows 是否支持win7需要特殊配置 Mac系统打包: https://tauri.app/v1/guides/building/macos 我主要试一下Mac下的打包 npm run tauri build 或 cargo tauri build npm run tauri build tauri-app0.0.0 tauri tauri build Error You must change the bundle identifier in tauri.conf.json tauri bundle identifier. The default value com.tauri.dev is not allowed as it must be unique across applications. 根据 [Tauri的安装、启动、打包和很多用例(第一部分)](https://blog.csdn.net/qq_39124701/article/details/129015210 Tauri的安装、启动、打包和很多用例(第一部分 Tauri的安装、启动、打包和很多用例(第一部分))), com.tauri.dev 随便改个名字,不叫dev就行. 这里就改成 com.tauri.shuang 再次执行,还是报了一个错: error TS2345: Argument of type {} is not assignable to parameter of type Partial{} Omit{ readonly meg: string; } VNodeProps AllowedComponentProps ComponentCustomProps Readonly..., never Record.... Property meg is missing in type {} but required in type Omit{ readonly meg: string; } VNodeProps AllowedComponentProps ComponentCustomProps ReadonlyExtractPropTypes__VLS_TypePropsToRuntimeProps{ meg: string; }, never.40 Greet/ ~~~~~Found 1 error in src/App.vue:40 Error beforeBuildCommand npm run build failed with exit code 2 问了下ChatGPT 什么问题如何解决 这个错误是 TypeScript 编译器的错误。它指出在文件 src/App.vue 的第 40 行你传递给组件 Greet/ 的属性不符合类型要求。 根据错误信息组件 Greet/ 需要一个名为 meg 的属性类型为字符串。然而你传递给组件的属性是一个空对象 {}没有包含必需的 meg 属性。 要解决这个问题你需要确保在使用组件 Greet/ 时传递一个包含 meg 属性的对象。例如 Greet megHello/或者如果 meg 属性是可选的你可以将其设置为可选属性 interface GreetProps { meg?: string;}// ...Greet megHello/ 通过这样做你应该能够解决这个 TypeScript 编译器错误并成功构建你的应用程序。 然后就可以了~ 跨平台构建: 可以针对 Apple Silicon、基于 Intel 的 Mac 计算机或通用 macOS 二进制文件编译应用程序。默认情况下CLI 会构建一个针对你计算机架构的二进制文件。如果想针对不同的目标进行构建则必须首先通过运行 rustup target add aarch64-apple-darwin 或 rustup target add x86_64-apple-darwin 来安装该目标缺少的 rust 目标然后您可以使用 --target tauri build --target aarch64-apple-darwin 针对 Apple 硅机器。 tauri build --target x86_64-apple-darwin 针对基于 Intel 的机器。 tauri build --target universal-apple-darwin 生成可在 Apple 芯片和基于 Intel 的 Mac 上运行的通用 macOS 二进制文件。 NSIS打包 Tauri 1.4版本新增了这种打包方式 软件更新 https://tauri.app/v1/guides/distribution/updater 将这段代码增加到json文件中 updater: { active: true, endpoints: [ https://releases.myapp.com/{{target}}/{{arch}}/{{current_version}} ], dialog: true, pubkey: YOUR_UPDATER_SIGNATURE_PUBKEY_HERE } 主要需要设置服务器地址和公钥 服务器接口返回一个json,大概是版本,更新内容等,需要额外开发. 生成公钥: npm run tauri signer generate -- -w $HOME/.tauri/myapp.key 把得到的公钥复制到json文件pubkey后面 另外可能还需要给TAURI_PRIVATE_KEY加入环境变量 Rust相关的代码,空间占用非常之大.. 完整代码: tauri-app[6] 参考资料 [1] Tauri入门教程: https://www.bilibili.com/video/BV1Za411N7dN/ [2] Tauri官网: https://tauri.app/ [3] 可参考: https://stackoverflow.com/questions/75013520/when-i-install-and-run-tauri-on-mac-os-monterey-i-get-immediate-error [4] 实测好用的四个有免费API接口的网站: https://blog.csdn.net/m0_73875883/article/details/130840251 [5] 天气接口: https://api.qqsuu.cn/doc/dm-hqtiqnqi.html [6] tauri-app: https://github.com/cuishuang/tauri-app 本文由 mdnice 多平台发布