基于tauri+vue3.js+vite3跨桌面端仿微信聊天实例TauriVue3Chat

tauri-chat 运用最新tauri+vue3+vite3+element-plus+v3layer等技术跨桌面端仿微信|QQ聊天程序EXE。基本实现了发送图文混排消息、图片/视频/网址预览、拖拽聊天区发送图片、朋友圈等功能。支持tauri打开多个窗体、更换主题皮肤等功能。

一、技术框架

  • 编辑器:VScode
  • 使用技术:tauri+vue^3.2.37+vite^3.0.2+vuex4+vue-router@4
  • UI组件库:element-plus^2.2.17 (饿了么vue3组件库)
  • 弹窗组件:v3layer(基于vue3自定义pc端弹窗组件)
  • 滚动条组件:v3scroll(基于vue3模拟滚动条组件)
  • 矢量图标:阿里iconfont字体图标库

二、项目结构

◆ Tauri新建多开窗口

项目中主题换肤、朋友圈、关于、视频预览等窗口均是新开窗口。

  1. // 关于
  2. const openAboutWin = () => {
  3. createWin({
  4. label: 'about',
  5. title: '关于',
  6. url: '/about',
  7. width: 430,
  8. height: 330,
  9. resizable: false,
  10. alwaysOnTop: true,
  11. })
  12. }
  13.  
  14. // 主题换肤
  15. const openThemeSkinWin = () => {
  16. createWin({
  17. label: 'skin',
  18. title: '换肤',
  19. url: '/skin',
  20. width: 630,
  21. height: 400,
  22. resizable: false,
  23. })
  24. }
  25.  
  26. // 朋友圈
  27. const openQzoneWin = () => {
  28. createWin({
  29. label: 'fzone',
  30. title: '朋友圈',
  31. url: '/fzone',
  32. width: 550,
  33. height: 700,
  34. resizable: false,
  35. })
  36. }

tauri多窗口参数配置

  1. // 窗口配置
  2. export const windowConfig = {
  3. label: null, // 窗口唯一label
  4. title: '', // 窗口标题
  5. url: '', // 路由地址url
  6. width: 900, // 窗口宽度
  7. height: 640, // 窗口高度
  8. minWidth: null, // 窗口最小宽度
  9. minHeight: null, // 窗口最小高度
  10. x: null, // 窗口相对于屏幕左侧坐标
  11. y: null, // 窗口相对于屏幕顶端坐标
  12. center: true, // 窗口居中显示
  13. resizable: true, // 是否支持缩放
  14. maximized: false, // 最大化窗口
  15. decorations: false, // 窗口是否无边框及导航条
  16. alwaysOnTop: false, // 置顶窗口
  17. fileDropEnabled: false, // 禁止系统拖放
  18. visible: false, // 隐藏窗口
  19. }

由于之前有写过一篇vue3+tauri创建多窗口的分享文章,这里就不详细介绍了。

https://www.cnblogs.com/xiaoyan2017/p/16812092.html

◆ Tauri自定义拖拽窗体|最大化/最小化/关闭功能

创建窗口的时候配置 decorations: false 参数,则创建的窗口没有顶部导航栏及边框。拖拽区域/最大化/最小化及关闭按钮都需要自定义功能。

tauri提供了 data-tauri-drag-region 属性,在需要拖拽的元素上设置该属性,该区域就能自由拖拽了。

  1. <template>
  2. <div class="nt__navbar">
  3. <div data-tauri-drag-region class="nt__navbar-wrap">
  4. <div class="nt__navbar-title">
  5. <template v-if="$slots.title"><slot name="title" /></template>
  6. <template v-else>{{title}}</template>
  7. </div>
  8. </div>
  9. <WinTool :minimizable="minimizable" :maximizable="maximizable" :closable="closable">
  10. <slot name="wbtn" />
  11. </WinTool>
  12. </div>
  13. </template>

下面这篇文章介绍tauri自定义最大化/最小化及关闭按钮功能。

https://www.cnblogs.com/xiaoyan2017/p/16818283.html

◆ Tauri创建系统托盘图标

