Связь между разными страницами и междоменными

внешний интерфейс сервер JavaScript HTML

0. Предисловие

Я считаю, что есть какие-то средства кроссдоменности, все с этим знакомы. Теперь давайте попрактикуемся не на одной вкладке и не в разных доменах.

1. localstorage

1.1 событие хранения

Localstorage — это пространство для хранения, совместно используемое браузерами с тегами в одном домене, поэтому его можно использовать для связи между несколькими тегами. В html5 есть событие: onstorage, мы можем следить за изменениями, добавляя слушатель к объекту окна:window.addEventListener('storage', (e) => console.log(e))

Следует отметить, что это событие будет запущено только тогда, когда нетекущая страница изменяет localStorage, а текущая модификация страницы localStorage не вызовет функцию прослушивателя. Если вы действительно хотите, перепишите метод самостоятельно или загрузите содержимое, которое вы изменили при его изменении.

Пример: js:

if(!localStorage.getItem('a')){
	localStorage.setItem('a',1)
}else{
	var s = localStorage.getItem('a')
	localStorage.setItem('a',+s+1)
}
window.addEventListener('storage', (e) => console.log(e))

Мы создаем два новых html с именами 1.html и 2.html и добавляем приведенный выше js, поэтому каждый раз, когда мы открываем или обновляем страницу, мы будем добавлять 1 к a. Следует отметить, что если его открыть двойным щелчком, он находится вfile://В соответствии с протоколом и событие хранения не будет запущено, но оно добавит 1 к a, поэтому вы можете сделать функцию, чтобы вычислить, сколько раз локальный файл открыт. Если мы откроем его с сервером, наша связь с другой вкладкой будет выполнена в режиме реального времени.

2. Играйте с фреймами

Все мы знаем, что фреймы могут быть междоменными, так что давайте попробуем. В следующих примерах все iframe встроены в HTML.Конечно, если вы напрямую открываете файл iframe, это бессмысленно.

2.1 Используйте изменения хэша для передачи информации для обеспечения связи между родительскими и дочерними окнами (может быть междоменной)

Родительское окно: 1.html

html:

<iframe name="myIframe" src="http://localhost:1000/2.html"></iframe>

js:

var originURL = myIframe.location.href
var i = document.querySelector('iframe')
i.onload= function(){//这是异步加载的iframe
  i.src += '#aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'
}

Дочернее окно: 2.html

window.onhashchange = function() {
    console.log(window.location.hash)
}

Открываем родительское окно и обнаруживаем, что js дочернего окна уже запущен.

Поскольку это может быть междоменным, мы можем дважды щелкнуть, чтобы открыть 1.html напрямую, и обнаружить, что это все еще возможно.В этом примере двойной щелчок, чтобы открыть, и сервер, чтобы открыть, может достичь цели.

2.2 Родитель вызывает js дочерней страницы или наоборот

Родительский тон: по-прежнему основан на предыдущих условиях

var i = document.querySelector('iframe')
i.onload= function(){
myIframe.window.f();
}

суб: 2.html

function f(){
	console.log('this is 2.html')
}

Сын подпевает отцу: суб: 2.html

parent.fn1()

Родитель: 1.html

function fn1(s){
	console.log('this is 1.html')
}
}

Конечно, вам бессмысленно открывать 2.html напрямую и сообщает об ошибке:Uncaught TypeError: parent.fn1 is not a function

Следует отметить, что это не может быть междоменным, поэтому дважды щелкните, чтобы открыть, и разные домены неверны:Uncaught DOMException: Blocked a frame with origin "null" from accessing a cross-origin frame., открыт только сервер

2.3 window.name (может пересекать домен)

Подобно Vue, значение передачи родитель-потомок в React, если имя тега iframe задано в родительском окне, его можно прочитать в дочернем окне.

Родительское окно: 1.html

<iframe  name="myIframe" src="http://localhost:1000/2.html"></iframe>

Дочернее окно: 2.html

console.log(window.name)

Молодой человек, дважды щелкните, чтобы открыть его с уверенностью, это работает.

2.4 почтовое сообщение (может пересекать домен)

После H5 к окну был добавлен метод window.postMessage(), первым параметром которого являются данные для отправки, а вторым параметром — доменное имя.

Родительское окно: 1.html

<iframe id="test" name="myIframe" src="http://localhost:1000/2.html"></iframe>

