一、项目概述
基于vite.js、vue3、electron
开发后台管理框架系统ElectronVueAdmin。内置 i18n
国际化解决方案,动态权限路由,权限验证,整合了典型的表格/表单等业务模块功能。
二、运用技术
- 编辑器:vscode
- vue3技术:vitejs+vue3.0+vuex4+vue-router@4
- 跨端框架:electron^12.0.4
- UI组件库:element-plus^1.0.2 (饿了么vue3组件库)
- 表格拖拽:sortablejs^1.13.0
- 图表组件:echarts^5.1.1
- 国际化:vue-i18n^9.1.6
- 模拟请求:mockjs^1.1.0
- 打包工具:vue-cli-plugin-electron-builder
三、特性
- 支持响应式适配桌面端和平板端
- 最新前端技术Vite2、Vue3、Electron12、Element Plus、Vue-i18n、Echarts5.x
- 支持组件式/指令式权限认证方式
- 支持中英文/繁体国际化方案
- 支持表格拖拽排序、树形表格等功能
- 支持多主题换肤切换
四、项目目录结构
五、一览效果
vue3桌面端组件库
项目中使用的UI组件库是饿了么推出的vue3 pc端组件库element-plus
大家如果感兴趣可以去看看,在vue3版本中已经列出了el-scrollbar滚动条组件。
主入口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') | |
}) |
引入公共组件配置
在根目录新建一个plugins.js用来配置一些公共组件。
/** | |
* 公共组件/插件配置文件 | |
* @author XiaoYan | |
*/ | |
// 引入公共样式 | |
import "@/assets/fonts/iconfont.css" | |
import "@/assets/css/common.scss" | |
// 引入elementPlus组件库 | |
import ELPlus from "element-plus" | |
// 引入国际化配置 | |
import VueI18n, { elPlusLang, getLang } from './i18n' | |
// 引入vue3自定义组件 | |
import V3Layer from '@/components/v3layer' | |
import V3Scroll from '@/components/v3scroll' | |
// 引入公共组件模板 | |
import WinBar from '@/components/winbar' | |
import WinBtn from '@/components/winbar/winbtn.vue' | |
import MacBtn from '@/components/winbar/macbtn.vue' | |
import Icon from '@/components/Icon' | |
import Utils from '@/utils' | |
import ElUtil from './elUtil' | |
const gPlugins = (app) => { | |
app.use(ELPlus, { | |
size: 'small', | |
locale: elPlusLang[getLang()]}) | |
app.use(VueI18n) | |
app.use(V3Layer) | |
app.use(V3Scroll) | |
// 注册公共组件 | |
app.component('WinBar', WinBar) | |
app.component('WinBtn', WinBtn) | |
app.component('MacBtn', MacBtn) | |
app.component('Icon', Icon) | |
// 注入全局依赖 | |
app.provide('utils', Utils) | |
app.provide('elUtil', ElUtil) | |
} |
Electron无边框导航栏
项目顶部导航栏类似Mac效果,通过css3渐变即可实现。
<template><WinBar zIndex="1000"><template #wbtn><MsgMenu /><Lang /><a class="wbtn" title="换肤" @click="handleSkinWin"><i class="iconfont icon-huanfu"></i></a><Setting /><a class="wbtn" title="刷新" @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
来处理国际化解决方案。目前支持中文、英文及繁体三种语言。
/** | |
* 国际化配置 VueI18n util | |
* @author XiaoYan Q:282310962 | |
*/ | |
import { createI18n } from "vue-i18n" | |
import Storage from "@/utils/storage" | |
// 默认值 | |
export const langKey = 'lang' | |
export const langVal = 'zh-CN' | |
/* elementPlus国际化配置 */ | |
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 = importAllLang() | |
export const $lang = getLang() | |
const i18n = createI18n({ | |
legacy: false, | |
locale: $lang, | |
messages: $messages | |
}) | |
/* 获取语言 */ | |
export function getLang() {const lang = Storage.get(langKey)return lang || langVal | |
} | |
/** | |
* 持久化存储 | |
* @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()}} | |
} | |
/** | |
* 自动化导入本地locale目录下语言配置 | |
*/ | |
export function importAllLang() {const langModule = {}try {const localeCtx = require.context('@/locale', true, /([a-z]{2})-?([A-Z]{2})?\.js$/) | |
localeCtx.keys().map(path => {const pathCtx = localeCtx(path)if(pathCtx.default) {const pathName = path.replace(/(.*\/)*([^.]+).*/ig, '$2')if(langModule[pathName]) { | |
langModule[pathName] = {...langModule[pathName], ...pathCtx.default}}else { | |
langModule[pathName] = pathCtx.default}}})} catch (error) { | |
console.log(error)}return langModule | |
} |
项目布局模板
项目分为Auth和Main两个布局模板,auth模板是处理一些登录、注册页面。main模板则是处理页面组件功能。
auth模板
<template><div class="vadmin__wrapper"><router-view class="vadmin__layouts-auth"></router-view></div> | |
</template> | |
<script> | |
import { useRoute } from "vue-router" | |
import useTitle from '@/hooks/useTitle' | |
export default { | |
components: {},setup() {const route = useRoute() | |
// 设置标题useTitle(route)} | |
} | |
</script> |
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 Echarts图表hook
项目中多个地方使用到图表,于是封装一个图表hook。
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 | |
} | |
erd.listenTo(refs.value, handleResize)}) | |
onBeforeUnmount(() => { | |
chartInst.dispose() | |
erd.removeListener(refs.value, handleResize)}) | |
return chartRef | |
} |
Okey,使用vite+electron+element-plus开发后台系统就先分享到这里。后续还会陆续分享一些实例项目。
Electron高仿抖音短视频|vue3+electron桌面端直播/小视频