前段時間小穎在B站找了個學習vue3+TS的視訊,自己嘗試著搭建了一些基礎程式碼,在實現功能的過程中遇到了一些問題,為了防止自己遺忘,寫個隨筆記錄一下嘻嘻
git地址:vue3.x-ts-element-plus--demo
起因是小穎在封裝 axios 時,發現引入的 ElNotification 元件沒有樣式,表單提交時載入 ElLoading 元件有沒有樣式,後來通過面向百度解決了該問題,嘻嘻
第一步:執行下面程式碼
npm i unplugin-element-plus -D
第二步:在 vue.config.js 改為
直接全域性引入 element-plus
第一步:修改 main.ts
參考:記錄-解決element-plus自動引入後ElLoading、ElMessage、ElNotification、ElMessageBox樣式丟失的問題
起因是小穎在封裝選單元件時,要動態遍歷選單資料根據資料中的 icon 值,通過:
<component :is="menuInfo.icon" class="menu-icon" />
動態渲染各自的選單圖示,但是沒有渲染出來,通過F12發現渲染出來的dom就不是圖示元件的dom,而是這樣的:
當前 menuInfo.icon 值為:setting
因考慮到選單可能不止兩級可能會是多級的所以小穎將其封裝成以下元件:
<template> <div class="logo-box">XXXX管理系統</div> <div class="menu-box"> <el-menu active-text-color="#ffd04b" background-color="#545c64" class="el-menu-vertical" :default-active="menuActive" :unique-opened="true" text-color="#fff" @open="handleOpen" @close="handleClose" > <template v-for="menu in menuList" :key="menu.id"> <subMenu :menuInfo="menu" /> </template> </el-menu> </div> </template> <script lang="ts" setup> import { defineProps, computed } from "vue"; import { useStore } from "vuex"; import SubMenu from "./subMenu.vue"; const store = useStore(); const props = defineProps({ menuList: { type: Array, default: () => [], }, }); const menuActive = computed(() => { return store.state.setting.menuActive; }); const handleOpen = (key: string, keyPath: string[]) => { console.log(key, keyPath); }; const handleClose = (key: string, keyPath: string[]) => { console.log(key, keyPath); }; </script> <style lang="scss" scoped> .logo-box { height: 80px; display: flex; justify-content: center; align-items: center; font-size: 20px; cursor: pointer; background-color: #545c64; color: #fff; // background: v-bind(themeBackground); } .menu-box { height: calc(100vh - 80px); background-color: #545c64; } .el-menu-vertical { border-right: none; } .el-menu-vertical:not(.menu--collapse) { min-height: 400px; } </style>
<template> <el-sub-menu v-if="menuInfo.childs.length > 0" :index="menuInfo.id"> <template #title> <el-icon :size="18"> <component :is="menuInfo.icon" /> </el-icon> <span>{{ menuInfo.m_name }}</span> </template> <template v-for="item in menuInfo.childs" :key="item.id"> <sub-menu :menu-info="item" /> </template> </el-sub-menu> <el-menu-item v-else :index="menuInfo.id" @click="menuFun(menuInfo, menuInfo.id)" > <el-icon :size="18"> <component :is="menuInfo.icon" class="menu-icon" /> </el-icon> <span>{{ menuInfo.m_name }}</span> </el-menu-item> </template> <script lang="ts" name="SubMenu" setup> import { Document, Menu as IconMenu, Location, Setting, Menu, Grid, } from "@element-plus/icons-vue"; import { defineProps } from "vue"; import { useRouter } from "vue-router"; import { useStore } from "vuex"; //路由 const router = useRouter(); //vuex const store = useStore(); const props = defineProps({ menuInfo: { type: Object, default: () => { return { id: "", parent_id: "", m_name: "", icon: "", childs: [], }; }, }, }); const menuFun = (event: any, index: string) => { setNav(event); store.dispatch("setMenuActive", { menuActive: index }); if (event.url && event.url.length > 0) { router.push({ path: event.url, query: {}, }); } }; const setNav = (item: any) => { store.dispatch("setNav", { nav: item }); }; </script>
修改 main.ts
import { createApp } from 'vue' import App from './App.vue' import router from './router' import store from './store' import ElementPlus from 'element-plus' import 'element-plus/es/components/button/style/css' import * as Icons from '@element-plus/icons-vue' const app = createApp(App) Object.keys(Icons).forEach(key => { app.component(key, Icons[key as keyof typeof Icons]) }) app.use(store) app.use(router) app.use(ElementPlus) app.mount('#app')
將 main.ts 改回原來的
import { createApp } from 'vue' import App from './App.vue' import router from './router' import store from './store' createApp(App).use(store).use(router).mount('#app') //公共css import './assets/css/index.scss'
將subMenu.vue元件的 js 程式碼改為
import { defineComponent } from "vue"; import { Document, Menu as IconMenu, Location, Setting, Menu, Grid, } from "@element-plus/icons-vue"; import { useRouter } from "vue-router"; import { useStore } from "vuex"; export default defineComponent({ components: { Document, Menu, Location, Setting, Grid, }, props: { menuInfo: { type: Object, default: () => { return { id: "", parent_id: "", m_name: "", icon: "", childs: [], }; }, }, }, setup() { //路由 const router = useRouter(); //vuex const store = useStore(); const menuFun = (event: any, index: string) => { setNav(event); store.dispatch("setMenuActive", { menuActive: index }); if (event.url && event.url.length > 0) { router.push({ path: event.url, query: {}, }); } }; const setNav = (item: any) => { store.dispatch("setNav", { nav: item }); }; return { menuFun, }; }, }); </script>
參考哪裡忘記了,第一種是面向百度的,第二種是小穎自己試出來的
來來來找到了,參考這裡;vue3 動態載入el-icon圖示
第一步:執行以下程式碼
npm install --save vuex-persist
第二步:在 store 下的 index.ts 中引入並使用
import VuexPersistence from "vuex-persist";//解決頁面重新整理vuex資料丟失 const vuexLocal = new VuexPersistence({ storage: window.localStorage }) export default createStore({ state: { }, getters: { }, mutations: { }, actions: { }, modules: modules, plugins: [vuexLocal.plugin] })
更多方法參考:vuex頁面重新整理資料丟失問題的四種解決方式
比如小穎要實現在 store 下的 index.ts 中自動引入 store 下的 modules 中的所有 ts
將 index.ts 改為:
import { createStore } from 'vuex' import VuexPersistence from "vuex-persist";//解決頁面重新整理vuex資料丟失 const modulesFiles = require.context('./modules', false, /\.ts$/) // you do not need `import app from './modules/app'` // it will auto require all vuex module from modules file const modules = modulesFiles.keys().reduce((modules: any, modulePath) => { // set './app.js' => 'app' const moduleName = modulePath.replace(/^\.\/(.*)\.\w+$/, '$1') const value = modulesFiles(modulePath) modules[moduleName] = value.default return modules }, {}) const vuexLocal = new VuexPersistence({ storage: window.localStorage }) export default createStore({ state: { }, getters: { }, mutations: { }, actions: { }, modules: modules, plugins: [vuexLocal.plugin] })
後面的坑等後面寫了再繼續補充,最近小穎在忙著弄接的私活所以也沒繼續看vue3了,等這段時間忙完繼續搞,