
Flutter3.27实战2025抖音app直播商城
原创自研flutter3.27+dart3.6
实战抖音短视频+聊天+直播电商带货app商城应用程序。
Flutter3.27仿抖音短视频+直播+聊天app商城系统
技术栈
- 编辑器:vscode
- 技术框架:flutter3.27.1+Dart3.6.0
- 路由/状态管理:get: ^4.6.6
- 本地缓存服务:get_storage: ^2.1.1
- 瀑布流组件:flutter_staggered_grid_view^0.7.0
- 轮播图组件:card_swiper^3.0.1
- toast弹窗组件:shirne_dialog^4.8.3
- 视频套件:media_kit: ^1.1.11
实现类似抖音app首页左右滑动切换页面内容,上下滑动切换短视频效果。
项目框架
目前flutter3-douyin-mall短视频直播商城项目已经同步到我的原创作品集。
Flutter3.27仿抖音短视频+直播+聊天app商城系统
flutter3实现首页轮播图+tab滚动吸附
return Scaffold(
backgroundColor: Colors.grey[50],
body: ScrollConfiguration(
behavior: CustomScrollBehavior().copyWith(scrollbars: false),
child: CustomScrollView(
scrollBehavior: CustomScrollBehavior().copyWith(scrollbars: false),
controller: scrollController,
slivers: [
SliverAppBar(
backgroundColor: Colors.transparent,
foregroundColor: Colors.white,
pinned: true,
expandedHeight: 200.0,
titleSpacing: 10.0,
// 搜索框(高斯模糊背景)
title: ClipRRect(
borderRadius: BorderRadius.circular(30.0),
child: BackdropFilter(
filter: ImageFilter.blur(sigmaX: 10.0, sigmaY: 10.0),
child: Container(
...
),
),
),
actions: [
IconButton(icon: Icon(Icons.shopping_cart_outlined), onPressed: () {},),
],
// 自定义伸缩区域(轮播图)
flexibleSpace: Container(
decoration: BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topLeft,
end: Alignment.bottomRight,
colors: [
Color(0xFFFF5000), Color(0xFFfcaec4)
]
)
),
child: FlexibleSpaceBar(
background: Swiper.children(
pagination: SwiperPagination(
builder: DotSwiperPaginationBuilder(
color: Colors.white70,
activeColor: Colors.white,
)
),
indicatorLayout: PageIndicatorLayout.SCALE,
children: [
Image.network('https://m.360buyimg.com/babel/jfs/t20271217/224114/35/38178/150060/6760d559Fd654f946/968c156726b6e822.png',),
Image.network('https://m.360buyimg.com/babel/jfs/t20280117/88832/5/48468/139826/6789cbcfF4e0b2a3d/9dc54355b6f65c40.jpg',),
Image.network('https://m.360buyimg.com/babel/jfs/t20280108/255505/29/10540/137372/677ddbc1F6cdbbed0/bc477fadedef22a8.jpg',),
],
),
),
),
),
...
// tabbar列表
SliverPersistentHeader(
pinned: true,
delegate: CustomStickyHeader(
child: PreferredSize(
preferredSize: Size.fromHeight(45.0),
child: Container(
...
),
),
),
),
// 瀑布流列表
...
],
),
),
// 返回顶部
floatingActionButton: Backtop(controller: scrollController, offset: scrollOffset),
);
flutter3实现短视频功能
@override
Widget build(BuildContext context) {
return Scaffold(
key: scaffoldKey,
extendBodyBehindAppBar: true,
appBar: AppBar(
forceMaterialTransparency: true,
backgroundColor: [0, 1, 4, 5].contains(videoModuleController.videoTabIndex.value) ? null : Colors.transparent,
foregroundColor: [0, 1, 4, 5].contains(videoModuleController.videoTabIndex.value) ? Colors.black : Colors.white,
titleSpacing: 1.0,
leading: Obx(() => IconButton(
icon: Badge.count(
backgroundColor: Colors.red,
count: 6,
child: Icon(Icons.sort_rounded, color: tabColor(),),
),
onPressed: () {
// 自定义打开右侧drawer
scaffoldKey.currentState?.openDrawer();
},
)),
title: Obx(() {
return ScrollConfiguration(
behavior: CustomScrollBehavior().copyWith(scrollbars: false),
child: TabBar(
...
),
);
}),
actions: [
Obx(() => IconButton(icon: Icon(Icons.search_rounded, color: tabColor(),), onPressed: () {},),),
],
),
body: ScrollConfiguration(
behavior: CustomScrollBehavior().copyWith(scrollbars: false),
child: PageView(
controller: pageController,
onPageChanged: (index) {
videoModuleController.updateVideoTabIndex(index);
setState(() {
tabController.animateTo(index, duration: Duration(milliseconds: 200), curve: Curves.easeInOut);
});
},
children: [
...tabModules
],
),
),
// 侧边栏
drawer: Drawer(
shape: RoundedRectangleBorder(borderRadius: BorderRadius.horizontal(right: Radius.circular(15.0))),
clipBehavior: Clip.antiAlias,
width: 300,
child: Container(
...
),
),
);
}
flutter3实现直播功能
// flutter3直播模块 Q:282310962
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.black,
extendBodyBehindAppBar: true,
appBar: AppBar(
forceMaterialTransparency: true,
backgroundColor: Colors.black,
foregroundColor: Colors.white,
toolbarHeight: 0,
),
body: Column(
children: [
Expanded(
child: Stack(
children: [
PageView.builder(
scrollBehavior: CustomScrollBehavior().copyWith(scrollbars: false),
scrollDirection: Axis.vertical,
controller: pageVerticalController,
onPageChanged: (index) async {
setState(() {
liveIndex = index;
});
player.stop();
await player.open(Media(liveJson[index]['src']));
},
itemCount: liveJson.length,
itemBuilder: (context, index) {
return Stack(
children: [
// 视频区域
Positioned(
...
),
/// 水平滚动模块(清屏/浮层)
PageView(
scrollDirection: Axis.horizontal,
controller: pageHorizontalController,
onPageChanged: (index) {
// ...
},
children: [
// 直播清屏
Container(
...
),
// 直播浮层
Stack(
children: [
// 顶部区域
Positioned(
top: MediaQuery.of(context).padding.top + 7,
left: 10.0,
right: 0,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// 直播间头像
Container(
...
),
// 排名统计
Container(
...
),
// 红包活动
Container(
...
),
],
),
),
// 底部区域
Positioned(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// 商品购买动效
Container(
...
),
// 送礼物动效
AnimationLiveGift(
giftQueryList: [
{'label': '小心心', 'gift': 'assets/images/gift/gift1.png', 'user': 'Jack', 'avatar': 'assets/images/avatar/img02.jpg', 'num': 12},
{'label': '棒棒糖', 'gift': 'assets/images/gift/gift2.png', 'user': 'Andy', 'avatar': 'assets/images/avatar/img06.jpg', 'num': 36},
{'label': '大啤酒', 'gift': 'assets/images/gift/gift3.png', 'user': '一条咸鱼', 'avatar': 'assets/images/avatar/img01.jpg', 'num': 162},
...
],
),
// 加入直播间动效
AnimationLiveJoin(
joinQueryList: [
{'avatar': 'assets/images/logo.png', 'name': 'andy'},
{'avatar': 'assets/images/logo.png', 'name': 'jack'},
...
],
),
// 直播弹幕+商品讲解
Container(
margin: EdgeInsets.only(top: 7.0),
height: 200.0,
child: Row(
...
),
),
// 底部工具栏
Container(
margin: const EdgeInsets.only(top: 7.0),
child: Row(
...
),
),
],
),
),
],
),
],
),
],
);
},
),
],
),
),
],
),
);
}
以上就是flutter3.27.1实战抖音app商城的一些知识分享,整个项目涉及到知识点蛮多。希望以上分享对小伙伴们有些帮助哈~~
往期热文
https://segmentfault.com/a/1190000045042968
https://segmentfault.com/a/1190000045245775
https://segmentfault.com/a/1190000045381943
https://segmentfault.com/a/1190000045556523
https://segmentfault.com/a/1190000045667190
作者:xiaoyan2017
链接: https://segmentfault.com/a/1190000046075489
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
原创自研flutter3.27+dart3.6
实战抖音短视频+聊天+直播电商带货app商城应用程序。
Flutter3.27仿抖音短视频+直播+聊天app商城系统
技术栈
- 编辑器:vscode
- 技术框架:flutter3.27.1+Dart3.6.0
- 路由/状态管理:get: ^4.6.6
- 本地缓存服务:get_storage: ^2.1.1
- 瀑布流组件:flutter_staggered_grid_view^0.7.0
- 轮播图组件:card_swiper^3.0.1
- toast弹窗组件:shirne_dialog^4.8.3
- 视频套件:media_kit: ^1.1.11
实现类似抖音app首页左右滑动切换页面内容,上下滑动切换短视频效果。
项目框架
目前flutter3-douyin-mall短视频直播商城项目已经同步到我的原创作品集。
Flutter3.27仿抖音短视频+直播+聊天app商城系统
flutter3实现首页轮播图+tab滚动吸附
return Scaffold(
backgroundColor: Colors.grey[50],
body: ScrollConfiguration(
behavior: CustomScrollBehavior().copyWith(scrollbars: false),
child: CustomScrollView(
scrollBehavior: CustomScrollBehavior().copyWith(scrollbars: false),
controller: scrollController,
slivers: [
SliverAppBar(
backgroundColor: Colors.transparent,
foregroundColor: Colors.white,
pinned: true,
expandedHeight: 200.0,
titleSpacing: 10.0,
// 搜索框(高斯模糊背景)
title: ClipRRect(
borderRadius: BorderRadius.circular(30.0),
child: BackdropFilter(
filter: ImageFilter.blur(sigmaX: 10.0, sigmaY: 10.0),
child: Container(
...
),
),
),
actions: [
IconButton(icon: Icon(Icons.shopping_cart_outlined), onPressed: () {},),
],
// 自定义伸缩区域(轮播图)
flexibleSpace: Container(
decoration: BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topLeft,
end: Alignment.bottomRight,
colors: [
Color(0xFFFF5000), Color(0xFFfcaec4)
]
)
),
child: FlexibleSpaceBar(
background: Swiper.children(
pagination: SwiperPagination(
builder: DotSwiperPaginationBuilder(
color: Colors.white70,
activeColor: Colors.white,
)
),
indicatorLayout: PageIndicatorLayout.SCALE,
children: [
Image.network('https://m.360buyimg.com/babel/jfs/t20271217/224114/35/38178/150060/6760d559Fd654f946/968c156726b6e822.png',),
Image.network('https://m.360buyimg.com/babel/jfs/t20280117/88832/5/48468/139826/6789cbcfF4e0b2a3d/9dc54355b6f65c40.jpg',),
Image.network('https://m.360buyimg.com/babel/jfs/t20280108/255505/29/10540/137372/677ddbc1F6cdbbed0/bc477fadedef22a8.jpg',),
],
),
),
),
),
...
// tabbar列表
SliverPersistentHeader(
pinned: true,
delegate: CustomStickyHeader(
child: PreferredSize(
preferredSize: Size.fromHeight(45.0),
child: Container(
...
),
),
),
),
// 瀑布流列表
...
],
),
),
// 返回顶部
floatingActionButton: Backtop(controller: scrollController, offset: scrollOffset),
);
flutter3实现短视频功能
@override
Widget build(BuildContext context) {
return Scaffold(
key: scaffoldKey,
extendBodyBehindAppBar: true,
appBar: AppBar(
forceMaterialTransparency: true,
backgroundColor: [0, 1, 4, 5].contains(videoModuleController.videoTabIndex.value) ? null : Colors.transparent,
foregroundColor: [0, 1, 4, 5].contains(videoModuleController.videoTabIndex.value) ? Colors.black : Colors.white,
titleSpacing: 1.0,
leading: Obx(() => IconButton(
icon: Badge.count(
backgroundColor: Colors.red,
count: 6,
child: Icon(Icons.sort_rounded, color: tabColor(),),
),
onPressed: () {
// 自定义打开右侧drawer
scaffoldKey.currentState?.openDrawer();
},
)),
title: Obx(() {
return ScrollConfiguration(
behavior: CustomScrollBehavior().copyWith(scrollbars: false),
child: TabBar(
...
),
);
}),
actions: [
Obx(() => IconButton(icon: Icon(Icons.search_rounded, color: tabColor(),), onPressed: () {},),),
],
),
body: ScrollConfiguration(
behavior: CustomScrollBehavior().copyWith(scrollbars: false),
child: PageView(
controller: pageController,
onPageChanged: (index) {
videoModuleController.updateVideoTabIndex(index);
setState(() {
tabController.animateTo(index, duration: Duration(milliseconds: 200), curve: Curves.easeInOut);
});
},
children: [
...tabModules
],
),
),
// 侧边栏
drawer: Drawer(
shape: RoundedRectangleBorder(borderRadius: BorderRadius.horizontal(right: Radius.circular(15.0))),
clipBehavior: Clip.antiAlias,
width: 300,
child: Container(
...
),
),
);
}
flutter3实现直播功能
// flutter3直播模块 Q:282310962
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.black,
extendBodyBehindAppBar: true,
appBar: AppBar(
forceMaterialTransparency: true,
backgroundColor: Colors.black,
foregroundColor: Colors.white,
toolbarHeight: 0,
),
body: Column(
children: [
Expanded(
child: Stack(
children: [
PageView.builder(
scrollBehavior: CustomScrollBehavior().copyWith(scrollbars: false),
scrollDirection: Axis.vertical,
controller: pageVerticalController,
onPageChanged: (index) async {
setState(() {
liveIndex = index;
});
player.stop();
await player.open(Media(liveJson[index]['src']));
},
itemCount: liveJson.length,
itemBuilder: (context, index) {
return Stack(
children: [
// 视频区域
Positioned(
...
),
/// 水平滚动模块(清屏/浮层)
PageView(
scrollDirection: Axis.horizontal,
controller: pageHorizontalController,
onPageChanged: (index) {
// ...
},
children: [
// 直播清屏
Container(
...
),
// 直播浮层
Stack(
children: [
// 顶部区域
Positioned(
top: MediaQuery.of(context).padding.top + 7,
left: 10.0,
right: 0,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// 直播间头像
Container(
...
),
// 排名统计
Container(
...
),
// 红包活动
Container(
...
),
],
),
),
// 底部区域
Positioned(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// 商品购买动效
Container(
...
),
// 送礼物动效
AnimationLiveGift(
giftQueryList: [
{'label': '小心心', 'gift': 'assets/images/gift/gift1.png', 'user': 'Jack', 'avatar': 'assets/images/avatar/img02.jpg', 'num': 12},
{'label': '棒棒糖', 'gift': 'assets/images/gift/gift2.png', 'user': 'Andy', 'avatar': 'assets/images/avatar/img06.jpg', 'num': 36},
{'label': '大啤酒', 'gift': 'assets/images/gift/gift3.png', 'user': '一条咸鱼', 'avatar': 'assets/images/avatar/img01.jpg', 'num': 162},
...
],
),
// 加入直播间动效
AnimationLiveJoin(
joinQueryList: [
{'avatar': 'assets/images/logo.png', 'name': 'andy'},
{'avatar': 'assets/images/logo.png', 'name': 'jack'},
...
],
),
// 直播弹幕+商品讲解
Container(
margin: EdgeInsets.only(top: 7.0),
height: 200.0,
child: Row(
...
),
),
// 底部工具栏
Container(
margin: const EdgeInsets.only(top: 7.0),
child: Row(
...
),
),
],
),
),
],
),
],
),
],
);
},
),
],
),
),
],
),
);
}
以上就是flutter3.27.1实战抖音app商城的一些知识分享,整个项目涉及到知识点蛮多。希望以上分享对小伙伴们有些帮助哈~~
往期热文
https://segmentfault.com/a/1190000045042968
https://segmentfault.com/a/1190000045245775
https://segmentfault.com/a/1190000045381943
https://segmentfault.com/a/1190000045556523
https://segmentfault.com/a/1190000045667190
作者:xiaoyan2017
链接: https://segmentfault.com/a/1190000046075489
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

