玖叶教程网

前端编程开发入门

接口动态生成路由表怎么关联组件(接口动态生成路由表怎么关联组件设置)

在前后端分离中,当权限是由后端接口动态生成的时候,此时我们需要将后端配置的页面组件与前端的页面做一个关联。

我们看下通常后端返回的数据结构格式:

{
  "code": 0,
  "result": [
    {
      "path": "/dashboard",
      "name": "Dashboard",
      "component": "LAYOUT",
      "redirect": "/dashboard/analysis",
      "meta": {
        "title": "routes.dashboard.dashboard",
        "hideChildrenInMenu": true,
        "icon": "bx:bx-home"
      },
      "children": [
        {
          "path": "analysis",
          "name": "Analysis",
          "component": "/dashboard/analysis/index",
          "meta": {
            "hideMenu": true,
            "hideBreadcrumb": true,
            "title": "routes.dashboard.analysis",
            "currentActiveMenu": "/dashboard",
            "icon": "bx:bx-home"
          }
        },
        {
          "path": "workbench",
          "name": "Workbench",
          "component": "/dashboard/workbench/index",
          "meta": {
            "hideMenu": true,
            "hideBreadcrumb": true,
            "title": "routes.dashboard.workbench",
            "currentActiveMenu": "/dashboard",
            "icon": "bx:bx-home"
          }
        }
      ]
    },
    {
      "path": "/system",
      "name": "System",
      "component": "LAYOUT",
      "redirect": "/system/account",
      "meta": {
        "icon": "ion:settings-outline",
        "title": "routes.demo.system.moduleName"
      },
      "children": [
        {
          "path": "account",
          "name": "AccountManagement",
          "meta": {
            "title": "routes.demo.system.account",
            "ignoreKeepAlive": true
          },
          "component": "/demo/system/account/index"
        },
        {
          "path": "account_detail/:id",
          "name": "AccountDetail",
          "meta": {
            "hideMenu": true,
            "title": "routes.demo.system.account_detail",
            "ignoreKeepAlive": true,
            "showMenu": false,
            "currentActiveMenu": "/system/account"
          },
          "component": "/demo/system/account/AccountDetail"
        },
        {
          "path": "role",
          "name": "RoleManagement",
          "meta": {
            "title": "routes.demo.system.role",
            "ignoreKeepAlive": true
          },
          "component": "/demo/system/role/index"
        },
        {
          "path": "dept",
          "name": "DeptManagement",
          "meta": {
            "title": "routes.demo.system.dept",
            "ignoreKeepAlive": true
          },
          "component": "/demo/system/dept/index"
        },
        {
          "path": "changePassword",
          "name": "ChangePassword",
          "meta": {
            "title": "routes.demo.system.password",
            "ignoreKeepAlive": true
          },
          "component": "/demo/system/password/index"
        }
      ]
    }
  ],
  "message": "ok",
  "type": "success"
}

result是可被访问的菜单,其中component属性就是对应的页面组件。我们可以看到component的值为一个字符串路径,这个在vue-router中是不能正确解析出组件的,因为它仅仅是一个字符串。

在vue-router中,我们可以使用component: () => import('/@/views/sys/login/Login.vue')动态导入组件,以后端返回的菜单为例,当"component"的值对应的是"/demo/system/role/index"字符串时,他对应的组件就应该通过() => import('/@/views/demo/system/role/index.vue)导入。

() => import('/@/views/demo/system/role/index.vue) 是一种动态导入组件的方式,它结合了箭头函数和 import() 方法。

具体而言,这段代码表示在 /@/views/demo/system/role/index.vue 组件被需要时才会加载。通过使用动态导入组件的方式,可以将组件分割成更小的代码块,只有当用户访问到该组件时才会加载。所以我们需要将我们开发好的页面通过import动态导入,并形成一个对应的映射表。

{
  "/demo/system/role/index":() => import('/@/views/demo/system/role/index.vue)
}

由于页面是不断增加的,所以我们不可能一个个去写这个映射关系。构建工具为我们提供了很方便的方法,在webpack中使用require.context,在vite中使用import.meta.glob。

import.meta.glob 是一个用于动态导入模块的方法,它可以根据指定的匹配模式,自动加载满足条件的所有模块,并返回一个对象,该对象包含了所有已加载模块的键值对。

例如,以下代码就是使用 import.meta.glob 方法来加载一个文件夹下的所有 Vue 组件:

const modules = import.meta.glob('./components/*.vue')

Object.keys(modules).forEach((path) => {
  const name = path.replace(/^\.\/components\/(.*)\.\w+$/, '$1')
  Vue.component(name, () => modules[path])
})

在上述代码中,import.meta.glob 方法会通过 ./components/*.vue 匹配模式来加载 ./components 文件夹中所有以 .vue 结尾的文件。然后,通过遍历加载的模块,将其作为 Vue 的全局组件进行注册。

以vite为例,我们使用import.meta.glob来得到一个组件映射对象

dynamicViewsModules = import.meta.glob('../../views/**/*.{vue,tsx}')

我们可以提供一个方法来处理component属性

function asyncImportRoute(routes: AppRouteRecordRaw[] | undefined) {
  dynamicViewsModules = dynamicViewsModules || import.meta.glob('../../views/**/*.{vue,tsx}')
  if (!routes) return
  routes.forEach((item) => {
    const { component, name } = item
    const { children } = item
    if (component) {
      const layoutFound = LayoutMap.get(component.toUpperCase())
      //判断是否是布局组件
      if (layoutFound) {
        item.component = layoutFound
      } else {
        item.component = dynamicImport(dynamicViewsModules, component as string)
      }
    } else if (name) {
      item.component = getParentLayout()
    }
    children && asyncImportRoute(children)
  })
}

通过循环传入的routes,我们取出每个路由的component属性值,通过属性值找到对应的映射组件并重新赋值。在上面方法中dynamicImport用于找出对应的映射关系。

function dynamicImport(
  dynamicViewsModules: Record<string, () => Promise<Recordable>>,
  component: string,
) {
  const keys = Object.keys(dynamicViewsModules)
  const matchKeys = keys.filter((key) => {
    const k = key.replace('../../views', '')
    const startFlag = component.startsWith('/')
    const endFlag = component.endsWith('.vue') || component.endsWith('.tsx')
    const startIndex = startFlag ? 0 : 1
    const lastIndex = endFlag ? k.length : k.lastIndexOf('.')
    return k.substring(startIndex, lastIndex) === component
  })
  if (matchKeys?.length === 1) {
    const matchKey = matchKeys[0]
    return dynamicViewsModules[matchKey]
  } else if (matchKeys?.length > 1) {
    warn(
      'Please do not create `.vue` and `.TSX` files with the same file name in the same hierarchical directory under the views folder. This will cause dynamic introduction failure',
    )
    return
  } else {
    warn('在src/views/下找不到`' + component + '.vue` 或 `' + component + '.tsx`, 请自行创建!')
    return EXCEPTION_COMPONENT
  }
}

总结

  1. 关联组件需要先定义好数据格式,通常后端返回的路由会有一个component属性,属性值为一个字符串路径,该路径指向对应的页面组件
  2. 使用import.meta.glob得到组件映射对象
  3. 定义asyncImportRoute方法替换掉后端返回的component属性为实际组件
  4. 定义dynamicImport方法从组件映射对象中查找实际组件,并判断组件是否唯一或者存在,并给出对应提示。

发表评论:

控制面板
您好,欢迎到访网站!
  查看权限
网站分类
最新留言