小工具知识网

当前位置: 首页 > 行业知识 > 后台-vite中import.meta.glob的具体用法 与 动态路由和递归组件菜单栏

行业知识

后台-vite中import.meta.glob的具体用法 与 动态路由和递归组件菜单栏

2026-11-01 17:48:14 来源:互联网转载

��1.获取图标文件里的所有图标

​​{{ item }}
import { ref } from 'vue'import SvgIcon from '@/components/SvgIcon/index.vue'const icons = [] as string[]    //获取图标文件const modules = import.meta.glob('../../assets/icons/*.svg')for (const path in modules) {const p = path.split('assets/icons/')[1].split('.svg')[0]        //icons为图标文件名 数组icons.push(p)}const iconList = ref(icons)const iconName = ref('')const emit = defineEmits(['selected'])function filterIcons() {iconList.value = iconsif (iconName.value) {iconList.value = icons.filter((item) => item.indexOf(iconName.value) !== -1)}}function selectedIcon(name: string) {emit('selected', name)document.body.click()}function reset() {iconName.value = ''iconList.value = icons}defineExpose({reset,}).icon-select {width: 100%;padding: 10px;&__list {height: 200px;overflow-y: scroll;p {height: 30px;line-height: 30px;margin-bottom: -5px;cursor: pointer;width: 33%;float: left;}span {display: inline-block;vertical-align: -0.15em;fill: currentColor;overflow: hidden;}}}

modules

path.split('assets/icons/')

p 

2.动态路由

store/modules/permission.ts

import { PermissionState } from '@/types/store/permission'import { RouteRecordRaw } from 'vue-router'import { defineStore } from 'pinia'import { constantRoutes } from '@/router'import { listRoutes } from '@/api/system/menu'//获取view下所有的vue文件const modules = import.meta.glob('../../views/**/*.vue')export const Layout = () => import('@/layout/index.vue')// 递归拼接组成路由的componentexport const filterAsyncRoutes = (routes: RouteRecordRaw[], roles: string[]) => {const res: RouteRecordRaw[] = []routes.forEach((route) => {const tmp = { ...route } as any//if (hasPermission(roles, tmp)) {if (tmp.component == 'Layout') {tmp.component = Layout} else {const component = modules[`../../views/${tmp.component}.vue`] as anyif (component) {tmp.component = modules[`../../views/${tmp.component}.vue`]} else {tmp.component = modules[`../../views/error-page/404.vue`]}}tmp.name = tmp.pathres.push(tmp)if (tmp.children) {tmp.children = filterAsyncRoutes(tmp.children, roles)}}//})return res}const usePermissionStore = defineStore({id: 'permission',state: (): PermissionState => ({routes: [],addRoutes: [],}),actions: {setRoutes(routes: RouteRecordRaw[]) {this.addRoutes = routes// this.routes供左边菜单栏使用,constantRoutes为路由文件原有的登陆、首页等this.routes = constantRoutes.concat(routes)},generateRoutes(roles: string[]) {return new Promise((resolve, reject) => {listRoutes().then((response) => {// asyncRoutes:获取后端返回的路由const asyncRoutes = response.data//  accessedRoutes:拼接成功后想要的路由const accessedRoutes = filterAsyncRoutes(asyncRoutes, roles)this.setRoutes(accessedRoutes)resolve(accessedRoutes)}).catch((error) => {reject(error)})})},},})export default usePermissionStore

modules

 asyncRoutes:获取后端返回的路由

 accessedRoutes:拼接成功后想要的路由

router/index.ts

import { createRouter, createWebHashHistory, RouteRecordRaw } from 'vue-router';import useStore from '@/store';export const Layout = () => import('@/layout/index.vue');// 参数说明: https://panjiachen.github.io/vue-element-admin-site/guide/essentials/router-and-nav.html// 静态路由export const constantRoutes: Array = [  {    path: '/redirect',    component: Layout,    meta: { hidden: true },    children: [      {        path: '/redirect/:path(.*)',        component: () => import('@/views/redirect/index.vue')      }    ]  },  {    path: '/login',    component: () => import('@/views/login/index.vue'),    meta: { hidden: true }  },  {    path: '/404',    component: () => import('@/views/error-page/404.vue'),    meta: { hidden: true }  },  {    path: '/',    component: Layout,    redirect: '/dashboard',    children: [      {        path: 'dashboard',        component: () => import('@/views/dashboard/index.vue'),        name: 'Dashboard',        meta: { title: '首页', icon: 'homepage', affix: true }      },      {        path: '401',        component: () => import('@/views/error-page/401.vue'),        meta: { hidden: true }      },    ]  }  // 外部链接  /*{        path: '/external-link',        component: Layout,        children: [            {                path: 'https://www.cnblogs.com/haoxianrui/',                meta: { title: '外部链接', icon: 'link' }            }        ]    }*/  // 多级嵌套路由  /* {         path: '/nested',         component: Layout,         redirect: '/nested/level1/level2',         name: 'Nested',         meta: {title: '多级菜单', icon: 'nested'},         children: [             {                 path: 'level1',                 component: () => import('@/views/nested/level1/index.vue'),                 name: 'Level1',                 meta: {title: '菜单一级'},                 redirect: '/nested/level1/level2',                 children: [                     {                         path: 'level2',                         component: () => import('@/views/nested/level1/level2/index.vue'),                         name: 'Level2',                         meta: {title: '菜单二级'},                         redirect: '/nested/level1/level2/level3',                         children: [                             {                                 path: 'level3-1',                                 component: () => import('@/views/nested/level1/level2/level3/index1.vue'),                                 name: 'Level3-1',                                 meta: {title: '菜单三级-1'}                             },                             {                                 path: 'level3-2',                                 component: () => import('@/views/nested/level1/level2/level3/index2.vue'),                                 name: 'Level3-2',                                 meta: {title: '菜单三级-2'}                             }                         ]                     }                 ]             },         ]     }*/];// 创建路由const router = createRouter({  history: createWebHashHistory(),  routes: constantRoutes as RouteRecordRaw[],  // 刷新时,滚动条位置还原  scrollBehavior: () => ({ left: 0, top: 0 })});// 重置路由export function resetRouter() {  const { permission } = useStore();  permission.routes.forEach(route => {    const name = route.name;    if (name && router.hasRoute(name)) {      router.removeRoute(name);    }  });}export default router;

