Общайтесь между вкладками dom без ссылки на окно

Я использую следующее, чтобы открыть новую вкладку (в новом процессе) с некоторым содержимым страницы,

var p = document.getElementById("myElement"); 
var a = document.createElement('a');
a.setAttribute('href',".../mypage.html");
a.setAttribute('rel',"noreferrer");
a.setAttribute('target',"_blank");
p.appendChild(a);
a.click();

http://news.softpedia.com/news/Force-Google-Chrome-to-Open-Links-in-New-Processes-128962.shtml

Это работает, и новая вкладка открыта с содержимым myPage.html.

Предположим, что это моя страница (только для примера...), как мне получить к ней доступ?

<!DOCTYPE html>
<html>
<body>

<h1> Heading</h1>
<p> paragraph.</p>
 <button type="button">Click Me!</button>

</body>
</html>

Теперь давайте перейдем к сложной/продвинутой части :)...

когда вы используете window.open (который я не могу использовать), это довольно просто, так как вы можете использовать различные методы.

 1. using window object
 2. post message
 https://developer.mozilla.org/en-US/docs/Web/API/Window/postMessage
 3. cookies 
 4. localStorage

Но здесь я открываю эту новую страницу без ссылки, полученной с помощью window.open

Мой вопрос:

Как я могу получить доступ к этой новой вкладке, если я хочу что-то изменить


person John Jerrby    schedule 18.10.2016    source источник
comment
Привет! Ставлю +1 за поиск перед публикацией   -  person Marny Lopez    schedule 18.10.2016
comment
@MarnyA.López - Спасибо :)   -  person John Jerrby    schedule 18.10.2016
comment
Надеюсь, у вас нет проблем с политикой одного и того же происхождения. 1) может ли любая страница быть родительской? 2) нужно отправлять сообщения в обе стороны? (родитель -> ребенок или ребенок -> родитель)   -  person fremail    schedule 18.10.2016
comment
@fremail - В настоящее время у меня нет проблем с доменом ... Мне нужно с дочерней вкладки отправить сообщение на родительскую вкладку, если у вас есть идея, приведите пример, спасибо!   -  person John Jerrby    schedule 18.10.2016
comment
Вы сказали, что не можете использовать API-интерфейс window.open, а затем сказали, что вообще не можете использовать окно? Как так? Просьба избегать XY...   -  person Dan Def    schedule 19.10.2016
comment
Если вы не можете использовать окно (на самом деле это странно!), вы можете проверить изменения localStorage в таймере (setInterval). Это не элегантное решение. Почему вы не можете использовать окно?   -  person fremail    schedule 19.10.2016
comment
@fremail - в chrome, когда вы используете открытое окно и открываете дочернюю вкладку, которую вы видите, и вы отлаживаете дочернюю вкладку, родительская вкладка зависает, проверьте этот пост... stackoverflow.com/questions/39748078/   -  person John Jerrby    schedule 19.10.2016
comment
@DanDef - в chrome, когда вы открываете окно и открываете дочернюю вкладку, которую вы видите, и вы отлаживаете дочернюю вкладку, родительская вкладка зависает, проверьте этот пост ... stackoverflow.com/questions/39748078/…, это не xy :)   -  person John Jerrby    schedule 19.10.2016


Ответы (4)


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

Вот пример того, как его использовать:

//Register a function: 
RegisterLocalStorageFunction("test", function(param){ 
    return param+param; 
});

//Call a function: 
let str = "testing"; 
CallLocalStorageFunction("test",str,function(para){ 
    console.log(para); 
});

В вашем контексте:

RegisterLocalStorageFunction("CallAlert", function(param){ 
    alert(param);
    return "Success"; 
});
var p = document.getElementById("myElement");
var a = document.createElement('a');
a.setAttribute('href',".../mypage.html");
a.setAttribute('rel',"noreferrer");
a.setAttribute('target',"_blank");
p.appendChild(a);
a.click();

В другом окне:

<!DOCTYPE html>
<html>
<body>
<h1> Heading</h1>
<p> paragraph.</p>
<button type="button" onclick="btnClick()">Click Me!</button>
<script>
    function btnclick(){
        CallLocalStorageFunction("CallAlert","Hello from the other tab",function(para){ 
            console.log("para"); 
        });
}
</script>
</body>
</html>

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

Обновить

В репозитории вы можете найти коммуникатор2, основанный на событии «хранение».

