在vue中使用iframe标签

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了在vue中使用iframe标签相关的知识,希望对你有一定的参考价值。

参考技术A 在vue中使用iframe标签时,打包后的src文件无法查看会报路径不对404等
可以把iframe中的src路径改成打包后的文件路径即可;

在 iframe / 对象标签内运行时更新初始路由器 url

【中文标题】在 iframe / 对象标签内运行时更新初始路由器 url【英文标题】:update initial router url when running inside iframe / object tags 【发布时间】:2020-02-12 07:36:54 【问题描述】:

我目前正在容器/主 Vue 应用程序的对象标签内渲染 Vue 应用程序(iframe 也可以工作)。首先,我设置了一个文件服务器,为该容器或请求的子应用程序提供服务以在 div 内呈现。

为简单起见,我将只显示我的 Node/Express 服务器所需的路由

// serve the sub-app on demand
router.get('/subApps/:appName', function(req, res) 
    res.sendFile(path.resolve(__dirname, `../apps/$req.params.appName/index.html`);
);

// always render the app container if no sub-app was requested
router.get('*', function(req, res) 
    res.sendFile(path.resolve(__dirname, '../base/index.html'));
);

我的应用容器/主 Vue 应用位于 /apps/:appName 上呈现的视图文件中,请求该子应用并将其包装到对象标签中

  document.getElementById("customAppContainer").innerHTML = `<object style="width: 100%; height:100%;" data="http://localhost:3000/subApps/$appKey"></object>`;

这种方法效果很好,但渲染的子应用使用启动 url http://localhost:3000/subApps/app-one 尽管它应该使用 url http://localhost:3000/apps/app-one。当子应用加载路由器实例时,我必须将启动 url 从 iframe url 更改为浏览器 url(父)。

我考虑过用 history.replaceState 解决这个问题

const router = new Router( ... );

router.afterEach((to, from) => 
    localStorage.subAppRouteUpdate = to.path;
);

if (window.location !== window.parent.location) 
    const browserUrl = top.location.href;
    history.replaceState(null, null, browserUrl);


export default router;

我为什么要这样做?主应用的 App.vue 应该将子应用路由附加到浏览器 url。使用这种方法,可以在子应用程序内部导航时更新浏览器 url。我通过将子应用 url 存储到本地存储并在主应用端监听本地存储更改来实现这一点。所以 App.vue 文件使用了这段代码

<script>
export default 
  created() 
    window.addEventListener("storage", () => 
      const fullRoute = this.$router.currentRoute.fullPath;
      const routeSegments = fullRoute.split("/");
      const appsIndex = routeSegments.indexOf("apps");
      const newBaseUrlSegments = routeSegments.slice(0, appsIndex + 2);
      const newBaseUrl = newBaseUrlSegments.join("/");
      const subAppRoute = localStorage.subAppRouteUpdate;
      const updatedUrl = newBaseUrl.concat(subAppRoute);
      history.replaceState(null, null, updatedUrl);
    );
  
;
</script>

在使用 IFrame 时启用路由。它几乎可以工作,这就是我得到的

不幸的是,当调用子应用的/ 时,浏览器 url 会更新为

http://localhost:3000/apps/app-one/apps/app-one

虽然我期待

http://localhost:3000/apps/app-one/


复制:

我创建了一个repository 用于复制/测试。有人知道可能出了什么问题或如何修复该 url 更新?


更新:

我认为发生错误是因为在子应用的 router.js 中我正在触发此代码

if (window.location !== window.parent.location) 
    const browserUrl = top.location.href;
    history.replaceState(null, null, browserUrl);


router.afterEach((to, from) => 
    console.log( urlToAppend: to.path );
    localStorage.subAppRouteUpdate = to.path;
);

replaceState 函数会将 IFrame url 从 /subApps/app-one 更新为正确的浏览器 url /apps/app-one。不幸的是,这将触发 afterEach 事件,to.path 会导致/apps/app-one,尽管它应该是/

如果 url 是 /apps/app-one/users/create,那么在每个事件之后当然应该使用 /users/create 触发。

但我不知道如何解决这个第一个触发事件。

【问题讨论】:

【参考方案1】:

这可能是一个有点老套的解决方案,但它对我有用。只需检查当前 url 路径是否不等于 to.path 以防事件被触发两次

router.afterEach((to, from) => 
    console.log( urlToAppend: to.path );
    if (router.currentRoute.path !== to.path) 
        localStorage.subAppRouteUpdate = to.path;
    
);

更新

base/src/App.vue 中的存储事件侦听器中,在将子路由连接到基本路由之前,您不会检查可能的重复项。此修复程序应该会有所帮助

window.addEventListener("storage", () => 
      const fullRoute = this.$router.currentRoute.fullPath;
      const routeSegments = fullRoute.split("/");
      const appsIndex = routeSegments.indexOf("apps");
      const newBaseUrlSegments = routeSegments.slice(0, appsIndex + 2);
      const newBaseUrl = newBaseUrlSegments.join("/");
      const subAppRoute = localStorage.subAppRouteUpdate;
      if (subAppRoute.startsWith(newBaseUrl)) 
        history.replaceState(null, null, newBaseUrl);
       else 
        const updatedUrl = newBaseUrl.concat(subAppRoute);
        history.replaceState(null, null, updatedUrl);
      
    );

router.afterEach 应该看起来像这样导航到在 app-one 路由器中定义的子路由:

router.afterEach((to, from) => 
        const newPath = '/' + to.path.split('/').pop();
        const matchingRoutes = router.options.routes.filter(r => r.path === newPath);
        const isPathInRoutes = matchingRoutes.length > 0;
        if (router.currentRoute.path !== newPath && isPathInRoutes) 
            router.push(newPath);
            localStorage.subAppRouteUpdate = newPath;
         else 
            localStorage.subAppRouteUpdate = to.path;
        
);

如果您希望在用户转到http://localhost:3000/apps/app-one 时默认呈现第一页,您可以检查输入的 url 的最后一部分是否等于子应用程序的基本路由(/app-one),如果它确实导航到默认页面路线(/):

router.afterEach((to, from) => 
    let newPath = '/' + to.path.split('/').pop();
    const matchingRoutes = router.options.routes.filter(r => r.path === newPath);
    const isPathInRoutes = matchingRoutes.length > 0;
    if (newPath === router.history.base || !isPathInRoutes) 
        newPath = '/';
    
    if (router.currentRoute.path !== newPath) 
            router.push(newPath);
            localStorage.subAppRouteUpdate = newPath;
     else 
            localStorage.subAppRouteUpdate = to.path;
    
);

【讨论】:

所以如果你导航到App 1 - Page 2,浏览器网址仍然是http://localhost:3000/apps/app-one,但我希望http://localhost:3000/apps/app-one/two 你能检查我更新的答案是否按预期工作吗? 是的,你几乎明白了! :) 我遇到的最后一个问题是当调用此 url http://localhost:3000/apps/app-one 时,子应用程序不会呈现视图 Onehttp://localhost:3000/apps/app-one/two 相同,我希望它呈现 Two .. :/ @ktad 我给了你赏金 :) 页面的渲染仍然缺失 我还更新了我的答案,以便在用户导航到http://localhost:3000/apps/app-one时默认呈现第1页

以上是关于在vue中使用iframe标签的主要内容,如果未能解决你的问题,请参考以下文章

vue使用ifram标签解决父子页面传值,触发事件的操作

vue使用ifram标签解决父子页面传值,触发事件的操作

react项目中利用<iframe>标签嵌入 VUE项目

vue router hash构建的项目放在iframe内无效

在vue中使用Iframe嵌套问题

在 iframe / 对象标签内运行时更新初始路由器 url