浏览器信息检测小工具
https://passer-by.com/browser/
进入上方网页可以检测浏览器信息
https://passer-by.com/browser/
进入上方网页可以检测浏览器信息

vue3.5+tauri2.0+arco桌面版OS系统|vite6.0+tauri2仿macos/windows桌面
经过了三周的爆肝研发,我的又一款原创跨平台重磅新作tauri2.1+vite6+vue3 setup+pinia2+arco.design
桌面客户端OS管理系统Tauri2Vue3OS,正式宣告完结了。支持macos和windows两种桌面风格。
Tauri2.0-Vue3-MacOS桌面端os平台|tauri2+vite6.0+arco电脑版OS管理系统
vue3-tauri2-os系统提供macos和windows11桌面风格、自研拖拽式栅格桌面引擎、封装tauri2多窗口管理、自定义json配置桌面/Dock菜单。
实现技术
- 技术框架:vite^6.0.3+vue^3.5.13+vue-router^4.5.0
- 跨平台框架:tauri^2.1.1
- 组件库:@arco-design/web-vue^2.56.3 (字节桌面版vue3组件库)
- 状态管理:pinia^2.3.0
- 拖拽插件:sortablejs^1.15.6
- 滑屏组件:swiper^11.1.15
- 图表组件:echarts^5.5.1
- markdown编辑器:md-editor-v3^5.1.1
- 模拟数据:mockjs^1.1.0
tauri2.0-vue3os已经正式发布到我的原创作品集,感兴趣的可以去看看。
项目框架目录结构
使用最新版tauri2.0跨平台框架技术,整合vite6构建工具。
tauri2.0-vue3os布局模板
<script setup>
import { appState } from '@/pinia/modules/app'
// 引入布局模板
import MacosLayout from './template/macos.vue'
import WindowsLayout from './template/windows.vue'
const appstate = appState()
const DeskLayout = {
macos: MacosLayout,
windows: WindowsLayout
}
</script>
<template>
<div class="vu__container flexbox" :style="{'--themeSkin': appstate.config.skin}">
<component :is="DeskLayout[appstate.config.layout]" />
</div>
</template>
<script setup>
import { appState } from '@/pinia/modules/app'
import Titlebar from '@/layouts/components/titlebar/index.vue'
import Desk from '@/layouts/components/mac/desk.vue'
import Dock from '@/layouts/components/mac/dock.vue'
const appstate = appState()
</script>
<template>
<div class="vu__layout flexbox flex-col">
<div class="vu__layout-header">
<Titlebar />
</div>
<div class="vu__layout-body flex1 flexbox">
<Desk />
</div>
<div class="vu__layout-footer">
<Dock v-if="appstate.config.dockEnable" />
</div>
</div>
</template>
tauri2+vue3栅格布局
栅格桌面菜单支持如下参数配置:
/**
* label 图标标题
* imgico 图标(本地或网络图片) 支持Arco Design内置图标或自定义iconfont图标
* path 跳转路由页面
* link 跳转外部链接
* hideLabel 是否隐藏图标标题
* filter 是否禁用拖拽
* background 自定义图标背景色
* color 自定义图标颜色
* size 栅格磁贴布局 1x1 ... 12x12
* padding 内边距
* onClick 点击图标回调函数
* isNewin 新窗口打开路由页面
* children 二级菜单
*/
支持children配置二级菜单。
tauri2.0+vue3自定义底部Dock菜单
Dock菜单配置参数:
/**
* label 图标tooltip提示
* imgico 图标(本地或网络图片) 支持Arco Design内置图标或自定义iconfont图标
* path 跳转路由页面
* link 跳转外部链接
* filter 是否禁用拖拽
* color 自定义图标颜色
* onClick 点击图标回调函数
* isNewin 新窗口打开路由页面
* children 二级菜单
*/
另外系统托盘采用tauri2+vue3自定义弹窗实现系统托盘右键功能。
OK,综上就是Tauri2.0+Vue3+Arco实战桌面端os管理系统的一些知识分享。
作者:xiaoyan2017
链接: https://segmentfault.com/a/1190000045667190
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
经过了三周的爆肝研发,我的又一款原创跨平台重磅新作tauri2.1+vite6+vue3 setup+pinia2+arco.design
桌面客户端OS管理系统Tauri2Vue3OS,正式宣告完结了。支持macos和windows两种桌面风格。
Tauri2.0-Vue3-MacOS桌面端os平台|tauri2+vite6.0+arco电脑版OS管理系统
vue3-tauri2-os系统提供macos和windows11桌面风格、自研拖拽式栅格桌面引擎、封装tauri2多窗口管理、自定义json配置桌面/Dock菜单。
实现技术
- 技术框架:vite^6.0.3+vue^3.5.13+vue-router^4.5.0
- 跨平台框架:tauri^2.1.1
- 组件库:@arco-design/web-vue^2.56.3 (字节桌面版vue3组件库)
- 状态管理:pinia^2.3.0
- 拖拽插件:sortablejs^1.15.6
- 滑屏组件:swiper^11.1.15
- 图表组件:echarts^5.5.1
- markdown编辑器:md-editor-v3^5.1.1
- 模拟数据:mockjs^1.1.0
tauri2.0-vue3os已经正式发布到我的原创作品集,感兴趣的可以去看看。
项目框架目录结构
使用最新版tauri2.0跨平台框架技术,整合vite6构建工具。
tauri2.0-vue3os布局模板
<script setup>
import { appState } from '@/pinia/modules/app'
// 引入布局模板
import MacosLayout from './template/macos.vue'
import WindowsLayout from './template/windows.vue'
const appstate = appState()
const DeskLayout = {
macos: MacosLayout,
windows: WindowsLayout
}
</script>
<template>
<div class="vu__container flexbox" :style="{'--themeSkin': appstate.config.skin}">
<component :is="DeskLayout[appstate.config.layout]" />
</div>
</template>
<script setup>
import { appState } from '@/pinia/modules/app'
import Titlebar from '@/layouts/components/titlebar/index.vue'
import Desk from '@/layouts/components/mac/desk.vue'
import Dock from '@/layouts/components/mac/dock.vue'
const appstate = appState()
</script>
<template>
<div class="vu__layout flexbox flex-col">
<div class="vu__layout-header">
<Titlebar />
</div>
<div class="vu__layout-body flex1 flexbox">
<Desk />
</div>
<div class="vu__layout-footer">
<Dock v-if="appstate.config.dockEnable" />
</div>
</div>
</template>
tauri2+vue3栅格布局
栅格桌面菜单支持如下参数配置:
/**
* label 图标标题
* imgico 图标(本地或网络图片) 支持Arco Design内置图标或自定义iconfont图标
* path 跳转路由页面
* link 跳转外部链接
* hideLabel 是否隐藏图标标题
* filter 是否禁用拖拽
* background 自定义图标背景色
* color 自定义图标颜色
* size 栅格磁贴布局 1x1 ... 12x12
* padding 内边距
* onClick 点击图标回调函数
* isNewin 新窗口打开路由页面
* children 二级菜单
*/
支持children配置二级菜单。
tauri2.0+vue3自定义底部Dock菜单
Dock菜单配置参数:
/**
* label 图标tooltip提示
* imgico 图标(本地或网络图片) 支持Arco Design内置图标或自定义iconfont图标
* path 跳转路由页面
* link 跳转外部链接
* filter 是否禁用拖拽
* color 自定义图标颜色
* onClick 点击图标回调函数
* isNewin 新窗口打开路由页面
* children 二级菜单
*/
另外系统托盘采用tauri2+vue3自定义弹窗实现系统托盘右键功能。
OK,综上就是Tauri2.0+Vue3+Arco实战桌面端os管理系统的一些知识分享。
作者:xiaoyan2017
链接: https://segmentfault.com/a/1190000045667190
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