Обновить

Вот размещен рабочий пример. Не забудьте разрешить всплывающие окна.

person Astasian    schedule 25.10.2016
comment
Спасибо, было бы здорово, если бы вы могли привести пример с моим контекстом, если вам нужна дополнительная информация... Спасибо! - person John Jerrby; 25.10.2016
comment
Спасибо :), я попробую сейчас и дам вам знать... - person John Jerrby; 25.10.2016
comment
Нет проблем, я рекомендую версию 2. Если у вас есть какие-либо проблемы, просто дайте мне знать. - person Astasian; 25.10.2016
comment
Спасибо, но я не могу использовать версию 2, так как вы используете там окно, а у меня нет объекта окна, так как я использую a.setAttribute('href',.../mypage.html); a.setAttribute('отн.', noreferrer); a.setAttribute('цель',_blank); но может я что-то упускаю... - person John Jerrby; 25.10.2016
comment
Это просто добавление функции в окно. Если вы загрузите библиотеку, вы сможете получить доступ к функциям везде. Это то же самое, если бы вы не делали функции внутренней функцией. Вам не нужен объект окна другого окна, это объект вашего текущего окна. С помощью window.xzy = function(){} вы делаете функцию доступной во всем окне, как и xzy(){}. Но поскольку библиотека находится внутри анонимной функции, мне пришлось вручную прикрепить ее к окну. - person Astasian; 25.10.2016
comment
хорошо, я попробую и дам вам знать :), почему ‹b›!функция‹/b› в начале? - person John Jerrby; 25.10.2016
comment
!функция(){}(); означает, что вы определяете функцию, а затем выполняете ее со следующими параметрами. Другой пример: !function(str){alert(str);}(hello);. Преимущество в том, что не все переменные помещаются в объект окна, что предотвращает конфликты. Поэтому мне пришлось вручную добавить функции к оконному объекту. - person Astasian; 25.10.2016
comment
Спасибо, я попробовал, и у меня это не работает, но, возможно, я делаю что-то не так... не могли бы вы добавить полный код с моим контекстом. у меня есть только две страницы, одна родительская, которая использует a.tag с пустым и no_referr, а вторая - дочерний html, который открывается с заголовком и pragrefh, было бы здорово, если бы вы могли поделиться своим рабочим решением, большое спасибо! !! - person John Jerrby; 25.10.2016
comment
Конечно. Мне нужно уйти на 2 часа, затем я снова подключаюсь и пробую. Спасибо, сэр! - person John Jerrby; 25.10.2016
comment
Я добавил пример. Не забывайте использовать веб-сервер для обслуживания этих файлов. Если вы не используете ни одного, контекст хранения будет другим. Я видел, что вы используете .../mypage.html с тремя точками. Должно быть только 2. И некоторые браузеры могут блокировать всплывающие окна. - person Astasian; 25.10.2016
comment
Спасибо 1+ за ваши усилия и помощь :) что вы имеете в виду использовать веб-сервер и другой контекст? предположим, я хочу изменить, например, из mypage.html, который является дочерним, содержание абзаца в основном, как я могу это сделать, в конце концов это то, что мне нужно сделать... Большое спасибо! - person John Jerrby; 25.10.2016
comment
Ты можешь это сделать. Я привел пример того же представителя на github. Я имею в виду, что с веб-сервером вам нужно запустить apache или iis для обслуживания этих файлов. Если вы получите к ним доступ через локальную файловую систему, это не сработает. - person Astasian; 25.10.2016
comment
Спасибо, я смог запустить этот файл с помощью webstorm..., я не видел пример, как изменить содержимое абзаца? где вы это делаете в коде? пришлите мне ссылку. - person John Jerrby; 25.10.2016
comment
Давайте продолжим обсуждение в чате. - person Astasian; 25.10.2016
comment
Вот рабочий пример: astasian.github.io/LocalStorageFunctionCall - person Astasian; 26.10.2016
comment
Спасибо большое! , не могли бы вы объяснить, почему вы используете окно в (communicator2.js) и есть ли элегантный способ избежать этого? использовать какое-то другое не глобальное свойство? - person John Jerrby; 26.10.2016
comment
Элегантный способ заключается в том, чтобы включить функцию и добавить необходимые функции в объект окна. - person Astasian; 26.10.2016
comment
не могли бы вы привести пример, как? Я думаю, что это плохая практика - использовать окно... - person John Jerrby; 26.10.2016
comment
Плохая практика - иметь все глобально доступное. В коммуникаторе1 все (даже функция сброса) автоматически помещается в объект окна. - person Astasian; 26.10.2016
comment
но в версии 2 у вас все еще есть окно типа window.RegisterLocalStorageFunction, как этого можно избежать? - person John Jerrby; 26.10.2016
comment
Да, но поскольку у нас есть некоторые проблемы с безопасностью при использовании локального хранилища, я пытаюсь проверить, могу ли я использовать sessionStorage, который лучше с точки зрения безопасности, если вы знаете, как заставить его работать с хранилищем сеансов, пожалуйста, дайте мне знать. Большое спасибо! - person John Jerrby; 27.10.2016
comment
Это невозможно с sessionStorage, потому что каждая вкладка имеет свою собственную. Что вас беспокоит? - person Astasian; 27.10.2016
comment
У нас есть эксперт по безопасности, который утверждает об использовании localStorage... в настоящее время мы обсуждаем... 1. Вы уверены на 100%, что это невозможно сделать с хранилищем сеансов? 2. не могли бы вы сказать, почему вы используете заполнитель для строк 11 и 12, зачем это нужно и почему вы используете 8000 мс? - person John Jerrby; 27.10.2016
comment
Привет еще раз, я сделал дополнительный тест, который не работает, сценарий таков: запустить родительский элемент дважды (не закрывая предыдущие две страницы) теперь в новом открытом дочернем элементе (второй) попытаться отправить какое-то значение родителю в текстовое поле, оно не работает, есть идеи? - person John Jerrby; 27.10.2016
comment
Это приводит к зависанию браузера ... и когда я открываю средство просмотра локального хранилища в консоли-> приложение-> локальное хранилище, вы видите, что запись вставляется и удаляется, ничего не делая .... не знаете, как? это заставляет браузер зависать... - person John Jerrby; 27.10.2016
comment
может быть, будет проще увидеть это, дважды запустите индексную страницу, теперь у вас открыто 4 вкладки, нажмите «Закрыть», это закроет оба окна, что плохо. Я хочу, чтобы каждый родитель закрыл свое окно... - person John Jerrby; 27.10.2016
comment
так как мне это нужно для производства, я провожу много тестов, чтобы увидеть, действительно ли я могу его использовать, иначе это просто POC, который я могу использовать в производстве, и он мне не помогает ... - person John Jerrby; 27.10.2016
comment
Мне нужно как-то, чтобы каждое родительское и дочернее окно имело свою собственную область (возможно, по какому-то индексу...) - person John Jerrby; 27.10.2016
comment
Спасибо, может быть, с хранилищем сессий? Мне нужно выйти из офиса, так что не торопитесь, давайте продолжим. завтра :) хорошего дня и спасибо за ваше время и усилия - person John Jerrby; 27.10.2016
comment
Привет снова :) Я знаю, что это сложно, но для меня большая проблема использовать эту строку, a.setAttribute('href', child.html + '#' +sessionStorage.getItem('winId')); , есть способ как-то этого избежать? кроме того, если вы открываете 3 index.html один за другим и пытаетесь закрыть из него Childs, работает только последний index.html... есть идеи, как это решить? - person John Jerrby; 28.10.2016
comment
Это еще не работает. Это была просто попытка с sessionStorage. После документа он будет уничтожен после перезагрузки, поэтому мы не сможем его использовать. я готов к этому - person Astasian; 28.10.2016
comment
Кстати, есть способ как-то сделать всю эту логику из коммуникатора и с минимальным или вообще кодом в индексе и myPage, я знаю, что это не тривиально, но, возможно, такой эксперт, как вы, может дать хорошее решение. - person John Jerrby; 28.10.2016
comment
Большое спасибо, эксперт, не торопитесь :), мне нужно лучшее решение, чем более быстрое решение .... - person John Jerrby; 28.10.2016
comment
en.m.wikipedia.org/wiki/Minification_(programming). Но технически я ответил на ваш вопрос. Пожалуйста, прими это, я все равно помогу тебе. - person Astasian; 28.10.2016
comment
Что это за ссылка, не уверен, что попал... - person John Jerrby; 28.10.2016
comment
Запись в Википедии для минификации - person Astasian; 28.10.2016
comment
хорошо, я вижу это, но как это связано? - person John Jerrby; 28.10.2016
comment
У вас есть какое-то направление? - person John Jerrby; 28.10.2016
comment
Вы думали, что хотите свернуть файл? Ваш сайт должен быть статичным, когда вы хотите поместить свой код в индекс и т. д., в противном случае просто минимизируйте его, тогда он все еще может быть кэширован. - person Astasian; 28.10.2016
comment
Ах, хорошо, конечно, у нас есть сборка, которая справляется с этим, но это другая тема... с этой темой я справлюсь :) - person John Jerrby; 28.10.2016
comment
Давайте продолжим обсуждение в чате. - person John Jerrby; 28.10.2016
comment
Привет Еще раз, да, я проверю это сейчас. - person John Jerrby; 28.10.2016
comment
Конечно сделал как и обещал! :) У меня есть несколько дополнительных мелких вопросов... - person John Jerrby; 31.10.2016
comment
Конечно Через несколько минут - person John Jerrby; 31.10.2016