当关闭窗体的时候,会判断是否主窗口,并给出关闭提示。当不是主窗口,则直接关闭,是主窗口则给出下图弹窗提示。最小化至托盘 则是隐藏窗口,退出程序则直接执行exit方法退出应用了。

  1. // 关闭窗体
  2. const handleCloseWindow = async() => {
  3. if(appWindow.label.indexOf('main') > -1) {
  4. let $el = v3layer({
  5. type: 'android',
  6. content: '确认退出应用程序吗?',
  7. btns: [
  8. {
  9. text: '最小化托盘',
  10. style: 'color:#24c8db',
  11. click: () => {
  12. $el.close()
  13. await appWindow.hide()
  14. }
  15. },
  16. {
  17. text: '退出程序',
  18. style: 'color:#ff5438',
  19. click: async() => {
  20. $el.close()
  21. store.commit('LOGOUT')
  22. await exit()
  23. }
  24. }
  25. ]
  26. })
  27. }else {
  28. await appWindow.close()
  29. }
  30. }

  1. /**
  2. * 创建系统托盘图标Tray
  3. */
  4.  
  5. use tauri::{
  6. AppHandle, Manager,
  7. CustomMenuItem, SystemTray, SystemTrayEvent, SystemTrayMenu, SystemTrayMenuItem, SystemTraySubmenu
  8. };
  9.  
  10. // 托盘菜单
  11. pub fn menu() -> SystemTray {
  12. let exit = CustomMenuItem::new("exit".to_string(), "退出");
  13. let relaunch = CustomMenuItem::new("relaunch".to_string(), "重启应用");
  14. let show = CustomMenuItem::new("show".to_string(), "显示窗口");
  15. let hide = CustomMenuItem::new("hide".to_string(), "隐藏窗口");
  16. let change_ico = CustomMenuItem::new("change_ico".to_string(), "更换托盘图标");
  17. let tray_menu = SystemTrayMenu::new()
  18. .add_submenu(SystemTraySubmenu::new(
  19. "国际化", // 语言菜单
  20. SystemTrayMenu::new()
  21. .add_item(CustomMenuItem::new("lang_english".to_string(), "English"))
  22. .add_item(CustomMenuItem::new("lang_zh_CN".to_string(), "简体中文"))
  23. .add_item(CustomMenuItem::new("lang_zh_HK".to_string(), "繁体中文")),
  24. ))
  25. .add_native_item(SystemTrayMenuItem::Separator) // 分割线
  26. .add_item(change_ico)
  27. .add_native_item(SystemTrayMenuItem::Separator)
  28. .add_item(hide)
  29. .add_item(show)
  30. .add_native_item(SystemTrayMenuItem::Separator)
  31. .add_item(relaunch)
  32. .add_item(exit);
  33.  
  34. SystemTray::new().with_menu(tray_menu)
  35. }
  36.  
  37. // 托盘事件
  38. pub fn handler(app: &AppHandle, event: SystemTrayEvent) {
  39. match event {
  40. SystemTrayEvent::LeftClick {
  41. position: _,
  42. size: _,
  43. ..
  44. } => {
  45. println!("点击左键");
  46. }
  47. SystemTrayEvent::RightClick {
  48. position: _,
  49. size: _,
  50. ..
  51. } => {
  52. println!("点击右键");
  53. }
  54. SystemTrayEvent::DoubleClick {
  55. position: _,
  56. size: _,
  57. ..
  58. } => {
  59. println!("双击");
  60. app.emit_all("win-show", {}).unwrap();
  61. }
  62. SystemTrayEvent::MenuItemClick { id, .. } => match id.as_str() {
  63. // 更新托盘图标
  64. "change_ico" => {
  65. app.tray_handle()
  66. .set_icon(tauri::Icon::Raw(
  67. include_bytes!("../icons/tray-empty.ico").to_vec()
  68. ))
  69. .unwrap();
  70. }
  71. // 选择语言,匹配 id 前缀包含 `lang_` 的事件
  72. lang if lang.contains("lang_") => {
  73. Lang::new(
  74. app,
  75. id,
  76. vec![
  77. Lang {
  78. name: "English",
  79. id: "lang_english",
  80. },
  81. Lang {
  82. name: "繁体中文",
  83. id: "lang_zh_HK",
  84. },
  85. Lang {
  86. name: "简体中文",
  87. id: "lang_zh_CN",
  88. },
  89. ],
  90. );
  91. }
  92. "hide" => {
  93. // println!("点击隐藏");
  94. app.emit_all("win-hide", {}).unwrap();
  95. }
  96. "show" => {
  97. // println!("点击显示");
  98. app.emit_all("win-show", {}).unwrap();
  99. }
  100. "relaunch" => {
  101. // println!("点击重启");
  102. app.emit_all("win-relaunch", {}).unwrap();
  103. }
  104. "exit" => {
  105. // println!("点击退出");
  106. app.emit_all("win-exit", {}).unwrap();
  107. }
  108. _ => {}
  109. },
  110. _ => {}
  111. }
  112. }
  113.  
  114. struct Lang<'a> {
  115. name: &'a str,
  116. id: &'a str,
  117. }
  118.  
  119. impl Lang<'static> {
  120. fn new(app: &AppHandle, id: String, langs: Vec<Lang>) {
  121. // 获取点击的菜单项的句柄
  122. langs.iter().for_each(|lang| {
  123. let handle = app.tray_handle().get_item(lang.id);
  124. if lang.id.to_string() == id.as_str() {
  125. // 设置菜单名称
  126. handle.set_title(format!(" {}", lang.name)).unwrap();
  127. handle.set_selected(true).unwrap();
  128. } else {
  129. handle.set_title(lang.name).unwrap();
  130. handle.set_selected(false).unwrap();
  131. }
  132. });
  133. }
  134. }