Android平台5+离线打包
本教程一笔化整个离线打包,不列举其他选情况,主要解决官方文档一次看不懂,后续熟悉流程可自行根据官方文档修改自定义设置。参考链接如下:
开发环境及工具
软件的下载演示为MAC,Windows下载选择Windows环境即可。
HbuilderX与SDK版本需要要求一致,PS:有相关bug提出新SDK(4.36)会白屏。本次演示使用4.29版本
使用新版以及后续SDK注意,新版由本次演示后的版本在注意事项中标明Andriod Studio相关环境使用时仔细阅读使用环境(后续下载SDK官方应该会修改环境),本次演示不包含该内容。
- java 1.8
Andriod离线打包
Android Studio打开项目
可能遇到的问题:
-
下载gradle失败
-
分不清build.gradle
下载gradle失败
需要修改为国内镜像,参考文档:Android Studio项目gradle下载慢问题
不想去看的话直接修改gradle/wrapper/gradle-wrapper.properties下distributionUrl配置
修改为
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://mirrors.cloud.tencent.com/gradle/gradle-6.5-all.zip
分不清build.gradle
打开的项目加载完成后会切换为Andriod战士方式,配置时建议切换为项目展示方式
项目中包含两个build.gradle文件分别为项目级和应用级,后续教程内以该规则进行描述
生成证书
可参考文档: 生成签名证书
需要JAVA JDK环境1.8
选择APK,点击下一步
选择创建新的
填写信息,确定
证书名称: simpleDemo.keystore
证书密码: 123456
别名: simple
别名密码: 123123
证书信息:
demo,demo,demo,changsha,hunan,CN
下一步
创建
申请APP离线key
打开终端
移动到证书所在目录
查看证书信息
命令如下
cd simpleDemo
ls
keytool -list -v -keystore simpleDemo.keystore
123456(这里是我生成的 个人配置的输入个人的)
证书指纹
可能遇到的错误:
- java环境
java环境是未进行详细解释,如果是完全按照教程流程唯一可能遇到java环境导致生成不正常意外报错,如果有可以问下评论区大佬。
打开应用管理
各平台信息,新增
填写信息,提交,内容参考上面的证书详情
创建离线key
创建
查看离线key
生成本地打包资源
生成资源
找到资源
替换资源
修改APPID
修改app离线key
修改证书
修改应用级build.gradle,别名密码和证书密码是可以一致的,区别开是为了更好的分辨某个填写至某个
运行
修改build.gradle后需要点击一次Sync Now或者资源重新加载参考教程内 同步gradle配置想·
完成后点击运行
运行完成
本教程一笔化整个离线打包,不列举其他选情况,主要解决官方文档一次看不懂,后续熟悉流程可自行根据官方文档修改自定义设置。参考链接如下:
开发环境及工具
软件的下载演示为MAC,Windows下载选择Windows环境即可。
HbuilderX与SDK版本需要要求一致,PS:有相关bug提出新SDK(4.36)会白屏。本次演示使用4.29版本
使用新版以及后续SDK注意,新版由本次演示后的版本在注意事项中标明Andriod Studio相关环境使用时仔细阅读使用环境(后续下载SDK官方应该会修改环境),本次演示不包含该内容。
- java 1.8
Andriod离线打包
Android Studio打开项目
可能遇到的问题:
-
下载gradle失败
-
分不清build.gradle
下载gradle失败
需要修改为国内镜像,参考文档:Android Studio项目gradle下载慢问题
不想去看的话直接修改gradle/wrapper/gradle-wrapper.properties下distributionUrl配置
修改为
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://mirrors.cloud.tencent.com/gradle/gradle-6.5-all.zip
分不清build.gradle
打开的项目加载完成后会切换为Andriod战士方式,配置时建议切换为项目展示方式
项目中包含两个build.gradle文件分别为项目级和应用级,后续教程内以该规则进行描述
生成证书
可参考文档: 生成签名证书
需要JAVA JDK环境1.8
选择APK,点击下一步
选择创建新的
填写信息,确定
证书名称: simpleDemo.keystore
证书密码: 123456
别名: simple
别名密码: 123123
证书信息:
demo,demo,demo,changsha,hunan,CN
下一步
创建
申请APP离线key
打开终端
移动到证书所在目录
查看证书信息
命令如下
cd simpleDemo
ls
keytool -list -v -keystore simpleDemo.keystore
123456(这里是我生成的 个人配置的输入个人的)
证书指纹
可能遇到的错误:
- java环境
java环境是未进行详细解释,如果是完全按照教程流程唯一可能遇到java环境导致生成不正常意外报错,如果有可以问下评论区大佬。
打开应用管理
各平台信息,新增
填写信息,提交,内容参考上面的证书详情
创建离线key
创建
查看离线key
生成本地打包资源
生成资源
找到资源
替换资源
修改APPID
修改app离线key
修改证书
修改应用级build.gradle,别名密码和证书密码是可以一致的,区别开是为了更好的分辨某个填写至某个
运行
修改build.gradle后需要点击一次Sync Now或者资源重新加载参考教程内 同步gradle配置想·
完成后点击运行
运行完成

