общие методы связи
postMessage
- MDN-postMessage
- грамматика
otherWindow.postMessage(message, targetOrigin, [transfer]);
-
otherWindow- Ссылка на другое окно, например
iframeизcontentWindowсвойства, исполнениеwindow.openвозвращаемый объект окна, именованный или пронумерованный в числовом видеwindow.frames.
- Ссылка на другое окно, например
-
message- будут отправлены другим
windowДанные. Он будет сериализован алгоритмом структурированного клонирования. Это означает, что вы можете безопасно передавать объекты данных в целевое окно без каких-либо ограничений, не сериализуя их самостоятельно.
- будут отправлены другим
-
targetOrigin- через окно
originсвойство, чтобы указать, какие окна могут получать сообщения о событиях, значение которых может быть строкой "*" (на неограниченный срок) илиURI. При отправке сообщения, если какой-либо протокол целевого окна, адрес хоста или порт не совпадаютtargetOriginЕсли указано значение, сообщение не будет отправлено; только если все три точно совпадают, сообщение не будет отправлено. Этот механизм используется для управления тем, на какие сообщения Windows можно отправлять сообщения; например, при использованииpostMessageПри передаче пароля этот параметр особенно важен, и его значение должно гарантированно совпадать со значением предполагаемого получателя сообщения, содержащего пароль.originАтрибуты точно такие же, чтобы предотвратить перехват паролей злоумышленниками. Если вы точно знаете, в какое окно должно быть отправлено сообщение, всегда указывайтеtargetOrigin, вместо*. Отсутствие точной цели приведет к утечке данных на любой вредоносный сайт, заинтересованный в данных.
- через окно
-
transferнеобязательный- представляет собой строку из и
messageпередается одновременноTransferableОбъекты. Право собственности на эти объекты будет передано получателю сообщения, а отправитель больше не сохранит право собственности.
- представляет собой строку из и
- использовать
window.parent.postMessage({
close: true,
type: 'shuaka',
result:msg.result,
errmeesage:msg.meesage,
cardMap:msg.map
}, 'http://192.168.60.104:3010/'
);
window.addEventListener('message', e => {
console.log(e)
var d = e.data; //e.data 里面有自己所传的所有参数 可以根据参数做自己的判断
});
-
postMessageПередача сообщений перед межоконной и междоменной связью может быть разрешена. - Уведомление
- Если вы не хотите получать с других сайтов
message, пожалуйста, не надоmessageevent для добавления прослушивателей событий. - когда вы используете
postMessageВсегда указывайте точную цель при отправке данных в другие окнаorigin, вместо*. - не могу проверить
originа такжеsourceАтрибут может привести к атакам межсайтового скриптинга.
- Если вы не хотите получать с других сайтов
Ajax
-
Ajax-Asynchronous JavaScript and XML(АсинхронныйJavaScriptа такжеXML), который можно использовать для связи с сервером для получения данных.
let xmlhttp;
if (window.XMLHttpRequest) {
// IE7+, Firefox, Chrome, Opera, Safari 浏览器执行代码
xmlhttp=new XMLHttpRequest();
} else {
// IE6, IE5 浏览器执行代码
xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");
}
xmlhttp.onreadystatechange = function() {
if (xmlhttp.readyState === 4 && xmlhttp.status === 200) {
document.getElementById("myDiv").innerHTML=xmlhttp.responseText;
}
}
xmlhttp.open("GET","/try/ajax/ajax_info.txt",true);
xmlhttp.send();
WebSocket
- Веб-сокет в js
-
WebSocketдаhtml5предоставляется в одномTCPПротокол двусторонней связи по соединению решает проблему связи в реальном времени между клиентом и сервером. Браузеру и серверу нужно только выполнить рукопожатие, а постоянныйTCPсоединение, после чего сервер и клиент проходят этотTCPсоединение для двусторонней связи в режиме реального времени.
- преимущество
- Чтобы добиться передачи данных, многие веб-сайты используют такие технологии, как
ajaxопрос. Опрос — это запрос, инициированный браузером через определенный интервал времени, чтобы получить данные с сервера. Опрос требует непрерывной отправки запросов на сервер, что требует большой пропускной способности и ресурсов сервера.WebSocketУчреждатьTCPПосле подключения сервер может активно передавать данные клиенту, что может лучше сэкономить ресурсы сервера и пропускную способность и обеспечить передачу данных в реальном времени.
function webSocket(){ if("WebSocket" in window) { console.log("您的浏览器支持WebSocket"); var ws = new WebSocket("ws://localhost:8080"); //创建WebSocket连接 //... } else {  console.log("您的浏览器不支持WebSocket"); } } - Чтобы добиться передачи данных, многие веб-сайты используют такие технологии, как
- использовать
- Поддержка клиентов
WebSocket, при созданииsocketПосле этого можно пройтиonopen,onmessage,oncloseа такжеonerrorчетыре пары событийsocketреагировать. Все операции WebSocket запускаются событиями, которые не блокируютсяUI,ДаUIЧем быстрее время отклика, тем лучше пользовательский опыт. - браузер через
JavaScriptВыпустить сборку на серверWebSocketПосле установления соединения клиент и сервер могут напрямую обмениваться данными через TCP-соединение. когда вы получаетеWebSocketПосле подключения вы сможетеsend()метод отправки данных на сервер, который может бытьonmessageСобытия получают данные, возвращаемые сервером.
var ws = new WebSocket("ws://localhost:8080"); //申请一个WebSocket对象,参数是服务端地址,同http协议使用http://开头一样,WebSocket协议的url使用ws://开头,另外安全的WebSocket协议使用wss://开头 ws.onopen = function(){ //当WebSocket创建成功时,触发onopen事件 console.log("open"); ws.send("hello"); //将消息发送到服务端 } ws.onmessage = function(e){ //当客户端收到服务端发来的消息时,触发onmessage事件,参数e.data包含server传递过来的数据 console.log(e.data); } ws.onclose = function(e){ //当客户端收到服务端发送的关闭连接请求时,触发onclose事件 console.log("close"); } ws.onerror = function(e){ //如果出现连接、处理、接收、发送数据失败的时候触发onerror事件 console.log(error); } - Поддержка клиентов
Сцены
- Поскольку социальный продукт внутри компании нуждается в разработке новой функции (блокнот), общая функция заключается в том, что пользователи могут создавать некоторые заметки в своих учетных записях, а формат записи заметок
markdownграмматика. Над областью редактирования есть еще одинtoolbar, аналогичный приведенному выше редактору форматированного текста. Дело в том, что продукт имеет несколько концов, включаяiOS,AndroidИ клиент, экспорт и загрузка редактора блокнота и т. д. должны вызывать метод соответствующего конца, поэтому необходимо поддерживать единую связь с каждым концом.
решение
Вариант 1: режим публикации-подписки
- Каждый конец монтирует измененный объект к глобальному объекту приложения, реализуя промежуточный уровень публикации и подписки, а редактор и клиент взаимодействуют с помощью методов публикации и подписки.
- ТС реализуется следующим образом:
// communite.ts
class Event {
public handlers: any = {}; // 事件容器,用来装事件数组(因为订阅者可以是多个)
public note: object = { // 写死的note属性
id: 1234,
language: "en-US",
themeColor: "red",
};
// 事件添加方法,参数有事件名和事件方法
public addEvent(type: string, handler: (...param: any[]) => void) {
// 首先判断handlers内有没有type事件容器,没有则创建一个新数组容器
if (!(type in this.handlers)) {
this.handlers[type] = [];
}
// 将事件存入/替换
this.handlers[type][0] = handler;
// this.handlers[type].push(handler); // 同一事件名多个回调函数
}
// 触发事件两个参数(事件名,参数)
public dispatchEvent(type: string, params?: any[], callback?: (...param: any) => void) {
// 若没有注册该事件则抛出错误
if (!(type in this.handlers)) {
return new Error("未注册该事件");
}
// tslint:disable-next-line:no-console
console.log("dispatchEvent params", type, params);
// tslint:disable-next-line:whitespace
switch(type) {
case "touchCharSize" :
callback ? callback() : this.handlers[type][0]();
break;
case "charSize":
// tslint:disable-next-line:no-console
console.log(params);
// callback ? callback(content) : this.handlers[type][0](content);
break;
case "upload":
const fileObject = {
filename: "test",
id: "123456",
size: 1024,
type: "pdf",
url: "/sdad/dsads/test.pdf",
};
callback ? callback(fileObject) : this.handlers[type][0](fileObject);
break;
default:
break;
}
// 触发
// this.handlers[type].forEach((handler: (...params: any[]) => void) => {
// handler(...params)
// })
}
// 事件移除参数(事件名,删除的事件,同一事件多个回调函数若无第二个参数则删除该事件的订阅和发布)
public removeEventListener(type: string, handler?: () => void) {
// 无效事件抛出
if (!(type in this.handlers)) {
return new Error("无效事件");
}
if (!handler) {
// 直接移除事件
delete this.handlers[type];
} else {
const idx = this.handlers[type].findIndex((ele: () => void) => ele === handler);
// 抛出异常事件
if (idx === -1) {
return new Error("无该绑定事件");
}
// 移除事件
this.handlers[type].splice(idx, 1);
if (this.handlers[type].length === 0) {
delete this.handlers[type];
}
}
}
}
export default new Event();
- Когда клиенту нужно получить некоторые данные, клиент запускает (
dispatchEvent) Соответствующее имя события достигает среднего уровня, средний уровень выполняет функцию обратного вызова соответствующего события в редакторе, запускает новое событие в функции обратного вызова, отправляет данные клиенту, а клиент прослушивает соответствующее событие в средний слой, чтобы иметь дело с результатом. Ниже приведен пример получения текущего редактируемого содержимого записной книжки:
// conmmunite.ts 中间层已实现对应的touchCharSize和charSize事件处理
// 客户端触发事件:touchCharSize
// 笔记本编辑器添加:touchCharSize,并执行回调触发:charSize
import Event from './communite.ts'
// 获取笔记字数
Event.addEventListener('touchCharSize', () => {
Event.dispatchEvent('charSize', {
total: 46000, // 总字数
current: 12233 // 当前字数
});
})
Event.dispatchEvent('touchCharSize'); // 客户端触发获取字数事件
// 获取笔记字数
Event.addEventListener('charSize', () => {
console.log('charSize');
})
- Поскольку сбор количества слов активно инициируется клиентом, для завершения всего процесса связи нам нужны два события.Клиент получает данные в событиях, инициированных редактором блокнота.
Вариант 2: Реализуется индивидуально
- В режиме публикации-подписки нам нужен промежуточный уровень для хранения наших событий, а связь между двумя концами более сложная, поэтому существует вторая схема реализации.
- Поскольку приложение может выполнять в приложении
JavaScriptметод, поэтому, когда клиент получает некоторую информацию в редакторе записной книжки, он может выполнитьJavaScriptМетоды.
// 类似安卓中的实现
WebView webView;
Button buttonLeft;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main4);
webView=findViewById(R.id.webview);
buttonLeft = findViewById(R.id.btnLeft);
WebSettings webSettings=webView.getSettings();
webSettings.setCacheMode(WebSettings.LOAD_NO_CACHE);//缓存
webSettings.setJavaScriptEnabled(true);
webSettings.setJavaScriptCanOpenWindowsAutomatically(true);//允许弹窗
webView.getSettings().setDomStorageEnabled(true);
webView.loadUrl("file:///android_asset/evaluate.html");
buttonLeft.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(final View v) {
webView.post(new Runnable() {
@RequiresApi(api = Build.VERSION_CODES.KITKAT)
@Override
public void run() {
webView.evaluateJavascript("javascript:callJS()", new ValueCallback<String>() {
@Override
public void onReceiveValue(String s) {
buttonLeft.setText(s);
}
});
// 执行JavaScript函数
webView.loadUrl("javascript:detanx()");
}
});
}
});
webView.setWebChromeClient(new WebChromeClient(){
@Override
public boolean onJsAlert(WebView view, String url, String message, final JsResult result) {
AlertDialog.Builder builder=new AlertDialog.Builder(Main4Activity.this);
builder.setTitle("alert1");
builder.setMessage(message);
builder.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
result.confirm();
}
});
builder.setCancelable(false);
builder.create().show();
return true;
}
});
}
- существует
index.htmlДобавьте соответствующий метод в .
// index.html
<!DOCTYPE html>
<html lang="en-US">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0" />
<title></title>
</head>
<body>
<div id="detanx"></div>
<script>
function detanx() {
document.getElementById('detanx').innerHTML = 'detanx';
}
</script>
</body>
</html>
- вызов приложения
JavaScriptОн реализуется, а затем приложение монтирует объект глобально (Event), объект содержит некоторые методы, мы передаемEventЭтот объект, вJavaScriptДля выполнения метода соответствующих событий мы передаемJavaScriptЧтобы реализовать унифицированную функцию обратного вызова, после запуска соответствующего события в приложении приложение возвращает соответствующий результат, выполняя унифицированную функцию обратного вызова. В функции обратного вызова мы используем уникальный идентификатор для представления каждого инициированного события. функция после обратного вызова соответствующего события выполняется позже. Вот пример:
// 缓存
const list = {}
// 触发方法并缓存
function dispatchEvent() {
// 生成唯一标识
const markid = new Date().getTime().toString();
list.markid = setContent;
Event.getContent(noteid, markid);
}
// 设置内容执行函数
function setContent(result) {
const { content } = result
console.log(result);
}
// 应用处理完成统一回调函数
function commonCallbak (markid, result) {
if(list.markid) {
list.markid(result);
// 移除缓存
delete list.markid;
} else {
throw new Error('markid is not exist.')
}
}
- Эта реализация может сохранить реализацию среднего уровня, но предпосылка состоит в том, что несколько терминалов могут поддерживать этот тип вызова.
JavaScriptПуть.
Суммировать
- Существует множество способов общения, таких как
websocket,Ajax,postMessage, режим публикации-подписки и т. д. Технические решения, которые мы используем, безусловно, различаются в зависимости от разных конкретных бизнес-сценариев. Нет лучшего решения, есть только самое подходящее. У нас достаточно преимуществ и недостатков каждого решения. Только поняв, вы знать, какое решение в настоящее время является лучшим.