tauri创建托盘图标默认读取 src-tauri/icons 目录下图标,如果自定义的.ico图标,可在tauri.cong.json文件中配置。

  1. "systemTray": {
  2. "iconPath": "icons/tray.ico",
  3. "iconAsTemplate": true,
  4. "menuOnLeftClick": false
  5. }

使用ico图标报错,需要在 src-tauri/src/Cargo.toml 中配置 icon-ico 或 icon-png

tauri build 打包构建,如果打包的时候报错,需要在 src-tauri/tauri.conf.json 这个配置文件中找到 identifier 这个字段,将它的值进行更改即可。

tauri.conf.json配置文件

  1. {
  2. "build": {
  3. "beforeDevCommand": "npm run dev",
  4. "beforeBuildCommand": "npm run build",
  5. "devPath": "http://localhost:1420",
  6. "distDir": "../dist",
  7. "withGlobalTauri": false
  8. },
  9. "package": {
  10. "productName": "tauri-chat",
  11. "version": "0.0.0"
  12. },
  13. "tauri": {
  14. "allowlist": {
  15. "all": true
  16. },
  17. "bundle": {
  18. "active": true,
  19. "category": "DeveloperTool",
  20. "copyright": "",
  21. "deb": {
  22. "depends": []
  23. },
  24. "externalBin": [],
  25. "icon": [
  26. "icons/32x32.png",
  27. "icons/128x128.png",
  28. "icons/128x128@2x.png",
  29. "icons/icon.icns",
  30. "icons/icon.ico"
  31. ],
  32. "identifier": "com.tauri.chat",
  33. "longDescription": "",
  34. "macOS": {
  35. "entitlements": null,
  36. "exceptionDomain": "",
  37. "frameworks": [],
  38. "providerShortName": null,
  39. "signingIdentity": null
  40. },
  41. "resources": [],
  42. "shortDescription": "",
  43. "targets": "all",
  44. "windows": {
  45. "certificateThumbprint": null,
  46. "digestAlgorithm": "sha256",
  47. "timestampUrl": ""
  48. }
  49. },
  50. "security": {
  51. "csp": null
  52. },
  53. "updater": {
  54. "active": false
  55. },
  56. "windows": [
  57. {
  58. "fullscreen": false,
  59. "height": 640,
  60. "resizable": true,
  61. "title": "TAURI-CHAT",
  62. "width": 900,
  63. "center": true,
  64. "decorations": false,
  65. "fileDropEnabled": false,
  66. "visible": false
  67. }
  68. ],
  69. "systemTray": {
  70. "iconPath": "icons/tray.ico",
  71. "iconAsTemplate": true,
  72. "menuOnLeftClick": false
  73. }
  74. }
  75. }

Oker,基于tauri+vue3实战桌面端聊天应用就分享到这里,希望对大家有些帮助。

最后附上一个uniapp+uview跨端后台管理系统

https://www.cnblogs.com/xiaoyan2017/p/15836112.html

