Toggle navigation
我的博客
首页
文章列表
留言板
登录
注册
首页
技术分享
文章
前端技术中的常用通信方案
作者:
gaohan
•
2023年07月11日
阅读 (322)
:::align-left
### 原生js通信
**1. Event**: 在发送方注册事件,并在接收方监听该事件来进行通信。发送方在适当的时机触发事件,接收方收到事件后执行相应的处理
[event-example](https://wx.xjjswh.cn/worker/event.html)
```
发送消息
```
**2.iframe**
[iframe-example](https://wx.xjjswh.cn/worker/iframe/main.html)
**3.标签通信--频道**
BroadcastChannel 接口代理了一个命名频道,可以让指定 origin 下的任意 browsing context 来订阅它。它允许同源的不同浏览器窗口,Tab 页,frame 或者 iframe 下的不同文档之间相互通信。通过触发一个 message 事件,消息可以广播到所有监听了该频道的 BroadcastChannel 对象
[channel1](https://wx.xjjswh.cn/worker/channel/channel1.html)
[channel2](https://wx.xjjswh.cn/worker/channel/channel2.html)
```
function BroadChannel(cb){
// 获取频道
this.get = function(channelname){
return this.channelMap.get(channelname)
}
// 获取默认频道名称
this.getDefaultName = function(){
return 'broad-channel-' + (this.channelMap.size + 1)
}
// 获取所有频道数
this.getLength = function(){
return this.channelMap.size
}
// 创建频道
this.create = function(channelname){
const self = this
const name = channelname || self.getDefaultName()
const channel = new BroadcastChannel(name)
channel.onmessage = function(ev){
const message = {
data: ev.data,
name,
time: Date.now()
}
cb && cb(message)
}
channel.onmessageerror = function(ev){
console.error(ev.data);
}
self.channelMap.set(name,channel)
self.channelLength = self.getLength()
return channel
}
// 开通频道
this.open = function (channelname){
const channel = this.get(channelname)
return channel || this.create(channelname)
}
// 关闭频道
this.close = function(channelname){
const channel = this.get(channelname)
if( channel ){
channel.close()
}
}
// 删除频道
this.delete = function(channelname){
this.close(channelname)
this.channelMap.delete(channelname)
this.channelLength = this.getLength()
}
// 判断是否存在相同频道
this.has = function(channelname){
return this.channelMap.has(channelname)
}
// 发送消息
this.postMessage = function(channelname, data){
const channel = this.get(channelname)
if( channel ){
try {
// 正常
channel.postMessage(data)
}catch (e) {
// 频道已关闭,重新创建频道
this.delete(channelname)
this.open(channelname)
this.postMessage(channelname, data)
}
}else{
console.warn('【channel:'+channelname+'】: channel is not defined, you should first execute open method');
}
}
// 初始化
this.reset = function (){
// 频道名称集合
this.channelMap = new Map()
this.channelLength = this.getLength()
}
this.reset()
}
const channel = new BroadChannel((data)=>{
console.log(data);
})
channel.open('test').postMessage('test',111)
channel.open('test2').postMessage('test2',222)
console.log(channel);
```
**4. ShareWorker**
SharedWorker是HTML5提供的一种Web Worker类型,它允许多个浏览器上下文(如多个窗口、标签页或框架)共享相同的Worker实例。与普通的Worker不同,SharedWorker可以跨浏览器上下文进行通信和共享数据
[worker1](https://wx.xjjswh.cn/worker/worker1.html)
[worker2](https://wx.xjjswh.cn/worker/worker2.html)
#### 5.本地缓存 ```LocalStorage和SessionStorage```
LocalStorage和SessionStorage是浏览器提供的本地存储方案。它们可以在浏览器端存储和读取数据,并在同一域名下的不同页面间进行数据共享。LocalStorage和SessionStorage适用于在同一浏览器中的不同页面之间进行数据传递的需求
#### 6. MessageChannel
Channel Messaging API 的 MessageChannel 接口允许我们创建一个新的消息通道,并通过它的两个 MessagePort 属性发送数据
[消息频道](https://wx.xjjswh.cn/worker/channel/main.html)
### 事件总线
事件总线是一种在应用程序中实现组件间通信的机制。它允许组件之间通过订阅和发布事件来进行信息传递,无论这些组件是父子组件、兄弟组件或跨越组件树的。
事件总线的实现可以是一个全局的事件管理器或服务,也可以是一个专门为事件通信而创建的组件
1. 方式1:
```
import mitt from 'mitt'
const EventBus = mitt();
```
2. 方式2
```
const EventBus = new Vue()
```
事件总线方法:
```
EventBus.on("on-preview")
EventBus.emit("on-preview", '图片地址')
EventBus.off("on-preview")
```
### 交互通信
WebViewJavascriptBridge是一个用于在WebView与JavaScript之间进行双向通信的桥接库。它允许原生应用程序的WebView与嵌入的JavaScript通过桥接对象进行交互,实现数据传输和方法调用
js代码:
```
/*这段代码是固定的,必须要放到js中*/
function setupWebViewJavascriptBridge(callback) {
//判断机型
let u = navigator.userAgent;
if (window.WebViewJavascriptBridge) {
return callback(WebViewJavascriptBridge);
}
//判断是否是ios
if (/(iPhone|iPad|iPod|iOS|Mac OS)/i.test(u)) {
if (window.WVJBCallbacks) {
return window.WVJBCallbacks.push(callback);
}
window.WVJBCallbacks = [callback];
let WVJBIframe = document.createElement('iframe');
WVJBIframe.style.display = 'none';
WVJBIframe.src = 'wvjbscheme://__BRIDGE_LOADED__';
document.documentElement.appendChild(WVJBIframe);
setTimeout(function() {
document.documentElement.removeChild(WVJBIframe);
}, 0);
} else {
document.addEventListener(
'WebViewJavascriptBridgeReady',
function() {
callback(WebViewJavascriptBridge)
},
false
);
}
}
let Bridge = {};
Bridge.install = function (Vue, options) {
Vue.prototype.$bridge = {};
/*与OC交互的所有JS方法都要放在此处注册,才能调用通过JS调用OC或者让OC调用这里的JS*/
setupWebViewJavascriptBridge(function(bridge) {
// 普通环境 - 生命全局变量
//初始化
//判断机型
let u = navigator.userAgent;
if (!/(iPhone|iPad|iPod|iOS|Mac OS)/i.test(u)) {
bridge.init(function(message, responseCallback) {
let data = {
'Javascript Responds': 'Wee!'
};
alert("jasdashjd");
responseCallback(data);
});
}
Vue.prototype.$bridge = bridge;
});
//
// setupWebViewJavascriptBridge(function (bridge) {
// Vue.prototype.$bridge = bridge;
// })
}
export default Bridge;
```
安卓端代码:
```
// 创建WebViewJavascriptBridge实例
WebViewJavascriptBridge bridge = new WebViewJavascriptBridge(context, webView, new BridgeHandler() {
@Override
public void handler(String data, CallBackFunction responseCallback) {
// 处理JavaScript发送的消息
// ...
// 发送响应给JavaScript
responseCallback.onCallBack("Android response");
}
});
// 注册一个Native Handler用于处理JavaScript请求
bridge.registerHandler("jsHandler", new BridgeHandler() {
@Override
public void handler(String data, CallBackFunction responseCallback) {
// 处理JavaScript请求
// ...
// 发送响应给JavaScript
responseCallback.onCallBack("Android response");
}
});
// 发送消息给JavaScript
bridge.callHandler("nativeHandler", "Android message", new CallBackFunction() {
@Override
public void onCallBack(String responseData) {
// 处理JavaScript响应
// ...
}
});
```
ios端代码:
```
// 导入WebViewJavascriptBridge头文件
#import "WebViewJavascriptBridge.h"
// 创建一个WebViewJavascriptBridge实例
WebViewJavascriptBridge *bridge = [WebViewJavascriptBridge bridgeForWebView:webView];
// 注册一个处理Native请求的handler
[bridge registerHandler:@"nativeHandler" handler:^(id data, WVJBResponseCallback responseCallback) {
// 处理Native请求,如获取设备信息等
// ...
// 回调JavaScript
responseCallback(@"Native response");
}];
// 发送消息给JavaScript
[bridge callHandler:@"jsHandler" data:@"Native message" responseCallback:^(id responseData) {
// 处理JavaScript响应
// ...
}];
```
#### C30使用WebViewJavascriptBridge集成库-appcore
[appcore文档](https://docs.qq.com/doc/DUG5lQWlGb0ZWeVBn)
**c++通信**
通过在窗口window对象上注册事件实现消息互通
发送c++消息:
```
/**
* @name: 发送c++消息
* @param cmd 消息类型
* @param name 消息名称
* @param data 消息数据
*/
try {
if (window.cef && window.cef.message) {
window.cef.message.sendMessage(cmd, [name, data]);
}
} catch (e) {
}
```
接收c++消息:
```
/**
* @name: 接收c++消息
* @param type 消息类型
* @param data 消息数据
*/
window.callFunction = (type: string, data: any) =>{}
```
#### C30使用集成库-wincore
### 其他通信:
1. 其他通信:AJAX是一种通过在后台与服务器进行数据交换的技术。通过在页面上使用JavaScript,可以异步地发送HTTP请求,获取数据并更新页面内容,实现与服务器的数据交互
2. WebSocket是一种在单个TCP连接上进行全双工通信的协议。它允许在客户端和服务器之间实时传输数据,同时支持服务器向客户端主动推送数据。WebSocket能够提供实时性和双向通信的能力,非常适合实时应用程序、即时通讯以及在线游戏等场景
3. Server-Sent Events是一种基于HTTP的服务器向客户端推送事件的技术。与WebSocket不同,SSE是一种单向通信机制,服务器可以向客户端推送数据,但客户端不能主动向服务器发送请求。SSE适用于需要实时更新的应用场景,如实时新闻、股票行情等
4. WebRTC(Web Real-Time Communication)是一种支持浏览器之间进行实时通信的开放性标准。它提供了音视频通信、数据传输和P2P文件共享等功能。WebRTC可以在Web应用程序中实现实时语音、视频通话和文件传输,同时也可以用于游戏、即时通讯和远程协作等场景
5.以及其他通信方式
::: warning
js开发中,通信问题一般都与浏览器安全协议有着密切的关系,也就是我们常说的跨域问题,面对不同的场景,可以选择不同的通信方式
:::
:::align-left
::: warning
使用Web API实现相关通信的方案时,需要考虑浏览器兼容性,一般主流浏览器都兼容,像IE或低版本浏览器会有兼容性问题
具体可以在[MDN](https://developer.mozilla.org/zh-CN/docs/Web/API/SharedWorker)或者[Can I Use](https://caniuse.com/)网站查看
:::
- 标签页之间可以采用哪些通信方式:grey_question:
- iframe可以采用哪些通信方式:grey_question:
- 如何用js代码实现事件总线:grey_question:
::: details
```
class EventBus {
constructor() {
this.events = {};
}
// 订阅事件
on(eventName, callback) {
if (!this.events[eventName]) {
this.events[eventName] = [];
}
this.events[eventName].push(callback);
}
// 发布事件
emit(eventName, ...args) {
const eventCallbacks = this.events[eventName];
if (eventCallbacks) {
eventCallbacks.forEach(callback => {
callback(...args);
});
}
}
// 取消订阅
off(eventName, callback) {
const eventCallbacks = this.events[eventName];
if (eventCallbacks) {
this.events[eventName] = eventCallbacks.filter(cb => cb !== callback);
}
}
}
// 创建一个事件总线实例
const eventBus = new EventBus();
// 定义事件处理函数
const handleEvent = (data) => {
console.log(`Event triggered: ${data}`);
};
// 订阅事件
eventBus.on('eventA', handleEvent);
// 发布事件
eventBus.emit('eventA', 'Hello World'); // 输出: Event triggered: Hello World
// 取消订阅事件
eventBus.off('eventA', handleEvent);
// 再次发布事件
eventBus.emit('eventA', 'Hello again'); // 不会有任何输出
```
:::
© 著作权归作者所有
分类
技术分享
标签
vue