基于vite2+electron12后台管理模板|Electron后台框架系统
阅读原文时间:2021年05月04日阅读:1

前一溜时间有给大家分享一个 electron+vite跨端短视频 项目。这次分享的是vite2.xelectron实现跨平台后台框架,支持国际化多语言配置、导航菜单+树形菜单两种路由菜单模式、展开/收缩路由菜单等功能。

vite2-electron-system 后台模板框架使用到的版本:vite2.1.51、vue3.0.5、electron12.0.4

  • ### vite2.x|vue3-i18n国际化多语言

项目支持如下图3种语言切换[中文/英文/繁体],使用Vue I18n国际化vue3版本。

// 安装vue-i18n插件
npm i vue-i18n@next -D

在布局模板中新建locale多语言配置文件。

/**
* @desc 国际化语言配置(主模板)
*/

export default {
'layout__main-menu__home': '首页',
'layout__main-menu__home_dashboard': '控制台',
'layout__main-menu__home_breadcrumbs': '自定义面包屑导航',
'layout__main-menu__home_breadcrumbs-link': 'https://cn.vitejs.dev/',
'layout__main-menu__home_docs': '自定义链接',
'layout__main-menu__home_tree': '树形菜单',

'layout\_\_main-menu\_\_component': '组件',  
'layout\_\_main-menu\_\_component\_table': '表格',  
'layout\_\_main-menu\_\_component\_table-all': '所有表格',  
'layout\_\_main-menu\_\_component\_table-custom': '自定义表格',  
'layout\_\_main-menu\_\_component\_table-search': '表格搜索',  
'layout\_\_main-menu\_\_component\_table-search-list': '搜索列表',  
'layout\_\_main-menu\_\_component\_form': '表单',  
'layout\_\_main-menu\_\_component\_form-all': '所有表单',  
'layout\_\_main-menu\_\_component\_form-custom': '自定义表单',  
'layout\_\_main-menu\_\_component\_editor': '富文本编辑器',  

}

在plugins目录下新建一个i18n.js配置文件。

/**
* vue-i18n国际化配置文件
*/

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
}

export default i18n

然后在main.js中导入配置。

// 引入element-plus组件库
import ElPlus from 'element-plus'

// 引入多语言
import VueI18n, { ElPlusLang, getLang } from '@/plugins/i18n'

app.use(ElPlus, {
size: 'small',
locale: ElPlusLang[getLang()]
})
app.use(VueI18n)

 

  • ### vite2|vue3.0动态Hook设置标题

如下图:项目中页面路由跳转,动态化显示标题。

vue3 hook 就能快速实现动态切换,在hook目录新建一个useTitle.js文件。

/**
* 动态获取路由标题
*/

import { onMounted, watchEffect } from 'vue'
import { useI18n } from 'vue-i18n'