uni-admin,H5发布后,报错“未找到集合[xxx]对应的schema”的一种问题原因分享
当然,造成该问题的原因,最好还是看一下对应的schema是不是上传到了unicloud,或者写错了名字
我的故障现象是:在本地测试时,完全没问题,但发布后,就会报错未找到集合[xxx]对应的schema,就偶尔几个表,其他大部分也没事。而且检查云数据库里,确实该表是存在的。
我最终发现,问题出在,我建的数据库表超过100个了,至于怎么出来101个表,我也不知道。
解决办法是删没用的表,删到100个以内,问题就解决了。
希望能帮到大家,这问题耽误了好几个小时。
当然,造成该问题的原因,最好还是看一下对应的schema是不是上传到了unicloud,或者写错了名字
我的故障现象是:在本地测试时,完全没问题,但发布后,就会报错未找到集合[xxx]对应的schema,就偶尔几个表,其他大部分也没事。而且检查云数据库里,确实该表是存在的。
我最终发现,问题出在,我建的数据库表超过100个了,至于怎么出来101个表,我也不知道。
解决办法是删没用的表,删到100个以内,问题就解决了。
希望能帮到大家,这问题耽误了好几个小时。
收起阅读 »
vue3.5+tauri v2桌面版后台管理系统|vite5+tauri2+element-plus客户端后台模板
经过大半个月高强度实战开发,又一款原创跨平台新作tauri2.0+vue3+pinia2+elementPlus+mockjs
电脑端通用权限后台管理系统,正式结束了。实现4种通用布局模板,支持vue-i18n国际化、面包屑导航、tab标签路由等功能。
tauri2.0-vue3admin桌面端管理系统|tauri2+vite5+element-plus后台EXE程序
使用技术
- 开发工具:VScode
- 技术框架:tauri2.0+vite^5.4.8+vue^3.5.11+vue-router^4.4.5
- 状态管理:pinia^2.2.4
- 存储服务:pinia-plugin-persistedstate^4.1.1
- 组件库:element-plus^2.8.5
- 图表组件:echarts^5.5.1
- 国际化:vue-i18n^10.0.4
- 富文本编辑器:@vueup/vue-quill^1.2.0
- md编辑器:md-editor-v3^4.20.3
- 模拟数据:mockjs^1.1.0
- 预处理样式:sass^1.79.4
目前该项目Tauri2-Vue3Admin已经同步发布到我的原创作品集。
项目结构
tauri2-admin后台布局模板
<script setup>
import { appState } from '@/pinia/modules/app'
import Toolbar from '@/layouts/components/Toolbar.vue'
import Sidebar from '@/layouts/components/sidebar/index.vue'
import Menus from '@/layouts/components/menus/index.vue'
import Breadcrumb from '@/layouts/components/Breadcrumb.vue'
import Tabview from '@/layouts/components/Tabview.vue'
import Main from '@/layouts/components/Main.vue'
const appstate = appState()
</script>
<template>
<div class="vuadmin__layout flexbox flex-col">
<Toolbar />
<div class="vuadmin__layout-body flex1 flexbox">
<!-- 侧边栏 -->
<div class="vuadmin__layout-sidebar">
<Sidebar />
</div>
<!-- 菜单栏 -->
<div class="vuadmin__layout-menus" :class="{'hidden': appstate.config.collapsed}">
<el-scrollbar>
<Menus :rootRouteEnable="false" />
</el-scrollbar>
</div>
<!-- 右侧主内容区 -->
<div class="vuadmin__layout-main flex1 flexbox flex-col">
<!-- 面包屑导航 -->
<Breadcrumb v-if="appstate.config.breadcrumb" />
<!-- 标签页 -->
<Tabview v-if="appstate.config.tabview" />
<!-- 内容区 -->
<Main />
</div>
</div>
</div>
</template>
tauri2-admin国际化配置
import { createI18n } from 'vue-i18n'
import { appState } from '@/pinia/modules/app'
// 引入语言配置
import enUS from './en-US'
import zhCN from './zh-CN'
import zhTW from './zh-TW'
// 默认语言
export const langVal = 'zh-CN'
export default async (app) => {
const appstate = appState()
const lang = appstate.lang || langVal
appstate.setLang(lang)
const i18n = createI18n({
legacy: false,
locale: lang,
messages: {
'en': enUS,
'zh-CN': zhCN,
'zh-TW': zhTW
}
})
app.use(i18n)
}
tauri2-admin实现自定义导航栏
<script setup>
import { ref, markRaw } from 'vue'
import { ElMessageBox } from 'element-plus'
import { QuestionFilled, SwitchButton } from '@element-plus/icons-vue'
import { getCurrentWindow } from '@tauri-apps/api/window'
import { listen } from '@tauri-apps/api/event'
import { exit } from '@tauri-apps/plugin-process'
import { isTrue } from '@/utils'
import { authState } from '@/pinia/modules/auth'
const authstate = authState()
const props = defineProps({
color: String,
// 窗口是否可最小化
minimizable: {type: [Boolean, String], default: true},
// 窗口是否可最大化
maximizable: {type: [Boolean, String], default: true},
// 窗口是否可关闭
closable: {type: [Boolean, String], default: true},
// 层级
zIndex: {type: [Number, String], default: 2024},
})
const hasMaximized = ref(false)
const isResizable = ref(true)
const isMaximizable = ref(true)
// 用户是否可以手动调整窗口大小
getCurrentWindow().isResizable().then(res => {
isResizable.value = res
})
// 窗口是否可以最大化
getCurrentWindow().isMaximizable().then(res => {
isMaximizable.value = res
})
// 初始监听窗口是否最大化
getCurrentWindow().isMaximized().then(res => {
hasMaximized.value = res
})
// 实时监听窗口是否最大化
listen('tauri://resize', async() => {
hasMaximized.value = await getCurrentWindow().isMaximized()
})
// 最小化
const handleWinMin = async() => {
await getCurrentWindow().minimize()
}
// 最大化/还原
const handleWinToggle = async() => {
await getCurrentWindow().toggleMaximize()
}
// 关闭
const handleWinClose = async() => {
const isMajor = getCurrentWindow().label.indexOf('main') > -1
if(isMajor) {
ElMessageBox.confirm('是否最小化到系统托盘,不退出程序?', '提示', {
type: 'warning',
icon: markRaw(QuestionFilled),
confirmButtonText: '残忍退出',
cancelButtonText: '最小化到托盘',
customStyle: {'width': '300px'},
draggable: true,
roundButton: true,
center: true,
buttonSize: 'small',
distinguishCancelAndClose: true,
}).then(async() => {
authstate.logout()
await exit()
}).catch(async(action) => {
if(action === 'cancel') {
await getCurrentWindow().hide()
}
})
}else {
await getCurrentWindow().close()
}
}
</script>
<template>
<div class="ev__winbtns flexbox flex-alignc vu__drag" :style="{'z-index': zIndex}">
<div class="ev__winbtns-actions flexbox flex-alignc vu__undrag" :style="{'color': color}">
<a v-if="isTrue(minimizable)" class="wbtn min" title="最小化" @click="handleWinMin"><i class="wicon iconfont elec-icon-min"></i></a>
<a v-if="isTrue(maximizable)" class="wbtn toggle" :title="hasMaximized ? '向下还原' : '最大化'" @click="handleWinToggle">
<i class="wicon iconfont" :class="hasMaximized ? 'elec-icon-restore' : 'elec-icon-max'"></i>
</a>
<a v-if="isTrue(closable)" class="wbtn close" title="关闭" @click="handleWinClose"><i class="wicon iconfont elec-icon-quit"></i></a>
</div>
</div>
</template>
<style lang="scss" scoped>
@import './index.scss';
</style>
tauri2-vue3admin自定义标签栏路由
<template>
<div class="vu__tabview">
<el-tabs
v-model="activeTab"
class="vu__tabview-tabs"
@tab-change="changeTabs"
@tab-remove="removeTab"
>
<el-tab-pane
v-for="(item, index) in tabList"
:key="index"
:name="item.path"
:closable="!item?.meta?.isAffix"
>
<template #label>
<el-dropdown ref="dropdownRef" trigger="contextmenu" :id="item.path" @visible-change="handleDropdownChange($event, item.path)" @command="handleDropdownCommand($event, item)">
<span class="vu__tabview-tabs__label">
<span>{{$t(item?.meta?.title)}}</span>
</span>
<template #dropdown>
<el-dropdown-menu>
<el-dropdown-item command="refresh" :icon="Refresh">{{$t('tabview__contextmenu-refresh')}}</el-dropdown-item>
<el-dropdown-item command="close" :icon="Close" :disabled="item.meta.isAffix">{{$t('tabview__contextmenu-close')}}</el-dropdown-item>
<el-dropdown-item command="closeOther" :icon="Switch">{{$t('tabview__contextmenu-closeother')}}</el-dropdown-item>
<el-dropdown-item command="closeLeft" :icon="DArrowLeft">{{$t('tabview__contextmenu-closeleft')}}</el-dropdown-item>
<el-dropdown-item command="closeRight" :icon="DArrowRight">{{$t('tabview__contextmenu-closeright')}}</el-dropdown-item>
<el-dropdown-item command="closeAll" :icon="CircleCloseFilled">{{$t('tabview__contextmenu-closeall')}}</el-dropdown-item>
</el-dropdown-menu>
</template>
</el-dropdown>
</template>
</el-tab-pane>
</el-tabs>
</div>
</template>
tauri2+vue3实现自定义托盘右键菜单功能。
End,以上就是tauri2+vue3+pinia2实战开发桌面版后台管理系统模板的一些知识分享。
作者:xiaoyan2017
链接: https://segmentfault.com/a/1190000045381943
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
经过大半个月高强度实战开发,又一款原创跨平台新作tauri2.0+vue3+pinia2+elementPlus+mockjs
电脑端通用权限后台管理系统,正式结束了。实现4种通用布局模板,支持vue-i18n国际化、面包屑导航、tab标签路由等功能。
tauri2.0-vue3admin桌面端管理系统|tauri2+vite5+element-plus后台EXE程序
使用技术
- 开发工具:VScode
- 技术框架:tauri2.0+vite^5.4.8+vue^3.5.11+vue-router^4.4.5
- 状态管理:pinia^2.2.4
- 存储服务:pinia-plugin-persistedstate^4.1.1
- 组件库:element-plus^2.8.5
- 图表组件:echarts^5.5.1
- 国际化:vue-i18n^10.0.4
- 富文本编辑器:@vueup/vue-quill^1.2.0
- md编辑器:md-editor-v3^4.20.3
- 模拟数据:mockjs^1.1.0
- 预处理样式:sass^1.79.4
目前该项目Tauri2-Vue3Admin已经同步发布到我的原创作品集。
项目结构
tauri2-admin后台布局模板
<script setup>
import { appState } from '@/pinia/modules/app'
import Toolbar from '@/layouts/components/Toolbar.vue'
import Sidebar from '@/layouts/components/sidebar/index.vue'
import Menus from '@/layouts/components/menus/index.vue'
import Breadcrumb from '@/layouts/components/Breadcrumb.vue'
import Tabview from '@/layouts/components/Tabview.vue'
import Main from '@/layouts/components/Main.vue'
const appstate = appState()
</script>
<template>
<div class="vuadmin__layout flexbox flex-col">
<Toolbar />
<div class="vuadmin__layout-body flex1 flexbox">
<!-- 侧边栏 -->
<div class="vuadmin__layout-sidebar">
<Sidebar />
</div>
<!-- 菜单栏 -->
<div class="vuadmin__layout-menus" :class="{'hidden': appstate.config.collapsed}">
<el-scrollbar>
<Menus :rootRouteEnable="false" />
</el-scrollbar>
</div>
<!-- 右侧主内容区 -->
<div class="vuadmin__layout-main flex1 flexbox flex-col">
<!-- 面包屑导航 -->
<Breadcrumb v-if="appstate.config.breadcrumb" />
<!-- 标签页 -->
<Tabview v-if="appstate.config.tabview" />
<!-- 内容区 -->
<Main />
</div>
</div>
</div>
</template>
tauri2-admin国际化配置
import { createI18n } from 'vue-i18n'
import { appState } from '@/pinia/modules/app'
// 引入语言配置
import enUS from './en-US'
import zhCN from './zh-CN'
import zhTW from './zh-TW'
// 默认语言
export const langVal = 'zh-CN'
export default async (app) => {
const appstate = appState()
const lang = appstate.lang || langVal
appstate.setLang(lang)
const i18n = createI18n({
legacy: false,
locale: lang,
messages: {
'en': enUS,
'zh-CN': zhCN,
'zh-TW': zhTW
}
})
app.use(i18n)
}
tauri2-admin实现自定义导航栏
<script setup>
import { ref, markRaw } from 'vue'
import { ElMessageBox } from 'element-plus'
import { QuestionFilled, SwitchButton } from '@element-plus/icons-vue'
import { getCurrentWindow } from '@tauri-apps/api/window'
import { listen } from '@tauri-apps/api/event'
import { exit } from '@tauri-apps/plugin-process'
import { isTrue } from '@/utils'
import { authState } from '@/pinia/modules/auth'
const authstate = authState()
const props = defineProps({
color: String,
// 窗口是否可最小化
minimizable: {type: [Boolean, String], default: true},
// 窗口是否可最大化
maximizable: {type: [Boolean, String], default: true},
// 窗口是否可关闭
closable: {type: [Boolean, String], default: true},
// 层级
zIndex: {type: [Number, String], default: 2024},
})
const hasMaximized = ref(false)
const isResizable = ref(true)
const isMaximizable = ref(true)
// 用户是否可以手动调整窗口大小
getCurrentWindow().isResizable().then(res => {
isResizable.value = res
})
// 窗口是否可以最大化
getCurrentWindow().isMaximizable().then(res => {
isMaximizable.value = res
})
// 初始监听窗口是否最大化
getCurrentWindow().isMaximized().then(res => {
hasMaximized.value = res
})
// 实时监听窗口是否最大化
listen('tauri://resize', async() => {
hasMaximized.value = await getCurrentWindow().isMaximized()
})
// 最小化
const handleWinMin = async() => {
await getCurrentWindow().minimize()
}
// 最大化/还原
const handleWinToggle = async() => {
await getCurrentWindow().toggleMaximize()
}
// 关闭
const handleWinClose = async() => {
const isMajor = getCurrentWindow().label.indexOf('main') > -1
if(isMajor) {
ElMessageBox.confirm('是否最小化到系统托盘,不退出程序?', '提示', {
type: 'warning',
icon: markRaw(QuestionFilled),
confirmButtonText: '残忍退出',
cancelButtonText: '最小化到托盘',
customStyle: {'width': '300px'},
draggable: true,
roundButton: true,
center: true,
buttonSize: 'small',
distinguishCancelAndClose: true,
}).then(async() => {
authstate.logout()
await exit()
}).catch(async(action) => {
if(action === 'cancel') {
await getCurrentWindow().hide()
}
})
}else {
await getCurrentWindow().close()
}
}
</script>
<template>
<div class="ev__winbtns flexbox flex-alignc vu__drag" :style="{'z-index': zIndex}">
<div class="ev__winbtns-actions flexbox flex-alignc vu__undrag" :style="{'color': color}">
<a v-if="isTrue(minimizable)" class="wbtn min" title="最小化" @click="handleWinMin"><i class="wicon iconfont elec-icon-min"></i></a>
<a v-if="isTrue(maximizable)" class="wbtn toggle" :title="hasMaximized ? '向下还原' : '最大化'" @click="handleWinToggle">
<i class="wicon iconfont" :class="hasMaximized ? 'elec-icon-restore' : 'elec-icon-max'"></i>
</a>
<a v-if="isTrue(closable)" class="wbtn close" title="关闭" @click="handleWinClose"><i class="wicon iconfont elec-icon-quit"></i></a>
</div>
</div>
</template>
<style lang="scss" scoped>
@import './index.scss';
</style>
tauri2-vue3admin自定义标签栏路由
<template>
<div class="vu__tabview">
<el-tabs
v-model="activeTab"
class="vu__tabview-tabs"
@tab-change="changeTabs"
@tab-remove="removeTab"
>
<el-tab-pane
v-for="(item, index) in tabList"
:key="index"
:name="item.path"
:closable="!item?.meta?.isAffix"
>
<template #label>
<el-dropdown ref="dropdownRef" trigger="contextmenu" :id="item.path" @visible-change="handleDropdownChange($event, item.path)" @command="handleDropdownCommand($event, item)">
<span class="vu__tabview-tabs__label">
<span>{{$t(item?.meta?.title)}}</span>
</span>
<template #dropdown>
<el-dropdown-menu>
<el-dropdown-item command="refresh" :icon="Refresh">{{$t('tabview__contextmenu-refresh')}}</el-dropdown-item>
<el-dropdown-item command="close" :icon="Close" :disabled="item.meta.isAffix">{{$t('tabview__contextmenu-close')}}</el-dropdown-item>
<el-dropdown-item command="closeOther" :icon="Switch">{{$t('tabview__contextmenu-closeother')}}</el-dropdown-item>
<el-dropdown-item command="closeLeft" :icon="DArrowLeft">{{$t('tabview__contextmenu-closeleft')}}</el-dropdown-item>
<el-dropdown-item command="closeRight" :icon="DArrowRight">{{$t('tabview__contextmenu-closeright')}}</el-dropdown-item>
<el-dropdown-item command="closeAll" :icon="CircleCloseFilled">{{$t('tabview__contextmenu-closeall')}}</el-dropdown-item>
</el-dropdown-menu>
</template>
</el-dropdown>
</template>
</el-tab-pane>
</el-tabs>
</div>
</template>
tauri2+vue3实现自定义托盘右键菜单功能。
End,以上就是tauri2+vue3+pinia2实战开发桌面版后台管理系统模板的一些知识分享。
作者:xiaoyan2017
链接: https://segmentfault.com/a/1190000045381943
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

