前一溜时间有给大家分享一个 electron+vite跨端短视频 项目。这次分享的是vite2.x和electron实现跨平台后台框架,支持国际化多语言配置、导航菜单+树形菜单两种路由菜单模式、展开/收缩路由菜单等功能。
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-menu导航菜单路由 --> <div> <el-menu :default-active="defaultActive" :collapse="collapsed" :collapse-transition="false" class="mainLayout__menuNav" @select="handleNodeSelect" > <sidebar-item v-for="route in allRoutes" :key="route.path" :item="route" :isNavEnable="isNavEnable" :rootsRoute="rootsRoute" /> </el-menu> </div> <!-- 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>
如何让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开发简易后台模板的一些分享,希望对大家有所帮助哈~~