Vue怎么使用postMessage实现父子跨域通信

发布时间:2023-01-03 10:00:54 作者:iii
来源:亿速云 阅读:184

Vue怎么使用postMessage实现父子跨域通信

在现代Web开发中,跨域通信是一个常见且重要的需求。特别是在使用Vue.js构建单页面应用(SPA)时,我们经常需要在不同的域或子域之间进行数据传递。postMessage是HTML5提供的一种安全且强大的跨域通信机制,能够在不暴露敏感数据的情况下实现父子窗口之间的通信。本文将详细介绍如何在Vue.js中使用postMessage实现父子跨域通信。

1. 什么是postMessage?

postMessage是HTML5引入的一种跨文档通信机制,允许不同源的窗口(或iframe)之间进行安全的数据传递。它通过发送消息的方式实现通信,避免了直接访问对方的DOM或JavaScript对象,从而保证了安全性。

1.1 postMessage的基本用法

postMessage的基本语法如下:

targetWindow.postMessage(message, targetOrigin, [transfer]);

接收方通过监听message事件来接收消息:

window.addEventListener('message', function(event) {
    // 处理接收到的消息
    console.log(event.data);
});

1.2 postMessage的安全性

postMessage的设计考虑到了安全性,发送方可以指定目标窗口的源,接收方也可以通过event.origin验证消息的来源。这样可以有效防止恶意网站窃取数据或注入恶意代码。

2. Vue.js中使用postMessage的场景

在Vue.js应用中,postMessage常用于以下场景:

接下来,我们将通过一个具体的例子,演示如何在Vue.js中使用postMessage实现父子跨域通信。

3. 实现父子跨域通信的步骤

3.1 创建父窗口应用

首先,我们创建一个Vue.js父窗口应用,负责发送消息给子窗口(iframe)并接收子窗口的响应。

3.1.1 创建Vue项目

使用Vue CLI创建一个新的Vue项目:

vue create parent-app

3.1.2 编写父窗口代码

src/App.vue中编写父窗口的代码:

<template>
  <div id="app">
    <h1>父窗口</h1>
    <iframe
      id="child-iframe"
      src="http://child-app.com"
      @load="onIframeLoad"
    ></iframe>
    <button @click="sendMessageToChild">发送消息给子窗口</button>
    <p>来自子窗口的消息: {{ childMessage }}</p>
  </div>
</template>

<script>
export default {
  data() {
    return {
      childMessage: '',
    };
  },
  methods: {
    onIframeLoad() {
      // iframe加载完成后,监听message事件
      window.addEventListener('message', this.handleMessageFromChild);
    },
    sendMessageToChild() {
      const iframe = document.getElementById('child-iframe');
      const message = { type: 'greeting', content: 'Hello, Child!' };
      iframe.contentWindow.postMessage(message, 'http://child-app.com');
    },
    handleMessageFromChild(event) {
      // 验证消息来源
      if (event.origin !== 'http://child-app.com') return;
      this.childMessage = event.data.content;
    },
  },
  beforeDestroy() {
    // 组件销毁前移除事件监听器
    window.removeEventListener('message', this.handleMessageFromChild);
  },
};
</script>

<style>
#app {
  font-family: Avenir, Helvetica, Arial, sans-serif;
  text-align: center;
  margin-top: 60px;
}
</style>

3.1.3 运行父窗口应用

parent-app目录下运行开发服务器

npm run serve

父窗口应用将在http://localhost:8080运行。

3.2 创建子窗口应用

接下来,我们创建一个Vue.js子窗口应用,负责接收父窗口的消息并发送响应。

3.2.1 创建Vue项目

使用Vue CLI创建一个新的Vue项目:

vue create child-app

3.2.2 编写子窗口代码

src/App.vue中编写子窗口的代码:

<template>
  <div id="app">
    <h1>子窗口</h1>
    <p>来自父窗口的消息: {{ parentMessage }}</p>
    <button @click="sendMessageToParent">发送消息给父窗口</button>
  </div>
</template>

<script>
export default {
  data() {
    return {
      parentMessage: '',
    };
  },
  methods: {
    sendMessageToParent() {
      const message = { type: 'response', content: 'Hello, Parent!' };
      window.parent.postMessage(message, 'http://localhost:8080');
    },
    handleMessageFromParent(event) {
      // 验证消息来源
      if (event.origin !== 'http://localhost:8080') return;
      this.parentMessage = event.data.content;
    },
  },
  mounted() {
    // 组件挂载后,监听message事件
    window.addEventListener('message', this.handleMessageFromParent);
  },
  beforeDestroy() {
    // 组件销毁前移除事件监听器
    window.removeEventListener('message', this.handleMessageFromParent);
  },
};
</script>

