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 по 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, чтобы получить данные для обработки, не загрязняя исходные данные.