Динамическая вставка javascript в HTML, который использует document.write
В настоящее время я загружаю всплывающее окно в стиле лайтбокса, которое загружает HTML-код из вызова XHR. Затем это содержимое отображается во всплывающем окне "modal", используя 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) этого поведения.
Может ли кто-нибудь уточнить, должно ли это работать или не должно работать? Спасибо.
Ответы
Ответ 1
В общем случае теги script не выполняются при использовании innerHTML. В вашем случае это хорошо, потому что вызов document.write
уничтожит все, что уже на странице. Однако это оставляет вас без добавления HTML document.write.
jQuery Методы манипуляции HTML будут выполнять скрипты в HTML для вас, трюк затем захватывает вызовы document.write
и получает HTML в нужном месте. Если это достаточно просто, то что-то вроде этого будет делать:
var content = '';
document.write = function(s) {
content += s;
};
// execute the script
$('#foo').html(markupWithScriptInIt);
$('#foo .whereverTheDocumentWriteContentGoes').html(content);
Все усложняется. Если script находится в другом домене, он будет загружен асинхронно, поэтому вам придется подождать, пока это не будет сделано для получения содержимого. Кроме того, что, если он просто записывает HTML в середину фрагмента без элемента оболочки, который вы можете легко выбрать? writeCapture.js (полное раскрытие: я написал) обрабатывает все эти проблемы. Я бы рекомендовал просто использовать его, но, по крайней мере, вы можете посмотреть на код, чтобы увидеть, как он обрабатывает все.
EDIT: страница, показывающая, что похоже на эффект, который вы хотите.
Ответ 2
Я создал простую тестовую страницу, которая иллюстрирует проблему:
<!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>
Эта страница предупреждает "бар" и печатает "foo", в то время как я ожидал, что он также предупредит "foo" и напечатает "bar". Но, к сожалению, поскольку тег script
является частью большей HTML-страницы, я не могу выделить этот тег и добавить его, как в примере выше. Ну, я могу, но для этого потребуется сканировать innerHTML
контент для тегов script
и заменить их в строке заполнителями, а затем вставить их с помощью DOM. Звучит не так тривиально.
Ответ 3
Использовать document.writeln(content);
вместо document.write(content)
.
Тем не менее, лучший способ - использовать конкатенацию innerHTML
, например так:
element.innerHTML += content;
element.innerHTML = content;
Метод заменит старый контент новым, который перезапишет ваш элемент innerHTML!
Принимая во внимание, что использование оператора +=
в element.innerHTML += content
добавит ваш текст после старого содержимого. (аналогично тому, что делает document.write
.)
Ответ 4
document.write
примерно так же устарел, как и они. Благодаря чудесам JavaScript вы можете просто назначить свою собственную функцию методу write
объекта document
, который использует innerHTML
для выбранного вами элемента, чтобы добавить поставляемый контент.
Ответ 5
Могу ли я получить некоторое разъяснение, чтобы убедиться, что у меня проблема?
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
элемента, может просто работать.
У меня такое чувство, что это не сработает, но для проверки концепции должно быть довольно просто.
Ответ 6
Итак, вы используете метод DOM для создания элемента script
и добавляете его к существующему элементу, и это приводит к тому, что содержимое добавляемого элемента script
выполняется? Это звучит хорошо.
Вы говорите, что тег script является частью большей HTML-страницы и поэтому не может быть выделен. Можете ли вы дать тегу script идентификатор и настроить его? Я, вероятно, не вижу здесь ничего очевидного.
Ответ 7
В теории, да, я могу выделить тег script таким образом. Проблема в том, что у нас потенциально есть десятки ситуаций, когда это происходит, поэтому я пытаюсь найти какую-то причину или документацию по этому поведению.
Кроме того, тег script
, по-видимому, не является частью DOM после его загрузки. В нашей среде мой div container
остается пустым, поэтому я не могу получить тег script
. Это должно сработать, потому что в моем примере выше script не выполняется, но все еще является частью DOM.