动态路由+能支持iframe嵌入


动态路由+能支持iframe嵌入

“动态路由 + iframe 内嵌”的工作机制与关键点,帮你快速看清楚从配置→路由注入→渲染的全流程。

总体流程

  • 静态和动态菜单源合并后统一转换为可注入的路由对象并注册到路由树。

  • 若路由项的 meta.type 指定为支持内嵌的类型(本项目现有:iframe<打开新标签页> 与 embedding_iframe<页面内嵌>),会被转换为一个内部访问路径 /i/${name},并将原始外链地址存入 meta.url

  • 页面渲染时,真实的页面不是常规 view 组件,而是通过 iframeView 组件读取 meta.url,以 <iframe> 内嵌方式展示。

关键文件与职责

  • 路由注入与转换:src/router/index.js

    • 合并菜单源:
      • 静态:userRoutes(来自 src/config/route.js
      • 动态:MENU(来自 tool.data.get('MENU')
    • 鉴权过滤:treeFilter(userRoutes, func) 会按 meta.role 做权限控制。
    • 转换核心:filterAsyncRouter(routerMap)
      • 识别外链型菜单并改造为内嵌路由:
        1
        2
        3
        4
        5
        //处理外部链接特殊路由
        if (item.meta.type == 'iframe' || item.meta.type == 'embedding_iframe') {
        item.meta.url = item.path;
        item.path = `/i/${item.name}`;
        }
        • path(外链 URL)被保存到 meta.url
        • path 统一变成 /i/${name}
      • 统一生成标准路由对象并按 layout 父路由动态注册:
        1
        2
        3
        4
        5
        6
        7
        8
        var route = {
        path: item.path,
        name: item.name,
        meta: item.meta,
        redirect: item.redirect,
        children: item.children ? filterAsyncRouter(item.children) : null,
        component: loadComponent(item.component),
        };
    • 首次进入时的动态注册控制:isGetRouter 保证只注入一次;注入完成后才加 404。
    • 注意:如果存在“进入前打开新标签”的逻辑,通常写在 beforeEach 中根据 meta.type==='iframe' 执行 window.open(...)。若你要所有 iframe 内嵌显示,应避免在守卫里拦截打开新页,仅依赖 iframeView 渲染。
  • 菜单与链接规范化:src/layout/index.vue

    • 菜单二次处理 filterUrl:确保左侧菜单点击时,外链类项的 path 也会落在 /i/${name},与路由规则一致。
      1
      2
      3
      if (item.meta.type == 'iframe' || item.meta.type == 'embedding_iframe') {
      item.path = `/i/${item.name}`;
      }
  • iframe 渲染容器:src/layout/components/iframeView.vue

    • 只在当前路由 meta.type 为外链内嵌类型时显示 iframe 容器:
      1
      2
      3
      <div v-show="$route.meta.type=='iframe' || $route.meta.type=='embedding_iframe'" class="iframe-pages">
      <iframe v-for="item in iframeList" :key="item.meta.url" v-show="$route.meta.url==item.meta.url" :src="item.meta.url" frameborder='0'></iframe>
      </div>
    • 进入外链路由时,会将当前路由压入 iframeList,从而支持多标签/刷新等行为:
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      if(route.meta.type == 'iframe' || route.meta.type == 'embedding_iframe'){
      if(this.ismobile || !this.layoutTags){
      this.$store.commit("setIframeList", route)
      }else{
      this.$store.commit("pushIframeList", route)
      }
      }else{
      if(this.ismobile || !this.layoutTags){
      this.$store.commit("clearIframeList")
      }
      }
    • 对应的持久化列表在 src/store/modules/iframe.js,包含 setIframeList/pushIframeList/refreshIframe/clearIframeList 等。

路由配置怎么写(例)

src/config/route.js 静态菜单里,外链菜单这样写:

1
2
3
4
5
{
name: 'compassindustry',
path: 'https://open.ys7.com/cn/s/index',
meta: { title: '行业指数', icon: 'el-icon-caret-right', type: 'embedding_iframe' }
}
  • name:必须唯一,用来生成内部访问路径 /i/compassindustry

  • path:外部真实 URL

  • meta.type:使用 iframeembedding_iframe 任一都可按当前代码支持内嵌

  • 渲染流程:点击菜单 → 实际跳转到 /i/compassindustryiframeView 根据 meta.url 内嵌加载外链

常见问题与排查

  • “No match found for location with path ‘/i/xxx’”:通常是该项路由尚未被注入。确保:

    • 该菜单项包含在 userRoutes 或后端返回的 MENU 中;
    • 名称 name 与菜单里点击的一致(由 name 决定 /i/${name});
    • 首次加载时不要过早跳转到尚未注册的 /i/...,或保证动态注入在导航前完成。
  • 点击外链被新开标签页:检查路由守卫里是否有针对 meta.type === 'iframe'window.open 拦截。若你希望“全部内嵌”,请移除或改为仅对特定类型生效。

  • 需要新支持的类型:在 filterAsyncRouteriframeView.vue 的判断里加上你的 meta.type 即可。