基於vite2+electron12後臺管理模板|Electron後臺框架系統

xiaoyan2017發表於2021-05-03

前一溜時間有給大家分享一個 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-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開發簡易後臺模板的一些分享,希望對大家有所幫助哈~~ ?

最後附上一個vue3+elementPlus網頁pc版聊天例項

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

 

相關文章