vue3+tauri2.0+element-plus桌面端exe聊天模板|vite5+tauri2仿QQ/微信客户端程序
趁着国庆假期,我的又一款原创重磅新作Vue3.5+Tauri2.0+Vite5.4+Pinia2+ElementPlus
跨平台实战仿QQ/微信电脑端聊天Exe程序Vue3Tauri2Chat,正式的完结了。整体UI采用全新无边框透明圆角阴影窗体。
Vue3+Tauri2.0聊天实例|tauri2+vite5+element-plus仿微信|tauri聊天应用
封装tauri2.x多开窗口管理、换肤壁纸、自定义系统托盘闪烁/右键菜单功能。实现聊天、联系人、收藏、朋友圈、短视频、我的等页面模块。
运用技术
- 编码工具:Vscode
- 技术框架:tauri2.0+vite^5.4+vue^3.5+vue-router^4.4.5
- 状态管理:pinia^2.2.2
- 本地存储插件:pinia-plugin-persistedstate^4.0.2
- 组件库:element-plus^2.8.3
- 富文本编辑器:@vueup/vue-quill^1.2.0
- 样式预处理:sass^1.79.3
- 视频滑动组件:swiper^11.1.14
目前tauri2-vue3chat聊天项目已经发布到我的原创作品集,有需要的话可以去瞅瞅~
https://gf.bilibili.com/item/detail/1107133011
tauri2-vue3chat项目布局模板
<template>
<div class="vu__chatbox">
<template v-if="!route?.meta?.isNewWin">
<div class="vu__container flexbox flex-alignc flex-justifyc">
<div class="vu__layout flexbox flex-col">
<div class="vu__layout-body flex1 flexbox" @contextmenu.prevent>
<!-- 菜单栏 -->
<slot v-if="!route?.meta?.hideMenuBar" name="menubar">
<MenuBar />
</slot>
<!-- 侧边栏 -->
<div v-if="route?.meta?.showSideBar" class="vu__layout-sidebar flexbox">
<aside class="vu__layout-sidebar__body flexbox flex-col">
<slot name="sidebar">
<SideBar />
</slot>
</aside>
</div>
<!-- 主内容区 -->
<div class="vu__layout-main flex1 flexbox flex-col">
<ToolBar v-if="!route?.meta?.hideToolBar" />
<router-view v-slot="{ Component, route }">
<keep-alive>
<component :is="Component" :key="route.path" />
</keep-alive>
</router-view>
</div>
</div>
</div>
</div>
</template>
<template v-else>
<WinLayout />
</template>
</div>
</template>
tauri2多窗口实践
// 朋友圈窗口
const handleFzone = () => {
winCreate({
label: 'win-fzone',
url: '/win/fzone',
title: '朋友圈',
width: 500,
height: 695,
minWidth: 350,
minHeight: 500,
maximizable: false,
})
}
// 短视频窗口
const handleFvideo = () => {
winCreate({
label: 'win-fvideo',
url: '/win/fvideo',
title: '短视频',
width: 575,
height: 675,
minWidth: 415,
minHeight: 545
})
}
// 换肤壁纸窗口
const handleSkin = () => {
winCreate({
label: 'win-skin',
url: '/win/skin',
title: '壁纸',
width: 375,
height: 480,
resizable: false,
maximizable: false,
visible: true,
})
}
// 界面管理器
const handleManageUI = () => {
winCreate({
label: 'win-manage',
url: '/win/manage',
title: '界面管理器',
width: 320,
height: 360,
resizable: false,
maximizable: false,
})
}
之前有过一篇关于tauri2创建多窗口应用的分享文章,可以去看看。
基于Tauri2+Vite5搭建桌面端程序|tauri2+vue3多窗口|消息提醒|托盘闪烁
vue3+tauri2自定义透明圆角阴影窗体
.vu__chatbox {height: calc(100vh); padding: 5px; overflow: hidden;}
.vu__layout {
background-color: #f5f5f5;
overflow: hidden;
height: 100%; width: 100%;
position: relative; z-index: 100;
border-radius: 8px;
box-shadow: 0 1px 5px 0 rgba(0, 0, 0, 0.15),0 1px 5px -1px rgba(0, 0, 0, 0.1),0 2px 5px rgba(0, 0, 0, 0.1);
}
<script setup>
/**
* tauri2.0自定义系统最大化/最小化/关闭 by andy Q:282310962
*/
// ...
const props = defineProps({
color: String,
// 窗口是否可最小化
minimizable: {type: [Boolean, String], default: true},
// 窗口是否可最大化
maximizable: {type: [Boolean, String], default: true},
// 窗口是否可关闭
closable: {type: [Boolean, String], default: true},
// 层级
zIndex: {type: [Number, String], default: 2024},
// 关闭前回调,会暂停实例关闭 function(done),done用于关闭
beforeClose: Function
})
const hasMaximized = ref(false)
const isResizable = ref(true)
const isMaximizable = ref(true)
// 用户是否可以手动调整窗口大小
getCurrentWindow().isResizable().then(res => {
isResizable.value = res
})
// 窗口是否可以最大化
getCurrentWindow().isMaximizable().then(res => {
isMaximizable.value = res
})
// 初始监听窗口是否最大化
getCurrentWindow().isMaximized().then(res => {
hasMaximized.value = res
})
// 实时监听窗口是否最大化
listen('tauri://resize', async() => {
hasMaximized.value = await getCurrentWindow().isMaximized()
})
// 最小化
const handleWinMin = async() => {
// winSet('minimize')
await getCurrentWindow().minimize()
}
// 最大化/还原
const handleWinToggle = async() => {
// winSet('max2min')
await getCurrentWindow().toggleMaximize()
}
// 关闭
const handleClose = async() => {
const isMajor = getCurrentWindow().label.indexOf('main') > -1
if(isMajor) {
let el = layer({
type: 'android',
content: '是否最小化到托盘,不退出程序?',
layerStyle: 'background: #f9f9f9; border-radius: 8px;',
closable: false,
resize: false,
btns: [
{
text: '最小化托盘',
style: 'color: #646cff',
click: () => {
layer.close(el)
// winSet('hide')
await getCurrentWindow().hide()
}
},
{
text: '退出程序',
style: 'color: #fa5151',
click: async() => {
authstate.logout()
await exit()
}
}
]
})
}else {
// winSet('close')
await getCurrentWindow().close()
}
}
</script>
<template>
<div class="ev__winbtns vu__drag" :style="{'z-index': zIndex}">
<div class="ev__winbtns-actions vu__undrag" :style="{'color': color}">
<a v-if="isTrue(minimizable)" class="wbtn min" title="最小化" @click="handleWinMin"><i class="wicon elec-icon elec-icon-min"></i></a>
<a v-if="isTrue(maximizable) && isResizable && isMaximizable" class="wbtn toggle" :title="hasMaximized ? '向下还原' : '最大化'" @click="handleWinToggle">
<i class="wicon elec-icon iconfont" :class="hasMaximized ? 've-icon-shrink' : 've-icon-arrowsalt'"></i>
</a>
<a v-if="isTrue(closable)" class="wbtn close" title="关闭" @click="handleClose"><i class="wicon elec-icon elec-icon-quit"></i></a>
</div>
</div>
</template>
综上就是vue3+tauri2.x实战桌面端聊天项目的一些知识分享。
作者:xiaoyan2017
链接: https://segmentfault.com/a/1190000045331960
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
趁着国庆假期,我的又一款原创重磅新作Vue3.5+Tauri2.0+Vite5.4+Pinia2+ElementPlus
跨平台实战仿QQ/微信电脑端聊天Exe程序Vue3Tauri2Chat,正式的完结了。整体UI采用全新无边框透明圆角阴影窗体。
Vue3+Tauri2.0聊天实例|tauri2+vite5+element-plus仿微信|tauri聊天应用
封装tauri2.x多开窗口管理、换肤壁纸、自定义系统托盘闪烁/右键菜单功能。实现聊天、联系人、收藏、朋友圈、短视频、我的等页面模块。
运用技术
- 编码工具:Vscode
- 技术框架:tauri2.0+vite^5.4+vue^3.5+vue-router^4.4.5
- 状态管理:pinia^2.2.2
- 本地存储插件:pinia-plugin-persistedstate^4.0.2
- 组件库:element-plus^2.8.3
- 富文本编辑器:@vueup/vue-quill^1.2.0
- 样式预处理:sass^1.79.3
- 视频滑动组件:swiper^11.1.14
目前tauri2-vue3chat聊天项目已经发布到我的原创作品集,有需要的话可以去瞅瞅~
https://gf.bilibili.com/item/detail/1107133011
tauri2-vue3chat项目布局模板
<template>
<div class="vu__chatbox">
<template v-if="!route?.meta?.isNewWin">
<div class="vu__container flexbox flex-alignc flex-justifyc">
<div class="vu__layout flexbox flex-col">
<div class="vu__layout-body flex1 flexbox" @contextmenu.prevent>
<!-- 菜单栏 -->
<slot v-if="!route?.meta?.hideMenuBar" name="menubar">
<MenuBar />
</slot>
<!-- 侧边栏 -->
<div v-if="route?.meta?.showSideBar" class="vu__layout-sidebar flexbox">
<aside class="vu__layout-sidebar__body flexbox flex-col">
<slot name="sidebar">
<SideBar />
</slot>
</aside>
</div>
<!-- 主内容区 -->
<div class="vu__layout-main flex1 flexbox flex-col">
<ToolBar v-if="!route?.meta?.hideToolBar" />
<router-view v-slot="{ Component, route }">
<keep-alive>
<component :is="Component" :key="route.path" />
</keep-alive>
</router-view>
</div>
</div>
</div>
</div>
</template>
<template v-else>
<WinLayout />
</template>
</div>
</template>
tauri2多窗口实践
// 朋友圈窗口
const handleFzone = () => {
winCreate({
label: 'win-fzone',
url: '/win/fzone',
title: '朋友圈',
width: 500,
height: 695,
minWidth: 350,
minHeight: 500,
maximizable: false,
})
}
// 短视频窗口
const handleFvideo = () => {
winCreate({
label: 'win-fvideo',
url: '/win/fvideo',
title: '短视频',
width: 575,
height: 675,
minWidth: 415,
minHeight: 545
})
}
// 换肤壁纸窗口
const handleSkin = () => {
winCreate({
label: 'win-skin',
url: '/win/skin',
title: '壁纸',
width: 375,
height: 480,
resizable: false,
maximizable: false,
visible: true,
})
}
// 界面管理器
const handleManageUI = () => {
winCreate({
label: 'win-manage',
url: '/win/manage',
title: '界面管理器',
width: 320,
height: 360,
resizable: false,
maximizable: false,
})
}
之前有过一篇关于tauri2创建多窗口应用的分享文章,可以去看看。
基于Tauri2+Vite5搭建桌面端程序|tauri2+vue3多窗口|消息提醒|托盘闪烁
vue3+tauri2自定义透明圆角阴影窗体
.vu__chatbox {height: calc(100vh); padding: 5px; overflow: hidden;}
.vu__layout {
background-color: #f5f5f5;
overflow: hidden;
height: 100%; width: 100%;
position: relative; z-index: 100;
border-radius: 8px;
box-shadow: 0 1px 5px 0 rgba(0, 0, 0, 0.15),0 1px 5px -1px rgba(0, 0, 0, 0.1),0 2px 5px rgba(0, 0, 0, 0.1);
}
<script setup>
/**
* tauri2.0自定义系统最大化/最小化/关闭 by andy Q:282310962
*/
// ...
const props = defineProps({
color: String,
// 窗口是否可最小化
minimizable: {type: [Boolean, String], default: true},
// 窗口是否可最大化
maximizable: {type: [Boolean, String], default: true},
// 窗口是否可关闭
closable: {type: [Boolean, String], default: true},
// 层级
zIndex: {type: [Number, String], default: 2024},
// 关闭前回调,会暂停实例关闭 function(done),done用于关闭
beforeClose: Function
})
const hasMaximized = ref(false)
const isResizable = ref(true)
const isMaximizable = ref(true)
// 用户是否可以手动调整窗口大小
getCurrentWindow().isResizable().then(res => {
isResizable.value = res
})
// 窗口是否可以最大化
getCurrentWindow().isMaximizable().then(res => {
isMaximizable.value = res
})
// 初始监听窗口是否最大化
getCurrentWindow().isMaximized().then(res => {
hasMaximized.value = res
})
// 实时监听窗口是否最大化
listen('tauri://resize', async() => {
hasMaximized.value = await getCurrentWindow().isMaximized()
})
// 最小化
const handleWinMin = async() => {
// winSet('minimize')
await getCurrentWindow().minimize()
}
// 最大化/还原
const handleWinToggle = async() => {
// winSet('max2min')
await getCurrentWindow().toggleMaximize()
}
// 关闭
const handleClose = async() => {
const isMajor = getCurrentWindow().label.indexOf('main') > -1
if(isMajor) {
let el = layer({
type: 'android',
content: '是否最小化到托盘,不退出程序?',
layerStyle: 'background: #f9f9f9; border-radius: 8px;',
closable: false,
resize: false,
btns: [
{
text: '最小化托盘',
style: 'color: #646cff',
click: () => {
layer.close(el)
// winSet('hide')
await getCurrentWindow().hide()
}
},
{
text: '退出程序',
style: 'color: #fa5151',
click: async() => {
authstate.logout()
await exit()
}
}
]
})
}else {
// winSet('close')
await getCurrentWindow().close()
}
}
</script>
<template>
<div class="ev__winbtns vu__drag" :style="{'z-index': zIndex}">
<div class="ev__winbtns-actions vu__undrag" :style="{'color': color}">
<a v-if="isTrue(minimizable)" class="wbtn min" title="最小化" @click="handleWinMin"><i class="wicon elec-icon elec-icon-min"></i></a>
<a v-if="isTrue(maximizable) && isResizable && isMaximizable" class="wbtn toggle" :title="hasMaximized ? '向下还原' : '最大化'" @click="handleWinToggle">
<i class="wicon elec-icon iconfont" :class="hasMaximized ? 've-icon-shrink' : 've-icon-arrowsalt'"></i>
</a>
<a v-if="isTrue(closable)" class="wbtn close" title="关闭" @click="handleClose"><i class="wicon elec-icon elec-icon-quit"></i></a>
</div>
</div>
</template>
综上就是vue3+tauri2.x实战桌面端聊天项目的一些知识分享。
作者:xiaoyan2017
链接: https://segmentfault.com/a/1190000045331960
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

