HBuilderX

HBuilderX

极客开发工具
uni-app

uni-app

开发一次,多端覆盖
uniCloud

uniCloud

云开发平台
HTML5+

HTML5+

增强HTML5的功能体验
MUI

MUI

上万Star的前端框架

Flutter3.27实战2025抖音app直播商城

flutter

原创自研flutter3.27+dart3.6实战抖音短视频+聊天+直播电商带货app商城应用程序。

Flutter3.27仿抖音短视频+直播+聊天app商城系统

img

img

技术栈

  • 编辑器: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

img

img

实现类似抖音app首页左右滑动切换页面内容,上下滑动切换短视频效果。

img

项目框架

img

目前flutter3-douyin-mall短视频直播商城项目已经同步到我的原创作品集。
Flutter3.27仿抖音短视频+直播+聊天app商城系统

img

img

img

flutter3实现首页轮播图+tab滚动吸附

img

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),  
);

img

img

img

img

flutter3实现短视频功能

img

img

@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(  
        ...  
      ),  
    ),  
  );  
}

img

img

img

img

img

img

img

img

flutter3实现直播功能

img

img

// 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商城系统

img

img

技术栈

  • 编辑器: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

img

img

实现类似抖音app首页左右滑动切换页面内容,上下滑动切换短视频效果。

img

项目框架

img

目前flutter3-douyin-mall短视频直播商城项目已经同步到我的原创作品集。
Flutter3.27仿抖音短视频+直播+聊天app商城系统

img

img

img

flutter3实现首页轮播图+tab滚动吸附

img

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),  
);

img

img

img

img

flutter3实现短视频功能

img

img

@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(  
        ...  
      ),  
    ),  
  );  
}

img

img

img

img

img

img

img

img

flutter3实现直播功能

img

img

// 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桌面

vite vue3

经过了三周的爆肝研发,我的又一款原创跨平台重磅新作tauri2.1+vite6+vue3 setup+pinia2+arco.design桌面客户端OS管理系统Tauri2Vue3OS,正式宣告完结了。支持macoswindows两种桌面风格。

Tauri2.0-Vue3-MacOS桌面端os平台|tauri2+vite6.0+arco电脑版OS管理系统

img

img

vue3-tauri2-os系统提供macos和windows11桌面风格、自研拖拽式栅格桌面引擎、封装tauri2多窗口管理、自定义json配置桌面/Dock菜单。

img

img

实现技术

  • 技术框架: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

img

img

tauri2.0-vue3os已经正式发布到我的原创作品集,感兴趣的可以去看看。

https://gf.bilibili.com/item/detail/1107621011

项目框架目录结构

使用最新版tauri2.0跨平台框架技术,整合vite6构建工具。
img

img

img

img

img

img

img

img

img

img

img

img

img

img

img

img

img

img

img

tauri2.0-vue3os布局模板

img

<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>

img

img

<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栅格布局

img

img

栅格桌面菜单支持如下参数配置:

/**  
 * label 图标标题  
 * imgico 图标(本地或网络图片) 支持Arco Design内置图标或自定义iconfont图标  
 * path 跳转路由页面  
 * link 跳转外部链接  
 * hideLabel 是否隐藏图标标题  
 * filter 是否禁用拖拽  
 * background 自定义图标背景色  
 * color 自定义图标颜色  
 * size 栅格磁贴布局 1x1 ... 12x12  
 * padding 内边距  
 * onClick 点击图标回调函数  
 * isNewin 新窗口打开路由页面  
 * children 二级菜单  
 */

支持children配置二级菜单。
img

img

img

tauri2.0+vue3自定义底部Dock菜单

img

Dock菜单配置参数:

/**  
 * label 图标tooltip提示  
 * imgico 图标(本地或网络图片) 支持Arco Design内置图标或自定义iconfont图标  
 * path 跳转路由页面  
 * link 跳转外部链接  
 * filter 是否禁用拖拽  
 * color 自定义图标颜色  
 * onClick 点击图标回调函数  
 * isNewin 新窗口打开路由页面  
 * children 二级菜单  
 */