export default function useTitle(route) {
console.log(route)
if(!route.meta) return

const { t } = useI18n()  
const defaultTitle = 'ELECTRON-VUE3-VADMIN'

const Title = () => {  
    if(route.meta.title) {  
        document.title = \`${t(route.meta.title)} - ${defaultTitle}\`  
    }else {  
        document.title = defaultTitle  
    }  
}

watchEffect(Title)

onMounted(() => {  
    Title()  
})  

}

调用非常简单,通过如下方式即可快速实现路由地址切换标题。

import { useRoute } from 'vue-router'
import useTitle from '@/hooks/useTitle'

export default {
setup() {
const route = useRoute()

    // 设置title  
    useTitle(route)

    return {  
        // ...  
    }  
}  

}

  • ### vite2.x路由载等待效果

为了避免出现等待白屏的情况,可以在路由跳转的时候加入loading提示。

使用了element-plus的loading组件。

let loadingInstance
// 全局钩子拦截登录状态
router.beforeEach((to, from, next) => {

// 加载提示(避免白屏等待)  
// 可以使用NProgress组件:https://ricostacruz.com/nprogress/  
loadingInstance = ElLoading.service({  
    lock: true,  
    text: 'Loading',  
    spinner: 'el-icon-loading',  
    background: 'rgba(255, 255, 255, 0.7)'  
})

const hasLogined = store.state.isLogin

// 判断当前路由地址是否需要登录权限  
if(to.meta.auth) {  
    if(hasLogined) {  
        next()  
    }else {  
        // 跳转登录页面  
        loginWin()  
    }  
}else {  
    next()  
}  

})
router.afterEach(() => {
// 关闭加载提示
loadingInstance.close()
})

大家根据需要也可以选择一款非常小巧强大的NProgress插件实现加载效果。

https://ricostacruz.com/nprogress/

  • ### vite2+element-plus路由菜单

项目中使用了elementUI导航菜单 el-menu 和树形菜单 el-tree 两种实现路由地址菜单。


<el-tree
ref="treeRef"
:data="allRoutes"
:props="defaultProps"
@node-click="handleNodeSelect"
node-key="path"
:default-expanded-keys="[rootsRoute, defaultActive]"
:default-checked-keys="[defaultActive]"
highlight-current
show-checkbox
check-strictly

如何让el-tree树形菜单组件一次只能选中一个路由?开启  highlight-current  和  check-strictly  属性。

highlight-current:是否高亮当前选中节点,默认值是 false。
check-strictly:在显示复选框的情况下,是否严格的遵循父子不互相关联的做法,默认为 false

通过watchEffect监听路由地址变化动态更新选中节点。

// 选择节点
const handleNodeSelect = (data) => {
// console.log(data);
if(data.children) return

if(utils.checkExternal(data.path)) {  
    alert(data.path)  
}else {  
    treeRef.value.setCheckedKeys(\[data.path\], true)  
    router.push(data.path)  
}  

}

// 监听路由变化,设置选中节点
const routeChanged = async () => {
if(!treeRef.value) return
treeRef.value.setCheckedKeys([route.path], true)
}

watchEffect(routeChanged)

另外还需自定义选中行的颜色样式。

// 树形睬単el-tree样式
.indexlayout-treemenu {
border: 3px dashed #f90; padding: 10px;

// 选中行颜色  
.el-tree--highlight-current .el-tree-node.is-checked>.el-tree-node\_\_content {  
    background: $--color-primary; color: #fff;  
}  

}

另外附上自定义路由JSON文件。

/**
* @desc 主页面路由集合
* @author ANDY
* -----------------------------------------
* 路由参数说明:
* path: '/home' 链接
* redirect: '' 路径重定向
* meta: {
* auth: true 需要登录验证
* icon: 'home' 显示侧边栏图标(1、使用iconfont icon-xxx 2、使用饿了么el-icon-xxx)
* title: '标题' 名称(显示在侧边栏/面包屑/浏览器title)
* breadcrumb: [ 面包屑导航
* {
* title: '标题' 标题
* path: '/demo' 链接
* }
* ]
* activeRoute: '/home/dashboard' 侧边栏链接选中,默认route.path
* rootsRoute: '/home' 所属顶部链接选中
* }
*/

import emptyLayout from '@/layouts/empty.vue'

const mainRoutes = [
// 首页模块
{
path: '/home',
redirect: '/home/dashboard',
component: emptyLayout,
meta: {
auth: true, //是否登录验证
icon: 'icon-ding',
title: 'layout__main-menu__home',
hidden: false, //隐藏菜单项
},
children: [
{
path: 'dashboard',
component: () => import('@/views/dashboard.vue'),
meta: {
auth: true,
icon: 'icon-haoyou',
title: 'layout__main-menu__home_dashboard'
}
},
{
path: 'breadcrumbs',
component: () => import('@/views/breadcrumbs/index.vue'),
meta: {
auth: true,
icon: 'icon-down',
title: 'layout__main-menu__home_breadcrumbs',
// 自定义面包屑
breadcrumb: [
{
title: 'layout__main-menu__home_breadcrumbs',
path: '/home/breadcrumbs'
},
{
title: 'layout__main-menu__home',
path: '/home'
},
{
title: 'layout__main-menu__home_breadcrumbs-link',
path: 'https://cn.vitejs.dev/'
}
]
}
},
{
path: 'https://cn.vitejs.dev/',
meta: {
// auth: true,
icon: 'icon-go',
title: 'layout__main-menu__home_docs',
rootsRoute: '/home'
}
},
{
path: 'tree',
component: () => import('@/views/component/tree/index.vue'),
meta: {
auth: true,
icon: 'el-icon-s-data',
title: 'layout__main-menu__home_tree'
},
},
]
},

// 组件模块  
{  
    path: '/component',  
    redirect: '/component/table/allTable',  
    component: emptyLayout,  
    meta: {  
        auth: true, //是否登录验证  
        icon: 'el-icon-s-operation',  
        title: 'layout\_\_main-menu\_\_component',  
        hidden: false, //隐藏菜单项  
    },  
    children: \[  
        {  
            path: 'table',  
            redirect: '/component/table/allTable',  
            component: emptyLayout,  
            meta: {  
                auth: true,  
                icon: 'el-icon-s-grid',  
                title: 'layout\_\_main-menu\_\_component\_table'  
            },  
            children: \[  
                {  
                    path: 'allTable',  
                    component: () => import('@/views/component/table/all.vue'),  
                    meta: {  
                        title: 'layout\_\_main-menu\_\_component\_table-all'  
                    }  
                },  
                {  
                    path: 'customTable',  
                    component: () => import('@/views/component/table/custom.vue'),  
                    meta: {  
                        title: 'layout\_\_main-menu\_\_component\_table-custom'  
                    }  
                },  
                {  
                    path: 'search',  
                    redirect: '/component/table/search/searchlist',  
                    component: emptyLayout,  
                    meta: {  
                        title: 'layout\_\_main-menu\_\_component\_table-search'  
                    },  
                    children: \[  
                        {  
                            path: 'searchlist',  
                            component: () => import('@/views/component/table/search.vue'),  
                            meta: {  
                                title: 'layout\_\_main-menu\_\_component\_table-search-list'  
                            }  
                        }  
                    \]  
                }  
            \]  
        },  
        {  
            path: 'form',  
            redirect: '/component/form/allForm',  
            component: emptyLayout,  
            meta: {  
                auth: true,  
                icon: 'el-icon-cpu',  
                title: 'layout\_\_main-menu\_\_component\_form'  
            },  
            children: \[  
                {  
                    path: 'allForm',  
                    component: () => import('@/views/component/form/all.vue'),  
                    meta: {  
                        title: 'layout\_\_main-menu\_\_component\_form-all'  
                    }  
                },  
                {  
                    path: 'customForm',  
                    component: () => import('@/views/component/form/custom.vue'),  
                    meta: {  
                        title: 'layout\_\_main-menu\_\_component\_form-custom'  
                    }  
                }  
            \]  
        },  
        {  
            path: 'editor',  
            component: () => import('@/views/component/editor/index.vue'),  
            meta: {  
                auth: true,  
                icon: 'el-icon-cpu',  
                title: 'layout\_\_main-menu\_\_component\_editor'  
            },  
        },  
    \]  
},

// 更多路由配置...  

]

export default mainRoutes

OK,以上就是基于vite2和electron开发简易后台模板的一些分享,希望对大家有所帮助哈~~

最后附上一个vue3+elementPlus网页pc版聊天实例

https://www.cnblogs.com/xiaoyan2017/p/14307849.html