В настоящее время я загружаю всплывающее окно в стиле лайтбокса, которое загружает его HTML из вызова XHR. Затем это содержимое отображается в «модальном» всплывающем окне с помощью element.innerHTML = content. Это работает как шарм.
В другом разделе этого веб-сайта я использую значок Flickr (http://www.elliotswan.com/2006/08/06/custom-flickr-badge-api-documentation/) для динамической загрузки изображений с Flickr. Это делается с помощью тега script, который загружает javascript flickr, который, в свою очередь, выполняет некоторые статические данные document.write.
Оба они отлично работают, когда включены в HTML. Только при загрузке кода значка Flickr внутри в лайтбокс контент не отображается вообще. Кажется, что использование innerHTML для написания операторов document.write заходит слишком далеко, но я не могу найти никаких подсказок в реализациях javascript (FF2 и 3, IE6 и 7) этого поведения.
Может ли кто-нибудь уточнить, должно ли это работать или не должно работать? Спасибо.



![Безумие обратных вызовов в javascript [JS]](https://i.imgur.com/WsjO6zJb.png)


Могу я сначала получить разъяснения, чтобы убедиться, что я понял проблему?
Вызовы document.write добавят контент в разметку в той точке разметки, в которой они происходят. Например, если вы включаете вызовы document.write в функцию, но вызываете функцию в другом месте, вывод document.write будет происходить в той точке разметки, где функция определенный, а не в называется.
Следовательно, чтобы это работало, все операторы Flickr document.write должны быть частью content в element.innerHTML = content. Это точно так?
Вы можете быстро проверить, должно ли это работать вообще, добавив один простой вызов document.write в контент, установленный как innerHTML, и посмотреть, что он делает:
<script>
var content = "<p>1st para</p><script>document.write('<p>2nd para</p>');</script>"
element.innerHTML = content;
</script>
Если это сработает, концепция document.write, работающего с набором контента как innerHTML элемента, может просто сработать.
Мне кажется, что это не сработает, но проверить концепцию должно быть довольно просто.
Я создал простую тестовую страницу, которая иллюстрирует проблему:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html>
<head>
<meta http-equiv = "Content-type" content = "text/html; charset=utf-8" />
<title>Document Write Testcase</title>
</head>
<body>
<div id = "container">
</div>
<div id = "container2">
</div>
<script>
// This doesn't work!
var container = document.getElementById('container');
container.innerHTML = "<script type='text/javascript'>alert('foo');document.write('bar');</script>";
// This does!
var container2 = document.getElementById('container2');
var script = document.createElement("script");
script.type = 'text/javascript';
script.innerHTML = "alert('bar');document.write('foo');";
container.appendChild(script);
</script>
</body>
</html>
Эта страница предупреждает 'bar' и печатает 'foo', хотя я ожидал, что она также предупредит 'foo' и напечатает 'bar'. Но, к сожалению, поскольку тег script является частью более крупной HTML-страницы, я не могу выделить этот тег и добавить его, как в примере выше. Что ж, я могу, но для этого потребуется сканировать содержимое innerHTML на наличие тегов script и заменять их в строке заполнителями, а затем вставлять их с помощью DOM. Звучит не тривиально.
Итак, вы используете метод DOM для создания элемента script и добавления его к существующему элементу, а затем это приводит к выполнению содержимого добавленного элемента script? Это звучит неплохо.
Вы говорите, что тег скрипта является частью большой HTML-страницы и поэтому не может быть выделен. Вы не можете присвоить тегу скрипта идентификатор и настроить его таргетинг? Я, наверное, упускаю здесь что-то очевидное.
Теоретически да, таким образом я могу выделить тег скрипта. Проблема в том, что у нас потенциально могут быть десятки ситуаций, когда это происходит, поэтому я пытаюсь найти причину или документацию такого поведения.
Кроме того, тег script, похоже, больше не является частью DOM после загрузки. В нашей среде мой div container остается пустым, поэтому я не могу получить тег script. Тем не менее, это должно сработать, потому что в моем примере выше скрипт не выполняется, но по-прежнему является частью DOM.
document.write уже устарел. Однако благодаря чудесам JavaScript вы можете просто назначить свою собственную функцию методу write объекта document, который использует innerHTML для элемента по вашему выбору для добавления предоставленного содержимого.
Да, но flickr использует document.write в своем API, и мне действительно нужен контент в том месте, где находится скрипт. Я не могу изменить API, и изменение написанного элемента не решит проблему.
Обычно теги скрипта не выполняются при использовании innerHTML. В вашем случае это хорошо, потому что вызов document.write сотрет все, что уже есть на странице. Однако это оставляет вас без того HTML, который должен был добавить document.write.
Методы манипулирования HTML в jQuery будут выполнять сценарии в HTML за вас, трюк состоит в том, чтобы захватить вызовы document.write и получить HTML в нужном месте. Если это достаточно просто, то подойдет что-то вроде этого:
var content = '';
document.write = function(s) {
content += s;
};
// execute the script
$('#foo').html(markupWithScriptInIt);
$('#foo .whereverTheDocumentWriteContentGoes').html(content);
Однако это становится сложным. Если скрипт находится в другом домене, он будет загружен асинхронно, поэтому вам придется подождать, пока он не будет готов, чтобы получить контент. Кроме того, что, если он просто запишет HTML в середину фрагмента без элемента-оболочки, который вы можете легко выбрать? writeCapture.js (полное раскрытие: это я написал) решает все эти проблемы. Я бы рекомендовал просто использовать его, но, по крайней мере, вы можете посмотреть на код, чтобы увидеть, как он все обрабатывает.
Обновлено: Вот страница, демонстрирующий, как звучит желаемый эффект.
Интересно ... Я также разработал замену для document.write, чтобы разрешить динамическую загрузку скриптов: bezen.domwrite (bezen.org/javascript)
Спасибо! Некоторое время назад мы работали над этим, но это выглядит выполнимым!
Это действительно умное решение. Сохранено для справки!
Используйте document.writeln(content); вместо document.write(content).
Однако лучший метод - использовать конкатенацию innerHTML, например:
element.innerHTML += content;
Метод element.innerHTML = content; заменит старое содержимое новым, что перезапишет innerHTML вашего элемента!
В то время как использование оператора += в element.innerHTML += content добавит ваш текст после старого содержимого. (аналогично тому, что делает document.write.)
«Вывод document.write будет происходить в том месте разметки, где функция определена, а не там, где она вызывается». - Неправда, у меня есть тестовая страница, подтверждающая это: jsbin.com/inuka