<style>
#app {
  font-family: Avenir, Helvetica, Arial, sans-serif;
  text-align: center;
  margin-top: 60px;
}
</style>

3.2.3 运行子窗口应用

child-app目录下运行开发服务器:

npm run serve

子窗口应用将在http://localhost:8081运行。

3.3 配置跨域访问

由于父窗口和子窗口运行在不同的端口(80808081),我们需要配置跨域访问。

3.3.1 修改子窗口的CORS配置

child-appvue.config.js中添加以下配置:

module.exports = {
  devServer: {
    headers: {
      'Access-Control-Allow-Origin': '*',
    },
  },
};

3.3.2 修改父窗口的CORS配置

parent-appvue.config.js中添加以下配置:

module.exports = {
  devServer: {
    headers: {
      'Access-Control-Allow-Origin': '*',
    },
  },
};

3.4 测试跨域通信

现在,父窗口和子窗口都已经配置完成,我们可以测试它们之间的跨域通信。

  1. 打开父窗口应用:http://localhost:8080
  2. 点击“发送消息给子窗口”按钮,父窗口将发送消息给子窗口。
  3. 子窗口接收到消息后,显示在页面上。
  4. 点击子窗口的“发送消息给父窗口”按钮,子窗口将发送响应消息给父窗口。
  5. 父窗口接收到响应消息后,显示在页面上。

通过以上步骤,我们成功实现了Vue.js中父子窗口的跨域通信。

4. 处理复杂场景

在实际开发中,我们可能会遇到更复杂的场景,例如:

4.1 多个子窗口通信

如果父窗口需要与多个子窗口进行通信,可以为每个子窗口分配唯一的标识符(ID),并在发送消息时指定目标子窗口。

4.1.1 修改父窗口代码

在父窗口的App.vue中,添加多个iframe并为每个iframe分配ID:

<template>
  <div id="app">
    <h1>父窗口</h1>
    <iframe
      id="child-iframe-1"
      src="http://child-app.com"
      @load="onIframeLoad"
    ></iframe>
    <iframe
      id="child-iframe-2"
      src="http://child-app.com"
      @load="onIframeLoad"
    ></iframe>
    <button @click="sendMessageToChild('child-iframe-1')">发送消息给子窗口1</button>
    <button @click="sendMessageToChild('child-iframe-2')">发送消息给子窗口2</button>
    <p>来自子窗口的消息: {{ childMessage }}</p>
  </div>
</template>

<script>
export default {
  data() {
    return {
      childMessage: '',
    };
  },
  methods: {
    onIframeLoad() {
      window.addEventListener('message', this.handleMessageFromChild);
    },
    sendMessageToChild(iframeId) {
      const iframe = document.getElementById(iframeId);
      const message = { type: 'greeting', content: `Hello, ${iframeId}!` };
      iframe.contentWindow.postMessage(message, 'http://child-app.com');
    },
    handleMessageFromChild(event) {
      if (event.origin !== 'http://child-app.com') return;
      this.childMessage = event.data.content;
    },
  },
  beforeDestroy() {
    window.removeEventListener('message', this.handleMessageFromChild);
  },
};
</script>

4.1.2 修改子窗口代码

在子窗口的App.vue中,根据接收到的消息内容显示不同的信息:

<template>
  <div id="app">
    <h1>子窗口</h1>
    <p>来自父窗口的消息: {{ parentMessage }}</p>
    <button @click="sendMessageToParent">发送消息给父窗口</button>
  </div>
</template>

<script>
export default {
  data() {
    return {
      parentMessage: '',
    };
  },
  methods: {
    sendMessageToParent() {
      const message = { type: 'response', content: 'Hello, Parent!' };
      window.parent.postMessage(message, 'http://localhost:8080');
    },
    handleMessageFromParent(event) {
      if (event.origin !== 'http://localhost:8080') return;
      this.parentMessage = event.data.content;
    },
  },
  mounted() {
    window.addEventListener('message', this.handleMessageFromParent);
  },
  beforeDestroy() {
    window.removeEventListener('message', this.handleMessageFromParent);
  },
};
</script>

4.2 双向通信

在双向通信场景中,父窗口和子窗口需要频繁地发送和接收消息。我们可以通过维护一个消息队列或使用事件总线来实现。