另外系统托盘采用tauri2+vue3自定义弹窗实现系统托盘右键功能。
img

OK,综上就是Tauri2.0+Vue3+Arco实战桌面端os管理系统的一些知识分享。

作者:xiaoyan2017
链接: https://segmentfault.com/a/1190000045667190
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

继续阅读 »

经过了三周的爆肝研发,我的又一款原创跨平台重磅新作tauri2.1+vite6+vue3 setup+pinia2+arco.design桌面客户端OS管理系统Tauri2Vue3OS,正式宣告完结了。支持macoswindows两种桌面风格。

Tauri2.0-Vue3-MacOS桌面端os平台|tauri2+vite6.0+arco电脑版OS管理系统

img

img

vue3-tauri2-os系统提供macos和windows11桌面风格、自研拖拽式栅格桌面引擎、封装tauri2多窗口管理、自定义json配置桌面/Dock菜单。

img

img

实现技术

  • 技术框架: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

img

img

tauri2.0-vue3os已经正式发布到我的原创作品集,感兴趣的可以去看看。

https://gf.bilibili.com/item/detail/1107621011

项目框架目录结构

使用最新版tauri2.0跨平台框架技术,整合vite6构建工具。
img

img

img

img

img

img

img

img

img

img

img

img

img

img

img

img

img

img

img

tauri2.0-vue3os布局模板

img

<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>

img

img

<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栅格布局

img

img

栅格桌面菜单支持如下参数配置:

/**  
 * label 图标标题  
 * imgico 图标(本地或网络图片) 支持Arco Design内置图标或自定义iconfont图标  
 * path 跳转路由页面  
 * link 跳转外部链接  
 * hideLabel 是否隐藏图标标题  
 * filter 是否禁用拖拽  
 * background 自定义图标背景色  
 * color 自定义图标颜色  
 * size 栅格磁贴布局 1x1 ... 12x12  
 * padding 内边距  
 * onClick 点击图标回调函数  
 * isNewin 新窗口打开路由页面  
 * children 二级菜单  
 */

支持children配置二级菜单。
img

img

img

tauri2.0+vue3自定义底部Dock菜单

img

Dock菜单配置参数:

/**  
 * label 图标tooltip提示  
 * imgico 图标(本地或网络图片) 支持Arco Design内置图标或自定义iconfont图标  
 * path 跳转路由页面  
 * link 跳转外部链接  
 * filter 是否禁用拖拽  
 * color 自定义图标颜色  
 * onClick 点击图标回调函数  
 * isNewin 新窗口打开路由页面  
 * children 二级菜单  
 */

另外系统托盘采用tauri2+vue3自定义弹窗实现系统托盘右键功能。
img

OK,综上就是Tauri2.0+Vue3+Arco实战桌面端os管理系统的一些知识分享。

作者:xiaoyan2017
链接: https://segmentfault.com/a/1190000045667190
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

收起阅读 »

Android平台5+离线打包

离线打包

本教程一笔化整个离线打包,不列举其他选情况,主要解决官方文档一次看不懂,后续熟悉流程可自行根据官方文档修改自定义设置。参考链接如下:

  1. Andriod离线打包

开发环境及工具

软件的下载演示为MAC,Windows下载选择Windows环境即可。

HbuilderX与SDK版本需要要求一致,PS:有相关bug提出新SDK(4.36)会白屏。本次演示使用4.29版本

  1. android studio

  2. HBuilderX

  3. 离线SDK

使用新版以及后续SDK注意,新版由本次演示后的版本在注意事项中标明Andriod Studio相关环境使用时仔细阅读使用环境(后续下载SDK官方应该会修改环境),本次演示不包含该内容。

  1. 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配置想·

完成后点击运行

运行完成

继续阅读 »

