上次有给大家分享一个Electron跨端仿抖音短视频项目,这次带来最新研发的vite.js+electron开发vue3中后台管理系统。
vite2-vue3-electronAdmin:一套基于electron+vite.js和element-plus组件库开发的客户端后台管理系统EXE。使用了最新的vue3全家桶技术,内置了 Vue-i18n 国际化解决方案,支持PC桌面端和平板自适应布局。
electron12 vite2.x仿制抖音短视频|直播聊天
基于最新的前端技术栈vite2+vue3全家桶+electron12+element-plus+echarts5开发而来。
技术栈
- 编码器:VScode
- 构建工具:Vitejs
- vue3全家桶:Vue3.0+Vuex4+Vue-router@4
- 跨端框架:Electron^12.0.4
- 打包工具:vue-cli-plugin-electron-builder
- UI组件库:element-plus^1.0.2 (饿了么vue3组件库)
- 表格拖拽:Sortablejs^1.13
- 图表组件:Echarts^5.1
- 国际化:vue-i18n^9.1
- 模拟请求:mockjs^1.1
特性
- 使用最新前端技术栈开发
- 支持桌面端及平板响应式布局
- 支持组件式+指令式两种权限认证方式
- 支持中英文/繁体国际化方案
- 支持表格拖拽排序、全屏表格、树形表格等功能
- 支持个性化换肤
项目结构
main.js配置
/**
* 渲染进程主入口
* @author XiaoYan
*/
import { createApp } from 'vue'
import App from './App.vue'
import Router from './router'
import Store from './store'
// 引入公共配置
import gPlugins from './plugins'
import { winCfg, loadWin } from './windows/actions'
loadWin().then(config => {
winCfg.window = config
createApp(App)
.use(Router)
.use(Store)
.use(gPlugins)
.mount('#app')
})
vue-router路由配置
项目中的路由采用了结构化分层加载,分为验证路由authRoutes.js和主模块路由mainRoutes.js两大部分。
/**
* 路由配置 Router util
* @author XiaoYan
*/
import { createRouter, createWebHashHistory } from "vue-router"
import { ElLoading } from "element-plus"
import { loginWin } from "@/windows/actions"
import store from '@/store'
// 导入公共模板/路由配置
import mainLayout from "@/layouts/main"
import authLayout from "@/layouts/auth"
import mainRoutes from "@/layouts/main/routes.js"
import authRoutes from "@/layouts/auth/routes.js"
const RoutesLs = [
// 主页面模块
{
path: '/',
redirect: '/home/index',
component: mainLayout,
children: mainRoutes,
},
// 验证模块
{
path: '/auth',
redirect: '/auth/login',
component: authLayout,
children: authRoutes,
},
// 错误模块
{
path: '/:pathMatch(.*)*',
component: () => import('@/views/error/404.vue'),
meta: {
title: 'app__global-page-notfound',
}
}
]
const router = createRouter({
history: createWebHashHistory(),
routes: RoutesLs,
})
let loadingIns
router.beforeEach((to, from, next) => {
// 开启加载提示
loadingIns = ElLoading.service({
lock: true,
text: 'Loading...',
spinner: 'el-icon-loading',
background: 'rgba(19, 209, 122, .1)'
})
// 判断当前路由状态
const isLogined = store.state.isLogin
if(to.meta.auth) {
if(isLogined) {
next()
}else {
loginWin()
loadingIns.close()
}
}else {
next()
}
})
router.afterEach(() => {
loadingIns.close()
})
electron-vue3自定义仿Mac导航栏
项目中顶部导航条采用的是mac导航条风格,关闭/最小化/最大化按钮在左侧。
<!-- //仿Mac导航条 -->
<template>
<WinBar zIndex="1000">
<template #wbtn>
<MsgMenu />
<Lang />
<a class="wbtn" @click="handleSkinWin"><i class="iconfont icon-huanfu"></i></a>
<Setting />
<a class="wbtn" @click="handleRefresh"><i class="iconfont el-icon-refresh"></i></a>
<a class="wbtn" :class="{'on': isAlwaysOnTop}" :title="isAlwaysOnTop ? '取消置顶' : '置顶'" @click="handleAlwaysTop"><i class="iconfont icon-ding"></i></a>
<Avatar @logout="handleLogout" />
</template>
</WinBar>
</template>
vue-i18n国际化方案
新建一个locale目录用来存放项目中语言文件。
/**
* @desc vue-i18n国际化配置文件
* @Time andy by 2021-05
* @Author Q:282310962 wx:xy190310
*/
import { createI18n } from 'vue-i18n'
import Storage from '@/utils/storage'
// 默认设置
export const langKey = 'lang'
export const langVal = 'zh-CN'
/**
* 引入element-plus国际化包
*/
import enUS from 'element-plus/lib/locale/lang/en'
import zhCN from 'element-plus/lib/locale/lang/zh-cn'
import zhTW from 'element-plus/lib/locale/lang/zh-tw'
export const ElPlusLang = {
'en-US': enUS,
'zh-CN': zhCN,
'zh-TW': zhTW
}
/**
* 初始化多语言
*/
export const $messages = importLang()
export const $lang = getLang()
const i18n = createI18n({
legacy: false,
locale: $lang,
messages: $messages
})
/**
* 自动导入语言配置
*/
export function importLang() {
const localeModule = {}
try {
// 导入 @/layouts 文件夹下包含子目录locale中的xxx.js文件
const layoutsCtx = require.context('@/layouts', true, /[/\\]locale[/\\]([a-z]{2})-?([A-Z]{2})?\.js$/)
layoutsCtx.keys().map(path => {
const pathCtx = layoutsCtx(path)
if(pathCtx.default) {
const pathName = path.replace(/(.*\/)*([^.]+).*/ig, '$2')
if(localeModule[pathName]) {
localeModule[pathName] = {
...localeModule[pathName], ...pathCtx.default
}
}else {
localeModule[pathName] = pathCtx.default
}
}
})
} catch (error) {
console.log(error)
}
return localeModule
}
/**
* 存储设置语言
* @param lang 语言类型 zh-CN | zh-TW | en-US
*/
export function setLang(lang, reload = false) {
if(getLang() !== lang) {
Storage.set(langKey, lang || '')
// 设置全局语言
i18n.global.locale.value = lang
if(reload) {
window.location.reload()
}
}
}
/**
* 获取语言
*/
export function getLang() {
const lang = Storage.get(langKey)
return lang || langVal
}
vite2+electron主模板布局
项目整体分为顶部导航条、侧边栏、路由菜单、右侧上面包屑导航、右侧下主体内容。
<!-- //Main主模块模板 -->
<template>
<div class="vadmin__wrapper" :style="{'--themeSkin': store.state.skin}">
<div v-if="!route.meta.isNewin" class="vadmin__layouts-main flexbox flex-col">
<!-- //顶部导航 -->
<div class="layout__topbar">
<TopNav />
</div>
<div class="layout__workpanel flex1 flexbox">
<!-- //侧边栏 -->
<div v-show="rootRouteEnable" class="panel__leftlayer">
<SideMenu :routes="mainRoutes" :rootRoute="rootRoute" />
</div>
<!-- //中间栏 -->
<div class="panel__middlelayer" :class="{'collapsed': collapsed}">
<RouteMenu
:routes="getAllRoutes"
:rootRoute="rootRoute"
:defaultActive="defaultActive"
:rootRouteEnable="rootRouteEnable"
/>
</div>
<!-- //右边栏 -->
<div class="panel__rightlayer flex1 flexbox flex-col">
<!-- 面包屑导航 -->
<BreadCrumb />
<!-- 主内容区 -->
<v3-scroll autohide>
<div class="lay__container">
<!-- //路由权限控制 -->
<permission :roles="route.meta.roles">
<template #tooltips>
<Forbidden />
</template>
<router-view></router-view>
</permission>
</div>
</v3-scroll>
</div>
</div>
</div>
<router-view v-else class="vadmin__layouts-main flexbox flex-col"></router-view>
</div>
</template>
Vue3图表化Hook
项目中多个地方需要使用到图表功能,于是就封装了一个图表hook函数。
/**
* 封装图表Hook
* @author XiaoYan
*/
import { onMounted, onBeforeUnmount, ref } from "vue"
import * as echarts from "echarts"
import elementResizeDetectorMaker from "element-resize-detector"
import utils from "@/utils"
export default function useChart(refs, options) {
let chartInst
let chartRef = ref(null)
let erd = elementResizeDetectorMaker()
const handleResize = utils.debounce(() => {
chartInst.resize()
}, 100)
onMounted(() => {
if(refs.value) {
chartInst = echarts.init(refs.value)
chartInst.setOption(options)
chartRef.value = chartInst
}
// window.addEventListener('resize', handleResize)
erd.listenTo(refs.value, handleResize)
})
onBeforeUnmount(() => {
chartInst.dispose()
// window.removeEventListener('resize', handleResize)
erd.removeListener(refs.value, handleResize)
})
return chartRef
}
Okay,基于vite.js+vue3+electron开发管理后台就分享到这里。希望对小伙伴们有些帮助!
链接:https://juejin.cn/post/6963310387945013261/
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
2 个评论
要回复文章请先登录或注册
x***@126.com (作者)
x***@126.com (作者)