Дочерние документы не могут самостоятельно читать данные из родительского фрейма, если тот находится на другом домене. Возможны исключения для под-доменов одного и того же доменного имени.
Все это связано с мерами безопасности и т.п. чепухи. :). Для преодоления данных ограничений я использую обмен сообщениями между фреймами. Особенности данного подхода мы и рассмотрим в данной статье.
Допустим, у вас есть родительское окно с фреймом.
Отправка данных из фрейма в родительское окно.
Упакуйте нужные данные в объект и отправьте их window.parent.
1 2 3 4 5 |
var data = { par1: value1, ... } window.parent.postMessage(data, '*'); |
Теперь данные нужно как то поймать в родительском окне.
Получение сообщения от фрейма в родительском окне.
Суть стоит в добавлении обработчика события ‘message’. В нем нас будет интересовать параметр event.originalEvent.data — с отправленными нам данными.
Для сокращения синтаксиса, воспользуюсь jQuery:
1 2 3 4 |
$(window).on('message', function(e) { var data = e.originalEvent.data; // далее идет какая то обработка полученных данных }); |
Как видите, пока все очень просто.
Теперь рассмотрим что делать, если нам понадобится отправить сообщение (к примеру, результат обработки данных) обратно в дочерний фрейм?
Рассылка сообщений по дочерним фреймам.
Первая проблема — мы не знаем откуда (из какого фрейма) пришло сообщение. Вторая состоит в том, что и другие под-программы вашего сайта (3d part скрипты, сервисы сбора статистики) могут отправлять сообщения, и ваш обработчик будет их также перехватывать. Это вам предстоит учесть самим.
Как решить первую проблему?
В пакет с данными можно добавить какой то идентификатор, по которому определять откуда отправлен запрос. Это один из вариантов.
Второй вариант состоит в том, чтобы разослать ответное сообщение всем дочерним фреймам, а те уже сами разберутся, что им делать с пакетом данных.
Нужно учесть, что :
- Некоторые сообщения могут не требовать ответа,
- Запросы могут иметь разное назначение и т.д.
Предлагаю взглянуть на следующий прототип API обмена сообщениями.
В родительском окне размещаем скрипт такого вида:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
$(window).on('message', function(e) { // данные data = e.originalEvent.data; // требуется ли ответ data.reply = false; // обработка разных кодов запросов switch(data.code) { case 'name-of-operation': // пусть эта операция требует ответа // мы дополним данные какими то значениями data.result = '...'; // установим флаг, что требует рассылка ответа data.reply = true; break; case 'other-operation': // какие то действия break; } // рассылка ответа во все фреймы if (data.reply) { for (var i = 0; i < window.frames.length; i++) { window.frames[i].postMessage(data, '*'); }; } }); |
На стороне iframe придется организовать обработку события message аналогично как и на стороне родительского окна.
А при отправке запросов надо указывать коды операции:
1 2 3 4 5 6 |
var data = { code: 'name-of-operation', // какие то данные ... } window.parent.postMessage(data, '*'); |