//js
var frame = document.querySelector('iframe')
frame.onload = function(argument) {
	window.frames[0].postMessage('data from html1', '*');
}

Дочернее окно: 2.html

window.onmessage = function (e) {
	console.log(e.data)
}

Он может быть междоменным, поэтому вы можете напрямую открыть его двойным щелчком, чтобы увидеть эффект.

Вышеупомянутое родительско-дочернее окно относится к введению тега iframe из одного html в другой html.

3. Связь между двумя вкладками, которые не находятся в одном домене.

То есть общаются две несвязанные вкладки (например открываю байду и гитхаб), как общаться?

Конечно, могут ли baidu и github общаться, мы не знаем, надо спросить у их разработчиков. Ранее мы уже знали, что iframe может пересекать домены, а localstorage может связывать две вкладки. Тогда давайте попробуем, iframe соединяет две несвязанные вкладки. Обратите внимание, что мост — это html, а две другие вкладки относятся к двум html-файлам, открытым браузером. Вы также можете создать два разных HTML-файла, или вы можете создать два идентичных HTML-файла, а затем дважды щелкнуть, чтобы открыть или сервер, чтобы открыть, просто есть два.

Далее давайте назовем iframe моста bridge.html. Открываем его узлом и слушаем локальный порт 1000.

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
  </head>
  <body>
    <h1>hi</h1>
  </body>
  <script type="text/javascript">
window.addEventListener("storage", function(ev){
    if (ev.key == 'info') {
        window.parent.postMessage(ev.newValue,'*');
    }
});


window.addEventListener('message',function(e){
    // 接受到父文档的消息后,广播给其他的同源页面
    localStorage.setItem('info',e.data);
});
  </script>
</html>

У нас есть еще две страницы, содержание следующее. Тогда мы можем открыть его по отдельности n разными способами, все равно он не гомологичен.

<!DOCTYPE html>
<html>
<head>
	<title></title>
</head>
<body>
    <input id="ipt" type="text" name="">
    <button onclick="sub()">sub</button>
    <p id="cont"></p>
    <iframe src="http://localhost:1000/" style="display: none"></iframe>
</body>
<script type="text/javascript">
    var ipt = document.querySelector('#ipt')
    function sub(){
      document.querySelector('iframe').contentWindow.postMessage(ipt.value,'*');
      cont.innerHTML +='我:'+ ipt.value + '<br>'
      ipt.value = ''
    }
    window.addEventListener('message',function(e){
      if(e.data) cont.innerHTML +='对方:'+ e.data + '<br>'
      
    });
</script>
</html>

Затем простой чат сделан, попробуйте. Если вы добавите веб-сокет, вы также можете общаться в чате с другим источником, а другие могут быть установлены по желанию.

1

Таким образом, доставка обновлений с 1 по 2 в режиме реального времени выполняется успешно, и наоборот.

4.MessageChannel

Как следует из названия, информационные каналы. Позволяет нам создать новый канал сообщений и отправлять данные m через два его свойства MessagePort и доступен в Web Worker. Его можно распечатать на консоли и обнаружить, что есть два атрибута, portl1 и port2. Этот метод чаще всего используется, когда страница встроена в iframe.

Точно так же, как канал, который входит и выходит, мы можем добавить третий параметр в метод postmessage:

var channel = new MessageChannel();
channel.port1.addEventListener("message", function(e){
    window.parent.postMessage(e,'*',[channel.port2]);
    channel = null;
});

глубокая копия

n разных типов объектов? Ссылки на кольца? Как сделать особенно простую глубокую копию?

Однако получилось:

var obj ={a:1,b:2,c:{d:3,e:[{f:1,g:2}]},h:null}
obj.h = obj
var res 
new Promise(resolve => {
    var channel = new MessageChannel();
    channel.port2.onmessage = ev => resolve(ev.data);
    channel.port1.postMessage(obj);
  }).then(data=>{res = data})

Данные передаются в конвейер, и конвейер возвращает данные, которые выглядят точно так же, реализуя глубокую копию. Мы называем это структурированным клонированием, которое обрабатывает циклические зависимости объектов и большинство встроенных объектов. Например, postMessage часто используется при отправке сообщения дочернему окну или WebWorker, чтобы получить данные для обработки, не загрязняя исходные данные.