与App.vue同级 permission.ts

import router from '@/router'import useStore from '@/store'import NProgress from 'nprogress'import 'nprogress/nprogress.css'NProgress.configure({ showSpinner: false }) // 进度环显示/隐藏// 白名单路由const whiteList = ['/login']router.beforeEach(async (to, from, next) => {if (to.meta.title) {//判断是否有标题document.title = `智-admin-${to.meta.title}  `} else {document.title = `智-admin`}NProgress.start()const { user, permission } = useStore()const hasToken = user.tokenif (hasToken) {// 登录成功,跳转到首页if (to.path == '/login') {next({ path: '/' })NProgress.done()} else {const hasGetUserInfo = user.roles.length > 0// 第一步.hasGetUserInfo一开始为falseif (hasGetUserInfo) {if (to.matched.length == 0) {from.name ? next({ name: from.name as any }) : next('/401')} else {// 第四步next()}} else {try {// 第二步await user.getUserInfo()const roles = user.rolesconst accessRoutes: any = await permission.generateRoutes(roles)accessRoutes.forEach((route: any) => {router.addRoute(route)})// 第三步                    // 如果 addRoutes 并未完成,路由守卫会一层一层的执行执行,直到 addRoutes 完成,找到对应的路由next({ ...to, replace: true })} catch (error) {// 移除 token 并跳转登录页await user.resetToken()next(`/login?redirect=${to.path}`)NProgress.done()}}}} else {// 未登录可以访问白名单页面(登录页面)if (whiteList.indexOf(to.path) !== -1) {next()} else {next(`/login?redirect=${to.path}`)NProgress.done()}}})router.afterEach(() => {NProgress.done()})

最后在main.ts导入permission.ts

next({ ...to, replace: true }) 意思:VUE 路由守卫 next() / next({ ...to, replace: true }) / next(‘/‘) 说明_路由守卫next_anne都的博客-CSDN博客

3.动态递归组件侧边菜单栏

1.src/layout/components/sidebar/index.vue

import { computed } from 'vue'import { useRoute, useRouter } from 'vue-router'import SidebarItem from './SidebarItem.vue'import Logo from './Logo.vue'import variables from '@/styles/variables.module.scss'import useStore from '@/store'const { permission, setting, app } = useStore()const route = useRoute()const router = useRouter()const routes = computed(() => permission.routes)const showLogo = computed(() => setting.sidebarLogo)const isCollapse = computed(() => !app.sidebar.opened)const activeMenu = computed(() => {const { meta, path } = routeif (meta.activeMenu) {return meta.activeMenu as string}return path})// 默认选中第一个const handleOpen = (key: string, keyPath: string[]) => {router.push(key)}

routes

 

sidebarItem组件

{{ generateTitle(onlyOneChild.meta.title) }}{{ generateTitle(item.meta.title) }}import { ref } from 'vue'import path from 'path-browserify'import { isExternal } from '@/utils/validate'import AppLink from './Link.vue'import { generateTitle } from '@/utils/i18n'import SvgIcon from '@/components/SvgIcon/index.vue'const props = defineProps({item: {type: Object,required: true,},isNest: {type: Boolean,required: false,},basePath: {type: String,required: true,},})const onlyOneChild = ref()function hasOneShowingChild(children = [] as any, parent: any) {if (!children) {children = []}const showingChildren = children.filter((item: any) => {if (item.meta && item.meta.hidden) {return false} else {// 过滤出子元素onlyOneChild.value = itemreturn true}})// 当只有一个子路由,该子路由显示子菜单,没有用展开项if (showingChildren.length == 1) {return true}// 没有子路由则显示父路由if (showingChildren.length == 0) {onlyOneChild.value = { ...parent, path: '', noShowingChildren: true }return true}return false}// 解析路径function resolvePath(routePath: string) {// isExternal 判断是否为网址if (isExternal(routePath)) {return routePath}if (isExternal(props.basePath)) {return props.basePath}// path.resolve('/partner', '/business')  为 /partner/businessreturn path.resolve(props.basePath, routePath)}

appLink组件

                import { computed, defineComponent } from 'vue';import { isExternal } from '@/utils/validate';import { useRouter } from 'vue-router';import useStore from '@/store';const { app } = useStore();const sidebar = computed(() => app.sidebar);const device = computed(() => app.device);export default defineComponent({  props: {    to: {      type: String,      required: true    }  },  setup(props) {    const router = useRouter();    const push = () => {      if (device.value == 'mobile' && sidebar.value.opened == true) {        app.closeSideBar(false);      }      router.push(props.to).catch(err => {        console.log(err);      });    };    return {      push,      isExternal    };  }});

上一篇:揭秘网络凭据,安全输入与隐私保护攻略揭秘!

下一篇:Android12 AIDL native层实现