本教程一笔化整个离线打包,不列举其他选情况,主要解决官方文档一次看不懂,后续熟悉流程可自行根据官方文档修改自定义设置。参考链接如下:

  1. Andriod离线打包

开发环境及工具

软件的下载演示为MAC,Windows下载选择Windows环境即可。

HbuilderX与SDK版本需要要求一致,PS:有相关bug提出新SDK(4.36)会白屏。本次演示使用4.29版本

  1. android studio

  2. HBuilderX

  3. 离线SDK

使用新版以及后续SDK注意,新版由本次演示后的版本在注意事项中标明Andriod Studio相关环境使用时仔细阅读使用环境(后续下载SDK官方应该会修改环境),本次演示不包含该内容。

  1. 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”的一种问题原因分享

uni-admin

当然,造成该问题的原因,最好还是看一下对应的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程序

img

img

使用技术

  • 开发工具: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

img

img

目前该项目Tauri2-Vue3Admin已经同步发布到我的原创作品集。

https://gf.bilibili.com/item/detail/1107226011

项目结构

img

img

img

img

tauri2-admin后台布局模板

img

<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>

img

img

img

img

img

img

img

img

img

img

img

img

img

img

img

img

img

tauri2-admin国际化配置

img

img

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实现自定义导航栏

img

<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自定义标签栏路由

img

img

<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>

img

tauri2+vue3实现自定义托盘右键菜单功能。

img

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程序

img

img

使用技术

  • 开发工具: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

img

img

目前该项目Tauri2-Vue3Admin已经同步发布到我的原创作品集。

https://gf.bilibili.com/item/detail/1107226011

项目结构

img

img

img

img

tauri2-admin后台布局模板

img

<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>

img

img

img

img

img

img

img

img

img

img

img

img

img

img

img

img

img

tauri2-admin国际化配置

img

img

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实现自定义导航栏

img

<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自定义标签栏路由

img

img

<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>

img

tauri2+vue3实现自定义托盘右键菜单功能。

img

End,以上就是tauri2+vue3+pinia2实战开发桌面版后台管理系统模板的一些知识分享。

作者:xiaoyan2017
链接: https://segmentfault.com/a/1190000045381943
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

收起阅读 »

vue3+tauri2.0+element-plus桌面端exe聊天模板|vite5+tauri2仿QQ/微信客户端程序

vue3

趁着国庆假期,我的又一款原创重磅新作Vue3.5+Tauri2.0+Vite5.4+Pinia2+ElementPlus跨平台实战仿QQ/微信电脑端聊天Exe程序Vue3Tauri2Chat,正式的完结了。整体UI采用全新无边框透明圆角阴影窗体

Vue3+Tauri2.0聊天实例|tauri2+vite5+element-plus仿微信|tauri聊天应用

img

img

封装tauri2.x多开窗口管理、换肤壁纸、自定义系统托盘闪烁/右键菜单功能。实现聊天、联系人、收藏、朋友圈、短视频、我的等页面模块。

img

img

运用技术

  • 编码工具: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

img

img

img

img

img

img

img

img

img

img

目前tauri2-vue3chat聊天项目已经发布到我的原创作品集,有需要的话可以去瞅瞅~
https://gf.bilibili.com/item/detail/1107133011

tauri2-vue3chat项目布局模板

img

img

<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>

img

img

img

tauri2多窗口实践

img

// 朋友圈窗口  
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多窗口|消息提醒|托盘闪烁

img

img

img

vue3+tauri2自定义透明圆角阴影窗体

img

.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);  
}

img

<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>

img

img

img

img

img

综上就是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聊天应用

img

img

封装tauri2.x多开窗口管理、换肤壁纸、自定义系统托盘闪烁/右键菜单功能。实现聊天、联系人、收藏、朋友圈、短视频、我的等页面模块。

img

img

运用技术

  • 编码工具: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

img

img

img

img

img

img

img

img

img

img

目前tauri2-vue3chat聊天项目已经发布到我的原创作品集,有需要的话可以去瞅瞅~
https://gf.bilibili.com/item/detail/1107133011

