在新窗口中打开一个 VueJS 组件

Posted

技术标签:

【中文标题】在新窗口中打开一个 VueJS 组件【英文标题】:Open a VueJS component on a new window 【发布时间】:2018-09-14 09:31:04 【问题描述】:

我有一个只有一页的基本 VueJS 应用程序。 不是SPA,我也不用vue-router。

我想实现一个按钮,当单击该按钮时,它会使用我的一个 Vue 组件中的内容执行 window.open() 函数。

查看window.open()的文档,我看到了以下关于URL的声明:

URL 接受指向 html 页面、图像文件或浏览器支持的任何其他资源的路径或 URL。

是否可以将组件作为window.open() 的参数传递?

【问题讨论】:

不能任意强制一些javascript在窗口中执行,不行。为此,您需要一个带有专用 URL 的专用页面。 简短的回答是:不。您不能将组件传递给window.open() 【参考方案1】:

我能够使用来自 an article about Portals in React 的一些见解来创建一个 Vue 组件,该组件能够在新窗口中挂载其子组件,同时保持反应性!很简单:

<window-portal>
  I appear in a new window!
</window-portal>

试试这个codesandbox!

该组件的代码如下:

<template>
  <div v-if="open">
    <slot />
  </div>
</template>

<script>
export default 
  name: 'window-portal',
  props: 
    open: 
      type: Boolean,
      default: false,
    
  ,
  data() 
    return 
      windowRef: null,
    
  ,
  watch: 
    open(newOpen) 
      if(newOpen) 
        this.openPortal();
       else 
        this.closePortal();
      
    
  ,
  methods: 
    openPortal() 
      this.windowRef = window.open("", "", "width=600,height=400,left=200,top=200");
      this.windowRef.addEventListener('beforeunload', this.closePortal);
      // magic!
      this.windowRef.document.body.appendChild(this.$el);
    ,
    closePortal() 
      if(this.windowRef) 
        this.windowRef.close();
        this.windowRef = null;
        this.$emit('close');
      
    
  ,
  mounted() 
    if(this.open) 
      this.openPortal();
    
  ,
  beforeDestroy() 
    if (this.windowRef) 
      this.closePortal();
    
  

</script>

关键是this.windowRef.document.body.appendChild(this.$el)这一行;这一行有效地从父窗口中删除了与 Vue 组件(***&lt;div&gt;)关联的 DOM 元素,并将其插入到子窗口的主体中。由于这个元素与 Vue 通常会更新的元素相同的引用,只是在不同的地方,一切正常工作 - Vue 继续更新元素以响应数据绑定的变化,尽管它被安装在一个新窗户。我真的很惊讶这是多么简单!

【讨论】:

这样方便但有时需要独立,因为父窗口会刷新或销毁一些组件,然后一些动作会在新窗口中停止,你知道如何剪切与父窗口相关的吗还是在 Vue 中独立? @HibaraAi 不使用这种方法 - 使用此组件,子窗口中的元素仍由父窗口的 Vue 实例管理,因此如果父窗口的 Vue 因刷新而被破坏,该元素将停止更新。也许您可以找到一种方法来挂钩水合过程并在刷新后将该子元素重新附加到父窗口,但我认为最终会更容易而不是加载一个全新的窗口并使用典型的窗口间通信喜欢window.postMessage 来实现你在说什么。 感谢您的回答,我发现vue可以配置使用多页应用程序,它可以独立刷新。 这是一个很好的方法,但不幸的是在实际场景中不太实用。太糟糕了,因为它真的很棒。 有趣的方法!【参考方案2】:

例如,如果你的主 vue 是这样声明的

var app = new Vue(...);

如果您只需要在新窗口中渲染几条数据,您可以从父窗口中引用数据模型。

var app1 = window.opener.app;

var title = app.title;

var h1 = document.createElement("H1");

h1.innerHTML = title;

document.body.appendChild(h1);

【讨论】:

【参考方案3】:

你不能传递一个 Vue 组件,因为window.open 不知道 Vue。但是,您可以做的是创建一个显示您的组件的路由并将该路由的 URL 传递给window.open,从而为您提供一个包含组件的新窗口。不过,不同窗口中的组件之间的通信可能会变得很棘手。

【讨论】:

谢谢。当我想到它时,它实际上是有道理的!

以上是关于在新窗口中打开一个 VueJS 组件的主要内容,如果未能解决你的问题,请参考以下文章

在新选项卡/窗口中打开链接而不丢失当前 JSF 页面的视图范围

如何使用HTML实现点击一个链接打开新窗口49

在新窗口中打开弹出窗口的方式

如何使用HTML实现点击一个链接打开新窗口

怎么单击一个按钮打开一个网页,我是要在新窗口中打开,不是在本窗口中打开.

JavaScript 在新窗口中打开,而不是选项卡