4.2.1 使用事件总线

在Vue.js中,我们可以使用事件总线来实现组件之间的通信。首先,创建一个全局事件总线:

// eventBus.js
import Vue from 'vue';
export const EventBus = new Vue();

然后,在父窗口和子窗口中使用事件总线进行通信。

4.2.2 修改父窗口代码

在父窗口的App.vue中,使用事件总线发送和接收消息:

<template>
  <div id="app">
    <h1>父窗口</h1>
    <iframe
      id="child-iframe"
      src="http://child-app.com"
      @load="onIframeLoad"
    ></iframe>
    <button @click="sendMessageToChild">发送消息给子窗口</button>
    <p>来自子窗口的消息: {{ childMessage }}</p>
  </div>
</template>

<script>
import { EventBus } from './eventBus';

export default {
  data() {
    return {
      childMessage: '',
    };
  },
  methods: {
    onIframeLoad() {
      EventBus.$on('message-from-child', this.handleMessageFromChild);
    },
    sendMessageToChild() {
      const iframe = document.getElementById('child-iframe');
      const message = { type: 'greeting', content: 'Hello, Child!' };
      iframe.contentWindow.postMessage(message, 'http://child-app.com');
    },
    handleMessageFromChild(message) {
      this.childMessage = message.content;
    },
  },
  beforeDestroy() {
    EventBus.$off('message-from-child', this.handleMessageFromChild);
  },
};
</script>

4.2.3 修改子窗口代码

在子窗口的App.vue中,使用事件总线发送和接收消息:

<template>
  <div id="app">
    <h1>子窗口</h1>
    <p>来自父窗口的消息: {{ parentMessage }}</p>
    <button @click="sendMessageToParent">发送消息给父窗口</button>
  </div>
</template>

<script>
import { EventBus } from './eventBus';

export default {
  data() {
    return {
      parentMessage: '',
    };
  },
  methods: {
    sendMessageToParent() {
      const message = { type: 'response', content: 'Hello, Parent!' };
      window.parent.postMessage(message, 'http://localhost:8080');
    },
    handleMessageFromParent(event) {
      if (event.origin !== 'http://localhost:8080') return;
      this.parentMessage = event.data.content;
    },
  },
  mounted() {
    window.addEventListener('message', this.handleMessageFromParent);
    EventBus.$on('message-from-parent', this.handleMessageFromParent);
  },
  beforeDestroy() {
    window.removeEventListener('message', this.handleMessageFromParent);
    EventBus.$off('message-from-parent', this.handleMessageFromParent);
  },
};
</script>

4.3 错误处理

在跨域通信过程中,可能会遇到各种错误,例如目标窗口未加载完成、消息格式错误等。我们需要在代码中添加错误处理逻辑。

4.3.1 添加错误处理

在父窗口和子窗口的代码中,添加错误处理逻辑:

// 父窗口
sendMessageToChild() {
  const iframe = document.getElementById('child-iframe');
  if (!iframe || !iframe.contentWindow) {
    console.error('子窗口未加载完成');
    return;
  }
  const message = { type: 'greeting', content: 'Hello, Child!' };
  try {
    iframe.contentWindow.postMessage(message, 'http://child-app.com');
  } catch (error) {
    console.error('发送消息失败:', error);
  }
},

// 子窗口
handleMessageFromParent(event) {
  if (event.origin !== 'http://localhost:8080') {
    console.error('消息来源不合法:', event.origin);
    return;
  }
  if (!event.data || !event.data.content) {
    console.error('消息格式错误:', event.data);
    return;
  }
  this.parentMessage = event.data.content;
},

5. 总结

通过本文的介绍,我们了解了如何在Vue.js中使用postMessage实现父子跨域通信。postMessage是一种安全且强大的跨域通信机制,能够在不暴露敏感数据的情况下实现不同窗口之间的数据传递。在实际开发中,我们可以根据具体需求扩展和优化通信逻辑,例如处理多个子窗口、实现双向通信、添加错误处理等。

希望本文能够帮助你在Vue.js项目中更好地使用postMessage实现跨域通信。如果你有任何问题或建议,欢迎在评论区留言讨论。

推荐阅读:
  1. 怎么在Vue中引入jquery实现平滑滚动到指定位置
  2. webstorm中vue语法的示例分析

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

vue postmessage

上一篇:Vue的addEventListener()监听事件怎么使用

下一篇:怎么使用Java编写一个简单的风控组件

相关阅读

您好,登录后才能下订单哦!

密码登录
登录注册
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》