tauri2-vue3chat项目布局模板

img

img

<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>

img

img

img

tauri2多窗口实践

img

// 朋友圈窗口  
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多窗口|消息提醒|托盘闪烁

img

img

img

vue3+tauri2自定义透明圆角阴影窗体

img

.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);  
}

img

<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>

img

img

img

img

img

综上就是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管理系统

img

img

运用技术

  • 开发工具: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

img

img

基于electronjs封装高性能窗口多开器,采用自研栅格化拖拽布局引擎。

img

img

项目结构框架

electron32-winos基于vite.js整合最新跨平台技术electron32.x搭建项目模板。

img

img

目前electron32-vue3-os桌面os已经发布到我的原创作品集。
https://gf.bilibili.com/item/detail/1106958011

img

img

Electron主线程配置

img

/**  
 * 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')  
})

img

img

img

img

img

img

img

img

img

img

img

img

img

electron32-os桌面布局

img

<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>

img

<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>

img

img

img

img

img

img

electron32-os桌面栅格模板

img

img

桌面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 新窗口打开路由页面  
  */

img

img

桌面菜单示例代码

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管理系统

img

img

运用技术

  • 开发工具: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

img

img

基于electronjs封装高性能窗口多开器,采用自研栅格化拖拽布局引擎。

img

img

项目结构框架

electron32-winos基于vite.js整合最新跨平台技术electron32.x搭建项目模板。

img

img

目前electron32-vue3-os桌面os已经发布到我的原创作品集。
https://gf.bilibili.com/item/detail/1106958011

img

img

Electron主线程配置

img

/**  
 * 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')  
})

img

img

img

img

img

img

img

img

img

img

img

img

img

electron32-os桌面布局

img

<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>

img

<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>

img

img

img

img

img

img

electron32-os桌面栅格模板

img

img

桌面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 新窗口打开路由页面  
  */

img

img

桌面菜单示例代码

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桌面端后台管理系统

img

img

技术栈

  • 编辑器: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

img

img

img

功能性

1、最新前端技术栈Vite5.x、Vue3、Electron31、ElementPlus、Vue-I18n、Echarts
2、支持中英文/繁体国际化解决方案
3、支持动态权限路由、多页签缓存路由
4、封装多窗口管理器
5、内置4种通用布局模板、自由切换风格
6、整合通用的表格、表单、列表、图表、编辑器、错误处理等模块
7、高颜值UI界面、轻量级模块化、高定制性

img

项目结构

整个项目整合vite.js+electronjs跨平台技术,采用vue3 setup语法编码。

img

img

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()  
})

img

img

img

img

img

img

img

img

img

img

img

img

img

img

img

img

img

img

img

img

electron31-vue3-admin布局模板

img

img

/**  
 * 通用布局模板  
 * @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国际化配置

img

img

/**  
 * 国际化配置  
 * @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

img

img

/**  
 * 动态图表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桌面端后台管理系统

img

img

技术栈

  • 编辑器: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

img

img

img

功能性

1、最新前端技术栈Vite5.x、Vue3、Electron31、ElementPlus、Vue-I18n、Echarts
2、支持中英文/繁体国际化解决方案
3、支持动态权限路由、多页签缓存路由
4、封装多窗口管理器
5、内置4种通用布局模板、自由切换风格
6、整合通用的表格、表单、列表、图表、编辑器、错误处理等模块
7、高颜值UI界面、轻量级模块化、高定制性

img

项目结构

整个项目整合vite.js+electronjs跨平台技术,采用vue3 setup语法编码。

img

img

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()  
})

img

img

img

img

img

img

img

img

img

img

img

img

img

img

img

img

img

img

img

img

electron31-vue3-admin布局模板

img

img

/**  
 * 通用布局模板  
 * @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国际化配置

img

img

/**  
 * 国际化配置  
 * @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

img

img

/**  
 * 动态图表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]
收起阅读 »