JavaScript родительской страницы:

var lastMessage;
setInterval(function() {
  var message = localStorage.getItem('message-to-parent');
  if (message && message !== lastMessage) {
    lastMessage = message;
    // your code here
    alert('There is a new message for you: ' + message);
  }
}, 100);

JavaScript дочерней страницы:

localStorage.setItem('message-to-parent', 'hello, my parent!');

Если у вас много анимаций и другого большого кода JS, я бы посоветовал увеличить интервал таймера, а лучше решить проблему с помощью window.

person fremail    schedule 18.10.2016
comment
Спасибо, как это решение будет работать в браузере, я имею в виду производительность или нагрузку на него... - person John Jerrby; 19.10.2016
comment
@JohnJerrby Таймер добавит задание (функция обратного вызова) для проверки сообщения с задержкой в ​​100 мс, но проблема в том, что это задание может запуститься позже, чем через 100 мс. Подробнее о таймерах JS читайте здесь ejohn.org/blog/how-javascript-timers-work Если вы используете задержку 100 мс или больше и функция обратного вызова для интервала проста (как мой код), вы можете быть спокойны за производительность. - person fremail; 19.10.2016
comment
Спасибо ! , Я не уверен, что смогу использовать это решение, поскольку оно ненадежно... (как говорит ссылка, которую вы разместили...), как вы думаете, есть ли другое решение, которое я могу использовать? - person John Jerrby; 19.10.2016
comment
@JohnJerrby Вы пытались использовать это решение? stackoverflow.com/a/28230846/3816979 - person fremail; 19.10.2016
comment
Я прочитал этот пост (я поставил ссылку на свой вопрос), но там есть окно $(window).on('storage', message_receive); , Есть способ связать его с чем-то другим? Если да, то это может быть здорово, и я могу его использовать... - person John Jerrby; 19.10.2016
comment
Я не знаю, как им пользоваться без window - person fremail; 20.10.2016