vue3+electron32+arco.design桌面端os模板|vite5+electron32仿mac/win客户端os程序
原创基于electron32.x+vite5+vue3 setup+pinia2+arco-design
实战开发全新桌面版os后台管理系统解决方案Vue3ElectronOS。内置了macos和windows两种风格桌面模板,自研可拖拽栅格布局桌面。
自研Electron32+Vite5+ArcoDesign桌面OS管理系统
运用技术
- 开发工具:VScode
- 技术框架:vite^5.4.1+vue^3.4.37+vue-router^4.4.3
- 跨平台框架:electron^32.0.1
- UI组件库:@arco-design/web-vue^2.56.0 (字节前端vue3组件库)
- 状态管理:pinia^2.2.2
- 拖拽插件:sortablejs^1.15.2
- 图表组件:echarts^5.5.1
- markdown编辑器:md-editor-v3^4.19.2
- 模拟数据:mockjs^1.1.0
- 打包构建:electron-builder^24.13.3
- electron+vite插件:vite-plugin-electron^0.28.7
基于electronjs封装高性能窗口多开器,采用自研栅格化拖拽布局引擎。
项目结构框架
electron32-winos基于vite.js
整合最新跨平台技术electron32.x
搭建项目模板。
目前electron32-vue3-os桌面os已经发布到我的原创作品集。
https://gf.bilibili.com/item/detail/1106958011
Electron主线程配置
/**
* electron主线程配置
* @author andy
*/
import { app, BrowserWindow } from 'electron'
import { WindowManager } from '../src/windows/index.js'
// 忽略安全警告提示 Electron Security Warning (Insecure Content-Security-Policy)
process.env['ELECTRON_DISABLE_SECURITY_WARNINGS'] = true
const createWindow = () => {
let win = new WindowManager()
win.create({isMajor: true})
// 系统托盘管理
win.trayManager()
// 监听ipcMain事件
win.ipcManager()
}
app.whenReady().then(() => {
createWindow()
app.on('activate', () => {
if(BrowserWindow.getAllWindows().length === 0) createWindow()
})
})
app.on('window-all-closed', () => {
if(process.platform !== 'darwin') app.quit()
})
入口文件main.js
import { createApp } from 'vue'
import './style.scss'
import App from './App.vue'
import { launchApp } from '@/windows/actions'
// 引入路由及状态管理
import Router from './router'
import Pinia from './pinia'
// 引入插件
import Plugins from './plugins'
launchApp().then(config => {
if(config) {
// 全局窗口配置
window.config = config
}
// 初始化app实例
createApp(App)
.use(Router)
.use(Pinia)
.use(Plugins)
.mount('#app')
})
electron32-os桌面布局
<script setup>
import { appState } from '@/pinia/modules/app'
// 引入布局模板
import MacosLayout from './template/macos.vue'
import WindowsLayout from './template/windows.vue'
const appstate = appState()
const DeskLayout = {
macos: MacosLayout,
windows: WindowsLayout
}
</script>
<template>
<div class="vu__container" :style="{'--themeSkin': appstate.config.skin}">
<component :is="DeskLayout[appstate.config.layout]" />
</div>
</template>
<script setup>
import Wintool from '@/layouts/components/wintool/index.vue'
import Desk from '@/layouts/components/mac/desk.vue'
import Dock from '@/layouts/components/mac/dock.vue'
</script>
<template>
<div class="vu__layout flexbox flex-col">
<div class="vu__layout-header">
<Wintool />
</div>
<div class="vu__layout-body flex1 flexbox">
<Desk />
</div>
<div class="vu__layout-footer">
<Dock />
</div>
</div>
</template>
electron32-os桌面栅格模板
桌面json菜单配置项
/**
* label 图标标签
* imgico 图标(本地或网络图片) 支持Arco Design内置图标或自定义iconfont字体图标
* path 跳转路由地址
* link 跳转外部链接
* hideLabel 是否隐藏图标标签
* background 自定义图标背景色
* color 自定义图标颜色
* size 栅格布局(16种) 1x1 1x2 1x3 1x4、2x1 2x2 2x3 2x4、3x1 3x2 3x3 3x4、4x1 4x2 4x3 4x4
* onClick 点击图标回调函数
* children 二级菜单配置 * isNewin 新窗口打开路由页面
*/
桌面菜单示例代码
const deskMenu = [
{
uid: 'd137f210-507e-7e8e-1950-9deefac27e48',
list: [
{imgico: markRaw(Today), size: '2x2'},
{label: '日历', imgico: markRaw(Calendar3x3), size: '3x3'},
{label: 'Electron32', imgico: '/electron.svg', link: 'https://www.electronjs.org/'},
// ...
]
},
{
uid: 'g270f210-207e-6e8e-2650-9deefac27e48',
list: [
{label: 'Appstore', imgico: '/static/mac/appstore.png'},
// ...
]
},
{
uid: 't165f210-607e-4e8e-9950-9deefac27e48',
list: [
{label: 'Vue.js', imgico: '/vue.svg', link: 'https://vuejs.org/',},
{label: 'Vite.js官方文档', imgico: '/vite.svg', link: 'https://vitejs.dev/',},
// ...
]
},
{
uid: 'u327f210-207e-1e8e-9950-9deefac27e48',
list: [
{label: 'Electron32', imgico: '/electron.svg', link: 'https://www.electronjs.org/'},
{label: '首页', imgico: markRaw(IconHome), path: '/home', color: '#fff', isNewin: true},
{label: '工作台', imgico: 'elec-icon-dotchart', path: '/home/dashboard', color: '#fff'},
// ...
{
label: '用户中心',
children: [
{label: '主页', imgico: '/static/svg/ucenter.svg', path: '/setting'},
{label: '用户管理', imgico: markRaw(IconUserGroup), path: '/user', color: '#fff'},
// ...
]
},
{
label: '设置',
children: [
// ...
]
},
{
label: '收藏网址',
children: [
{label: 'Electron32', imgico: '/electron.svg', link: 'https://www.electronjs.org/'},
{label: 'Vite.js', imgico: '/vite.svg',},
// ...
]
},
{
label: '公众号', imgico: '/static/qrimg.png', color: '#07c160',
onClick: () => {
Modal.info({
// ...
})
}
},
]
}
]
Okay,综上就是electron32+vue3开发桌面端os系统的一些知识分享。
作者:xiaoyan2017
链接: https://segmentfault.com/a/1190000045245775
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
原创基于electron32.x+vite5+vue3 setup+pinia2+arco-design
实战开发全新桌面版os后台管理系统解决方案Vue3ElectronOS。内置了macos和windows两种风格桌面模板,自研可拖拽栅格布局桌面。
自研Electron32+Vite5+ArcoDesign桌面OS管理系统
运用技术
- 开发工具:VScode
- 技术框架:vite^5.4.1+vue^3.4.37+vue-router^4.4.3
- 跨平台框架:electron^32.0.1
- UI组件库:@arco-design/web-vue^2.56.0 (字节前端vue3组件库)
- 状态管理:pinia^2.2.2
- 拖拽插件:sortablejs^1.15.2
- 图表组件:echarts^5.5.1
- markdown编辑器:md-editor-v3^4.19.2
- 模拟数据:mockjs^1.1.0
- 打包构建:electron-builder^24.13.3
- electron+vite插件:vite-plugin-electron^0.28.7
基于electronjs封装高性能窗口多开器,采用自研栅格化拖拽布局引擎。
项目结构框架
electron32-winos基于vite.js
整合最新跨平台技术electron32.x
搭建项目模板。
目前electron32-vue3-os桌面os已经发布到我的原创作品集。
https://gf.bilibili.com/item/detail/1106958011
Electron主线程配置
/**
* electron主线程配置
* @author andy
*/
import { app, BrowserWindow } from 'electron'
import { WindowManager } from '../src/windows/index.js'
// 忽略安全警告提示 Electron Security Warning (Insecure Content-Security-Policy)
process.env['ELECTRON_DISABLE_SECURITY_WARNINGS'] = true
const createWindow = () => {
let win = new WindowManager()
win.create({isMajor: true})
// 系统托盘管理
win.trayManager()
// 监听ipcMain事件
win.ipcManager()
}
app.whenReady().then(() => {
createWindow()
app.on('activate', () => {
if(BrowserWindow.getAllWindows().length === 0) createWindow()
})
})
app.on('window-all-closed', () => {
if(process.platform !== 'darwin') app.quit()
})
入口文件main.js
import { createApp } from 'vue'
import './style.scss'
import App from './App.vue'
import { launchApp } from '@/windows/actions'
// 引入路由及状态管理
import Router from './router'
import Pinia from './pinia'
// 引入插件
import Plugins from './plugins'
launchApp().then(config => {
if(config) {
// 全局窗口配置
window.config = config
}
// 初始化app实例
createApp(App)
.use(Router)
.use(Pinia)
.use(Plugins)
.mount('#app')
})
electron32-os桌面布局
<script setup>
import { appState } from '@/pinia/modules/app'
// 引入布局模板
import MacosLayout from './template/macos.vue'
import WindowsLayout from './template/windows.vue'
const appstate = appState()
const DeskLayout = {
macos: MacosLayout,
windows: WindowsLayout
}
</script>
<template>
<div class="vu__container" :style="{'--themeSkin': appstate.config.skin}">
<component :is="DeskLayout[appstate.config.layout]" />
</div>
</template>
<script setup>
import Wintool from '@/layouts/components/wintool/index.vue'
import Desk from '@/layouts/components/mac/desk.vue'
import Dock from '@/layouts/components/mac/dock.vue'
</script>
<template>
<div class="vu__layout flexbox flex-col">
<div class="vu__layout-header">
<Wintool />
</div>
<div class="vu__layout-body flex1 flexbox">
<Desk />
</div>
<div class="vu__layout-footer">
<Dock />
</div>
</div>
</template>
electron32-os桌面栅格模板
桌面json菜单配置项
/**
* label 图标标签
* imgico 图标(本地或网络图片) 支持Arco Design内置图标或自定义iconfont字体图标
* path 跳转路由地址
* link 跳转外部链接
* hideLabel 是否隐藏图标标签
* background 自定义图标背景色
* color 自定义图标颜色
* size 栅格布局(16种) 1x1 1x2 1x3 1x4、2x1 2x2 2x3 2x4、3x1 3x2 3x3 3x4、4x1 4x2 4x3 4x4
* onClick 点击图标回调函数
* children 二级菜单配置 * isNewin 新窗口打开路由页面
*/
桌面菜单示例代码
const deskMenu = [
{
uid: 'd137f210-507e-7e8e-1950-9deefac27e48',
list: [
{imgico: markRaw(Today), size: '2x2'},
{label: '日历', imgico: markRaw(Calendar3x3), size: '3x3'},
{label: 'Electron32', imgico: '/electron.svg', link: 'https://www.electronjs.org/'},
// ...
]
},
{
uid: 'g270f210-207e-6e8e-2650-9deefac27e48',
list: [
{label: 'Appstore', imgico: '/static/mac/appstore.png'},
// ...
]
},
{
uid: 't165f210-607e-4e8e-9950-9deefac27e48',
list: [
{label: 'Vue.js', imgico: '/vue.svg', link: 'https://vuejs.org/',},
{label: 'Vite.js官方文档', imgico: '/vite.svg', link: 'https://vitejs.dev/',},
// ...
]
},
{
uid: 'u327f210-207e-1e8e-9950-9deefac27e48',
list: [
{label: 'Electron32', imgico: '/electron.svg', link: 'https://www.electronjs.org/'},
{label: '首页', imgico: markRaw(IconHome), path: '/home', color: '#fff', isNewin: true},
{label: '工作台', imgico: 'elec-icon-dotchart', path: '/home/dashboard', color: '#fff'},
// ...
{
label: '用户中心',
children: [
{label: '主页', imgico: '/static/svg/ucenter.svg', path: '/setting'},
{label: '用户管理', imgico: markRaw(IconUserGroup), path: '/user', color: '#fff'},
// ...
]
},
{
label: '设置',
children: [
// ...
]
},
{
label: '收藏网址',
children: [
{label: 'Electron32', imgico: '/electron.svg', link: 'https://www.electronjs.org/'},
{label: 'Vite.js', imgico: '/vite.svg',},
// ...
]
},
{
label: '公众号', imgico: '/static/qrimg.png', color: '#07c160',
onClick: () => {
Modal.info({
// ...
})
}
},
]
}
]
Okay,综上就是electron32+vue3开发桌面端os系统的一些知识分享。
作者:xiaoyan2017
链接: https://segmentfault.com/a/1190000045245775
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