Tauri-Vue3桌面端聊天室|tauri+vite3仿微信|tauri聊天程序EXE的更多相关文章

  1. electron聊天室|vue+electron-vue仿微信客户端|electron桌面聊天

    一.项目概况 基于Electron+vue+electron-vue+vuex+Nodejs+vueVideoPlayer+electron-builder等技术仿制微信电脑端界面聊天室实例,实现消息 ...

  2. vue聊天室|h5+vue仿微信聊天界面|vue仿微信

    一.项目简介 基于Vue2.0+Vuex+vue-router+webpack2.0+es6+vuePhotoPreview+wcPop等技术架构开发的仿微信界面聊天室——vueChatRoom,实现 ...

  3. react聊天室|react+redux仿微信聊天IM实例|react仿微信界面

    一.项目概况 基于react+react-dom+react-router-dom+redux+react-redux+webpack2.0+react-photoswipe+swiper等技术混合开 ...

  4. Svelte3聊天室|svelte+svelteKit仿微信聊天实例|svelte.js开发App

    基于svelte3.x+svelteKit构建仿微信App聊天应用svelte-chatroom. svelte-chatroom 基于svelte.js+svelteKit+mescroll.js+ ...

  5. Taro聊天室|react+taro仿微信聊天App界面|taro聊天实例

    一.项目简述 taro-chatroom是基于Taro多端实例聊天项目,运用Taro+react+react-redux+taroPop+react-native等技术开发的仿微信App界面聊天室,实 ...

  6. uni-app聊天室|vue+uniapp仿微信聊天实例|uniapp仿微信App界面

    一.介绍 运用UniApp+Vue+Vuex+swiper+uniPop等技术开发的仿微信原生App聊天室|仿微信聊天界面实例项目uniapp-chatroom,实现了发送图文消息.表情(gif图), ...

  7. html5聊天案例|趣聊h5|仿微信界面聊天|红包|语音聊天|地图

    之前有开发过一个h5微直播项目,当时里面也用到过聊天模块部分,今天就在之前聊天部分的基础上重新抽离模块,开发了这个h5趣聊项目,功能效果比较类似微信聊天界面.采用html5+css3+Zepto+sw ...

  8. h5移动端聊天室|仿微信界面聊天室|h5多人聊天室

    今年的FIFA世界杯甚是精彩,最近兴致高涨就利用HTML5开发了一个手机端仿微信界面聊天室,该h5聊天室采用750px全新伸缩flex布局,以及使用rem响应式配合fontsize.js,页面弹窗则是 ...

  9. uniapp+nvue实现仿微信App聊天应用 —— 成功实现好友聊天+语音视频通话功能

    基于uniapp + nvue实现的uniapp仿微信App聊天应用 txim 实例项目,实现了以下功能. 1: 聊天会话管理 2: 好友列表 3: 文字.语音.视频.表情.位置等聊天消息收发 4: ...

随机推荐

  1. DS队列----银行单队列多窗口模拟

    题目描述 假设银行有K个窗口提供服务,窗口前设一条黄线,所有顾客按到达时间在黄线后排成一条长龙.当有窗口空闲时,下一位顾客即去该窗口处理事务.当有多个窗口可选择时,假设顾客总是选择编号最小的窗口. 本 ...

  2. JavaSciprt 笔记目录

    JavaScript 基础知识(一):对象以及原型 JavaScript 基础知识(二):闭包 JavaScript 异步编程(一):认识异步编程 JavaScript 异步编程(二):Promise

  3. IPV6属于自己专属公网IP

    有了公网IP就可以搭建网站 简单理解公网IP就是私人的服务器 搭建之前一定要注意!没有网络安全意识的不要随便搭建 如何搭建? 材料如下 支持IPV6的光猫 支持IPV6的路由器 支持IPV6的设备 方 ...

  4. 100 个常见错误「GitHub 热点速览 v.22.35」

    本周的特推非常得延续上周的特点--会玩,向别人家的女朋友发送早安.这个错误是如何发生的呢?如何有效避免呢?自己用 daily_morning 免部署.定制一个早安小助手给女友吧. 除了生活中的错误,工 ...

  5. 【读书笔记】C#高级编程 第二十一章 任务、线程和同步

    (一)概述 所有需要等待的操作,例如,因为文件.数据库或网络访问都需要一定的时间,此时就可以启动一个新的线程,同时完成其他任务. 线程是程序中独立的指令流. (二)Paraller类 Paraller ...

  6. Java---Stream入门

    由于本文需要有一定的Lambda基础,所以如果不懂什么是Lambda的同学请移步:Java---Lambda 学习Stream的目的 函数式编程渐渐变成主流,而Stream是函数式编程的重点. 相对于 ...

  7. vivo 全球商城:电商平台通用取货码设计

    vivo官网商城开发团队 - Zhou Longjian 一.背景 随着O2O线上线下业务的不断扩展,电商平台也在逐步完善交易侧相关的产品功能.在最近的需求版本中,业务方为进一步提升用户的使用体验,规 ...

  8. Java 中HashMap 详解

    本篇重点: 1.HashMap的存储结构 2.HashMap的put和get操作过程 3.HashMap的扩容 4.关于transient关键字 HashMap的存储结构 1. HashMap 总体是 ...

  9. 跨语言调用C#代码的新方式-DllExport

    简介 上一篇文章使用C#编写一个.NET分析器文章发布以后,很多小伙伴都对最新的NativeAOT函数导出比较感兴趣,今天故写一篇短文来介绍一下如何使用它. 在以前,如果有其他语言需要调用C#编写的库 ...

  10. 【学习笔记】循环神经网络(RNN)

    前言 多方寻找视频于博客.学习笔记,依然不能完全熟悉RNN,因此决定还是回到书本(<神经网络与深度学习>第六章),一点点把啃下来,因为这一章对于整个NLP学习十分重要,我想打好基础. 当然 ...