x***@126.com
x***@126.com
  • 发布:2021-05-19 18:22
  • 更新:2021-05-19 18:22
  • 阅读:4615

vite.js+vue3+electron12.0.4超清爽UI界面前端中后台管理系统

分类:HTML5+

上次有给大家分享一个Electron跨端仿抖音短视频项目,这次带来最新研发的vite.js+electron开发vue3中后台管理系统。

vite2-vue3-electronAdmin:一套基于electron+vite.js和element-plus组件库开发的客户端后台管理系统EXE。使用了最新的vue3全家桶技术,内置了 Vue-i18n 国际化解决方案,支持PC桌面端和平板自适应布局。

electron12 vite2.x仿制抖音短视频|直播聊天

img

基于最新的前端技术栈vite2+vue3全家桶+electron12+element-plus+echarts5开发而来。

img

技术栈

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

img

特性

  • 使用最新前端技术栈开发
  • 支持桌面端及平板响应式布局
  • 支持组件式+指令式两种权限认证方式
  • 支持中英文/繁体国际化方案
  • 支持表格拖拽排序、全屏表格、树形表格等功能
  • 支持个性化换肤

img

项目结构

img

img

img

img

img

img

img

img

img

img

img

img

img

img

img

img

img

img

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导航条风格,关闭/最小化/最大化按钮在左侧。
img

<!-- //仿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国际化方案

img

新建一个locale目录用来存放项目中语言文件。

img

/**  
 * @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开发管理后台就分享到这里。希望对小伙伴们有些帮助!

img

链接:https://juejin.cn/post/6963310387945013261/
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

0 关注 分享

要回复文章请先登录注册