vue3+electron31+element-plus后台系统管理应用程序
整合vite5.x+electron31+pinia2+vue-i18n+echarts全新后台管理方案Vue3ElectronAdmin。提供了4种通用布局模板,支持中英文/繁体国际化解决方案、动态路由权限,实现了表格、表单、列表、图表、编辑器、错误处理等模块。
原创Electron31+Vue3+ElementPlus桌面端后台管理系统
技术栈
- 编辑器:vscode
- 框架技术:vite^5.3.4+vue^3.4.31+vue-router^4.4.0
- 跨端框架:electron^31.3.0
- 组件库:element-plus^2.7.8
- 状态管理:pinia^2.2.0
- 国际化方案:vue-i18n@9
- 图表组件:echarts^5.5.1
- markdown编辑器:md-editor-v3^4.18.0
- 模拟数据:mockjs^1.1.0
- 打包工具:electron-builder^24.13.3
- electron+vite桥接插件:vite-plugin-electron^0.28.7
功能性
1、最新前端技术栈Vite5.x、Vue3、Electron31、ElementPlus、Vue-I18n、Echarts
2、支持中英文/繁体国际化解决方案
3、支持动态权限路由、多页签缓存路由
4、封装多窗口管理器
5、内置4种通用布局模板、自由切换风格
6、整合通用的表格、表单、列表、图表、编辑器、错误处理等模块
7、高颜值UI界面、轻量级模块化、高定制性
项目结构
整个项目整合vite.js+electronjs
跨平台技术,采用vue3 setup
语法编码。
electronjs主线程配置
/**
* electron主线程配置
* @author andy
*/
import { app, BrowserWindow } from 'electron'
import { WindowManager } from '../src/windows/index.js'
// 忽略安全警告提示 Electron Security Warning (Insecure Content-Security-Policy)
process.env['ELECTRON_DISABLE_SECURITY_WARNINGS'] = true
const createWindow = () => {
let win = new WindowManager()
win.create({isMajor: true})
// 系统托盘管理
win.trayManager()
// 监听ipcMain事件
win.ipcManager()
}
app.whenReady().then(() => {
createWindow()
app.on('activate', () => {
if(BrowserWindow.getAllWindows().length === 0) createWindow()
})
})
app.on('window-all-closed', () => {
if(process.platform !== 'darwin') app.quit()
})
electron31-vue3-admin布局模板
/**
* 通用布局模板
* @author Andy
*/
<script setup>
import { appState } from '@/pinia/modules/app'
// 引入布局模板
import Classic from './template/classic/index.vue'
import Columns from './template/columns/index.vue'
import Vertical from './template/vertical/index.vue'
import Horizontal from './template/horizontal/index.vue'
const appstate = appState()
const LayoutMap = {
'classic': Classic,
'columns': Columns,
'vertical': Vertical,
'horizontal': Horizontal
}
</script>
<template>
<div class="vuadmin__container" :style="{'--themeSkin': appstate.config.skin}">
<component :is="LayoutMap[appstate.config.layout]" />
</div>
</template>
electron31-admin国际化配置
/**
* 国际化配置
* @author YXY
*/
import { createI18n } from 'vue-i18n'
import { appState } from '@/pinia/modules/app'
// 引入语言配置
import enUS from './en-US'
import zhCN from './zh-CN'
import zhTW from './zh-TW'
// 默认语言
export const langVal = 'zh-CN'
export default async (app) => {
const appstate = appState()
const lang = appstate.lang || langVal
appstate.setLang(lang)
const i18n = createI18n({
legacy: false,
locale: lang,
messages: {
'en': enUS,
'zh-CN': zhCN,
'zh-TW': zhTW
}
})
app.use(i18n)
}
vue3封装echarts图表hook
/**
* 动态图表Hook
*/
import { onMounted, onBeforeUnmount, ref } from 'vue'
import * as echarts from 'echarts'
import elementResizeDetectorMaker from 'element-resize-detector'
export function useEcharts(el, options) {
let chartEl
let chartRef = ref(null)
let erd = elementResizeDetectorMaker()
const resizeHandle = () => {
chartEl && chartEl.resize()
}
onMounted(() => {
if(el?.value) {
chartEl = echarts.init(el.value)
chartEl.setOption(options)
chartRef.value = chartEl
}
erd.listenTo(el.value, resizeHandle)
})
onBeforeUnmount(() => {
chartEl.dispose()
erd.removeListener(el.value, resizeHandle)
})
return chartRef
}
OK,以上就是Electron31+Vue3+ElementPlus跨平台实战开发后台管理系统的一些分享。整个项目涉及到的知识点还是蛮多的,限于篇幅就暂时分享到这里。希望对大家有所帮助哈~
作者:xiaoyan2017
链接: https://segmentfault.com/a/1190000045186093
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
整合vite5.x+electron31+pinia2+vue-i18n+echarts全新后台管理方案Vue3ElectronAdmin。提供了4种通用布局模板,支持中英文/繁体国际化解决方案、动态路由权限,实现了表格、表单、列表、图表、编辑器、错误处理等模块。
原创Electron31+Vue3+ElementPlus桌面端后台管理系统
技术栈
- 编辑器:vscode
- 框架技术:vite^5.3.4+vue^3.4.31+vue-router^4.4.0
- 跨端框架:electron^31.3.0
- 组件库:element-plus^2.7.8
- 状态管理:pinia^2.2.0
- 国际化方案:vue-i18n@9
- 图表组件:echarts^5.5.1
- markdown编辑器:md-editor-v3^4.18.0
- 模拟数据:mockjs^1.1.0
- 打包工具:electron-builder^24.13.3
- electron+vite桥接插件:vite-plugin-electron^0.28.7
功能性
1、最新前端技术栈Vite5.x、Vue3、Electron31、ElementPlus、Vue-I18n、Echarts
2、支持中英文/繁体国际化解决方案
3、支持动态权限路由、多页签缓存路由
4、封装多窗口管理器
5、内置4种通用布局模板、自由切换风格
6、整合通用的表格、表单、列表、图表、编辑器、错误处理等模块
7、高颜值UI界面、轻量级模块化、高定制性
项目结构
整个项目整合vite.js+electronjs
跨平台技术,采用vue3 setup
语法编码。
electronjs主线程配置
/**
* electron主线程配置
* @author andy
*/
import { app, BrowserWindow } from 'electron'
import { WindowManager } from '../src/windows/index.js'
// 忽略安全警告提示 Electron Security Warning (Insecure Content-Security-Policy)
process.env['ELECTRON_DISABLE_SECURITY_WARNINGS'] = true
const createWindow = () => {
let win = new WindowManager()
win.create({isMajor: true})
// 系统托盘管理
win.trayManager()
// 监听ipcMain事件
win.ipcManager()
}
app.whenReady().then(() => {
createWindow()
app.on('activate', () => {
if(BrowserWindow.getAllWindows().length === 0) createWindow()
})
})
app.on('window-all-closed', () => {
if(process.platform !== 'darwin') app.quit()
})
electron31-vue3-admin布局模板
/**
* 通用布局模板
* @author Andy
*/
<script setup>
import { appState } from '@/pinia/modules/app'
// 引入布局模板
import Classic from './template/classic/index.vue'
import Columns from './template/columns/index.vue'
import Vertical from './template/vertical/index.vue'
import Horizontal from './template/horizontal/index.vue'
const appstate = appState()
const LayoutMap = {
'classic': Classic,
'columns': Columns,
'vertical': Vertical,
'horizontal': Horizontal
}
</script>
<template>
<div class="vuadmin__container" :style="{'--themeSkin': appstate.config.skin}">
<component :is="LayoutMap[appstate.config.layout]" />
</div>
</template>
electron31-admin国际化配置
/**
* 国际化配置
* @author YXY
*/
import { createI18n } from 'vue-i18n'
import { appState } from '@/pinia/modules/app'
// 引入语言配置
import enUS from './en-US'
import zhCN from './zh-CN'
import zhTW from './zh-TW'
// 默认语言
export const langVal = 'zh-CN'
export default async (app) => {
const appstate = appState()
const lang = appstate.lang || langVal
appstate.setLang(lang)
const i18n = createI18n({
legacy: false,
locale: lang,
messages: {
'en': enUS,
'zh-CN': zhCN,
'zh-TW': zhTW
}
})
app.use(i18n)
}
vue3封装echarts图表hook
/**
* 动态图表Hook
*/
import { onMounted, onBeforeUnmount, ref } from 'vue'
import * as echarts from 'echarts'
import elementResizeDetectorMaker from 'element-resize-detector'
export function useEcharts(el, options) {
let chartEl
let chartRef = ref(null)
let erd = elementResizeDetectorMaker()
const resizeHandle = () => {
chartEl && chartEl.resize()
}
onMounted(() => {
if(el?.value) {
chartEl = echarts.init(el.value)
chartEl.setOption(options)
chartRef.value = chartEl
}
erd.listenTo(el.value, resizeHandle)
})
onBeforeUnmount(() => {
chartEl.dispose()
erd.removeListener(el.value, resizeHandle)
})
return chartRef
}
OK,以上就是Electron31+Vue3+ElementPlus跨平台实战开发后台管理系统的一些分享。整个项目涉及到的知识点还是蛮多的,限于篇幅就暂时分享到这里。希望对大家有所帮助哈~
作者:xiaoyan2017
链接: https://segmentfault.com/a/1190000045186093
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