Вы должны подключить прослушиватель DOMNodeInserted до того, как будет запущено событие click, после чего вы сможете получить доступ к этому объекту окна.

// assuming that all inserted alements are links or a-tags
// this code must run before the code that adds the a-element
document.addEventListener("DOMNodeInserted", function (ev) {
      var link = ev.target;
      var oldRef = link.href;
      link.onclick = function(event){
        event.preventDefault();
        var childWindow = window.open(oldRef);
        childWindow.onload = function(){
          console.log('at this point you can interact with this newly opened window-object: ',childWindow);
        };
      };
});

//...
// some other code
//...

var p = document.getElementById("myElement"); 
var a = document.createElement('a');
a.setAttribute('href',".../mypage.html");
a.setAttribute('rel',"noreferrer");
a.setAttribute('target',"_blank");
p.appendChild(a);
a.click();

Надеюсь это поможет.

person Blauharley    schedule 25.10.2016
comment
Спасибо, но я не могу открыть окно... :( Я могу использовать только тег a.tag... - person John Jerrby; 25.10.2016
comment
Пожалуйста, попробуйте это :) - person Blauharley; 25.10.2016

Вы можете использовать SharedWorker для связи между различными контекстами просмотра.

См. Можем ли мы ссылаться на переменные javascript через веб-страницы в сеансе браузера?

В качестве альтернативы вы можете использовать событие storage Можно ли изменить механизм загрузки рабочего процесса в Shared Web Workers?

person guest271314    schedule 29.10.2016