如何在GitHub免费搭建个人博客网站?
如何在GitHub免费搭建个人博客网站?当你想要开始自己的博客之旅,但又不想花费金钱购买服务器和域名时,还有一些免费的平台可供你选择。以下是一种无需服务器和域名的方法,利用GitHub Pages和Jekyll搭建个人博客网站(http://m.bokequ.com/list/22-0.html)
步骤一:准备 GitHub 账户
如果你还没有 GitHub 账户,首先需要注册一个。GitHub 提供免费的代码托管服务,同时也支持通过 GitHub Pages 托管静态网站。
步骤二:创建 GitHub 仓库
登录你的 GitHub 账户,点击右上角的加号按钮,选择 "New repository"。在 "Repository name" 栏中输入你的用户名(或者你希望的博客地址),比如 yourusername.github.io(注意替换成你的用户名)。勾选 "Initialize this repository with a README" 选项,并点击 "Create repository"。
步骤三:下载 Jekyll 主题
Jekyll 是一个简单易用的静态网站生成器,GitHub Pages 支持使用 Jekyll 搭建个人网站。你可以在 Jekyll 官方网站(https://jekyllrb.com/)或 GitHub 上找到各种免费的 Jekyll 主题。选择一个你喜欢的主题,将其下载并解压缩到本地。
步骤四:上传文件到 GitHub 仓库
将 Jekyll 主题文件夹中的所有文件上传到你在步骤二中创建的 GitHub 仓库中。你可以使用 GitHub Desktop、Git 命令行或者直接通过 GitHub 网站上传文件。
步骤五:访问你的博客网站
等待一段时间,GitHub 会自动构建你的网站,并将其托管在bokequ.github.io这个地址上。你可以在浏览器中输入这个地址,访问你的个人博客网站。
步骤六:定制你的博客
编辑 Jekyll 主题文件夹中的配置文件和内容文件,定制你的个人博客。你可以修改页面布局、添加新的页面和文章,以及调整样式和颜色。
通过 GitHub Pages 和 Jekyll,你可以免费搭建个人博客网站,无需购买服务器和域名。这是一个简单且经济高效的方式,让你能够开始你的博客之旅,并与世界分享你的想法和创作。
如何在GitHub免费搭建个人博客网站?当你想要开始自己的博客之旅,但又不想花费金钱购买服务器和域名时,还有一些免费的平台可供你选择。以下是一种无需服务器和域名的方法,利用GitHub Pages和Jekyll搭建个人博客网站(http://m.bokequ.com/list/22-0.html)
步骤一:准备 GitHub 账户
如果你还没有 GitHub 账户,首先需要注册一个。GitHub 提供免费的代码托管服务,同时也支持通过 GitHub Pages 托管静态网站。
步骤二:创建 GitHub 仓库
登录你的 GitHub 账户,点击右上角的加号按钮,选择 "New repository"。在 "Repository name" 栏中输入你的用户名(或者你希望的博客地址),比如 yourusername.github.io(注意替换成你的用户名)。勾选 "Initialize this repository with a README" 选项,并点击 "Create repository"。
步骤三:下载 Jekyll 主题
Jekyll 是一个简单易用的静态网站生成器,GitHub Pages 支持使用 Jekyll 搭建个人网站。你可以在 Jekyll 官方网站(https://jekyllrb.com/)或 GitHub 上找到各种免费的 Jekyll 主题。选择一个你喜欢的主题,将其下载并解压缩到本地。
步骤四:上传文件到 GitHub 仓库
将 Jekyll 主题文件夹中的所有文件上传到你在步骤二中创建的 GitHub 仓库中。你可以使用 GitHub Desktop、Git 命令行或者直接通过 GitHub 网站上传文件。
步骤五:访问你的博客网站
等待一段时间,GitHub 会自动构建你的网站,并将其托管在bokequ.github.io这个地址上。你可以在浏览器中输入这个地址,访问你的个人博客网站。
步骤六:定制你的博客
编辑 Jekyll 主题文件夹中的配置文件和内容文件,定制你的个人博客。你可以修改页面布局、添加新的页面和文章,以及调整样式和颜色。
通过 GitHub Pages 和 Jekyll,你可以免费搭建个人博客网站,无需购买服务器和域名。这是一个简单且经济高效的方式,让你能够开始你的博客之旅,并与世界分享你的想法和创作。
收起阅读 »
PHP框架的性能比较
基准测试结果表明,在页面加载时间方面,codeigniter 最快,其次是 laravel、symfony 和 zend framework。在数据库操作方面,codeigniter 最快,其次是 laravel、symfony 和 zend framework。在内存使用方面,codeigniter 最少,其次是 laravel、symfony 和 zend framework。实战案例表明,codeigniter 非常适合小型项目,而 laravel 和 symfony 适用于中型到大型项目,zend framework 适用于企业级应用,但性能较差。
PHP框架性能比较
在选择PHP框架时,性能是一个关键考虑因素。本文将比较常见的 PHP 框架的性能,并提供实战案例来展示其差异http://m.bokequ.com/moban/1252.html
比较的框架
Laravel: 一个流行的 MVC 框架,以其易用性和强大的特性而闻名。
Symfony: 一个广泛的框架,提供丰富的组件库和灵活的配置选项。
Zend Framework: 一个老牌的企业级框架,以其稳定性和安全性而闻名。
CodeIgniter: 一个轻量级的 MVC 框架,非常适合小型到中型的项目。
基准测试
我们使用以下基准测试来比较这些框架:
页面加载时间:加载一个简单页面的时间
数据库操作:执行数据库查询的速度
内存使用:框架运行时所需的内存量
实战案例
我们创建一个简单的博客应用程序,使用每个框架来显示一页包含 10 篇文章的帖子。我们使用 Apache Bench 进行基准测试,每秒发送 100 个请求持续 10 分钟。
结果
页面加载时间:Laravel
数据库操作:CodeIgniter
内存使用:CodeIgniter
结论
从基准测试和实战案例中可以看出,CodeIgniter 在性能方面表现出色,非常适合小型项目。 Laravel 和 Symfony 在性能和功能方面实现了良好的平衡,适用于中型到大型项目。 Zend Framework 是企业级应用程序的首选,提供卓越的稳定性和安全性,但它的性能也受到影响。
基准测试结果表明,在页面加载时间方面,codeigniter 最快,其次是 laravel、symfony 和 zend framework。在数据库操作方面,codeigniter 最快,其次是 laravel、symfony 和 zend framework。在内存使用方面,codeigniter 最少,其次是 laravel、symfony 和 zend framework。实战案例表明,codeigniter 非常适合小型项目,而 laravel 和 symfony 适用于中型到大型项目,zend framework 适用于企业级应用,但性能较差。
PHP框架性能比较
在选择PHP框架时,性能是一个关键考虑因素。本文将比较常见的 PHP 框架的性能,并提供实战案例来展示其差异http://m.bokequ.com/moban/1252.html
比较的框架
Laravel: 一个流行的 MVC 框架,以其易用性和强大的特性而闻名。
Symfony: 一个广泛的框架,提供丰富的组件库和灵活的配置选项。
Zend Framework: 一个老牌的企业级框架,以其稳定性和安全性而闻名。
CodeIgniter: 一个轻量级的 MVC 框架,非常适合小型到中型的项目。
基准测试
我们使用以下基准测试来比较这些框架:
页面加载时间:加载一个简单页面的时间
数据库操作:执行数据库查询的速度
内存使用:框架运行时所需的内存量
实战案例
我们创建一个简单的博客应用程序,使用每个框架来显示一页包含 10 篇文章的帖子。我们使用 Apache Bench 进行基准测试,每秒发送 100 个请求持续 10 分钟。
结果
页面加载时间:Laravel
数据库操作:CodeIgniter
内存使用:CodeIgniter
结论
从基准测试和实战案例中可以看出,CodeIgniter 在性能方面表现出色,非常适合小型项目。 Laravel 和 Symfony 在性能和功能方面实现了良好的平衡,适用于中型到大型项目。 Zend Framework 是企业级应用程序的首选,提供卓越的稳定性和安全性,但它的性能也受到影响。
收起阅读 »
网站如何实现https重定向(301)到http
对于个人网站站注册比较少的,服务器配置不是很好的,没必要https,https跳转到http是要时间的,会影响网站打开的速度。免费的https每年都要更换。个人博客网站https有一段时间了,而且很多页面都有收录排名,现在已去掉https了,用户搜索从https进网站无法打开页面。去掉后https对面网站有一定的影响,所有这里就要实现访问https自动跳转到http
网站设置http跳转到https比较容易,如相反方向将https跳转到http,不是专搞程序的,有点难设置。网上文章也有很多"HTTPS重定向到HTTP的解决方法"。但很多都是没用的,都是转载别人没测试过,搞的网站打不开。
将以下代码放在你网站根目录下的.htaccess文件,没有.htaccess可以新建一个。域名换成你自己的域名,经测试有效
RewriteEngine On
RewriteBase /
RewriteCond %{HTTP_HOST} !^www\. [NC]
RewriteRule ^ http://www.bokequ.com%{REQUEST_URI} [L,R=301,NE]
RewriteCond %{HTTPS} on [OR]
RewriteCond %{HTTP:X-Forwarded-Proto} https [OR]
RewriteCond %{SERVER_PORT} ^443$
RewriteRule ^ http://%{HTTP_HOST}%{REQUEST_URI} [L,R=301,NE]
RewriteCond %{HTTP_REFERER} !^$
RewriteCond %{HTTP_REFERER} !^http://(www\.)?bokequ.com/.*$ [NC]
RewriteRule \.(gif|jpg|png|tif|js|css|xls|xlsx|zip|rar|pdf|ods|ots)$ - [F,NC]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-l
RewriteRule ^(.+)$ index.php/$1 [L]
对于个人网站站注册比较少的,服务器配置不是很好的,没必要https,https跳转到http是要时间的,会影响网站打开的速度。免费的https每年都要更换。个人博客网站https有一段时间了,而且很多页面都有收录排名,现在已去掉https了,用户搜索从https进网站无法打开页面。去掉后https对面网站有一定的影响,所有这里就要实现访问https自动跳转到http
网站设置http跳转到https比较容易,如相反方向将https跳转到http,不是专搞程序的,有点难设置。网上文章也有很多"HTTPS重定向到HTTP的解决方法"。但很多都是没用的,都是转载别人没测试过,搞的网站打不开。
将以下代码放在你网站根目录下的.htaccess文件,没有.htaccess可以新建一个。域名换成你自己的域名,经测试有效
RewriteEngine On
RewriteBase /
RewriteCond %{HTTP_HOST} !^www\. [NC]
RewriteRule ^ http://www.bokequ.com%{REQUEST_URI} [L,R=301,NE]
RewriteCond %{HTTPS} on [OR]
RewriteCond %{HTTP:X-Forwarded-Proto} https [OR]
RewriteCond %{SERVER_PORT} ^443$
RewriteRule ^ http://%{HTTP_HOST}%{REQUEST_URI} [L,R=301,NE]
RewriteCond %{HTTP_REFERER} !^$
RewriteCond %{HTTP_REFERER} !^http://(www\.)?bokequ.com/.*$ [NC]
RewriteRule \.(gif|jpg|png|tif|js|css|xls|xlsx|zip|rar|pdf|ods|ots)$ - [F,NC]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-l
RewriteRule ^(.+)$ index.php/$1 [L]
收起阅读 »