Динамическая вставка JavaScript в HTML, использующий document.write.
-
09-06-2019 - |
Вопрос
В настоящее время я загружаю всплывающее окно в стиле лайтбокса, которое загружает HTML из вызова XHR.Затем этот контент отображается в «модальном» всплывающем окне с помощью element.innerHTML = content
Это работает как шарм.
В другом разделе этого сайта я использую «значок» Flickr (http://www.elliotswan.com/2006/08/06/custom-flickr-badge-api-documentation/) для динамической загрузки изображений Flickr.Это делается с помощью тега сценария, который загружает javascript flickr, который, в свою очередь, выполняет некоторые document.write
заявления.
Оба они отлично работают, если включены в HTML.Только при загрузке кода значка flickr внутри лайтбокс, контент вообще не отображается.Кажется, что использование innerHTML
написать document.write
операторы заходят слишком далеко, но я не могу найти никакой подсказки в реализациях javascript (FF2&3, IE6&7) этого поведения.
Может ли кто-нибудь уточнить, должно или не должно это работать?Спасибо.
Решение
Как правило, теги скриптов не выполняются при использовании 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 (полное раскрытие:Я это написал) решает все эти проблемы.Я бы рекомендовал просто использовать его, но, по крайней мере, вы можете посмотреть код, чтобы увидеть, как он со всем справляется.
РЕДАКТИРОВАТЬ:Вот страница демонстрируя, как звучит желаемый эффект.
Другие советы
Я создал простую тестовую страницу, которая иллюстрирует проблему:
<!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.Звучит не что тривиально.
Использовать document.writeln(content);
вместо document.write(content)
.
Однако лучший метод — использовать конкатенацию innerHTML
, так:
element.innerHTML += content;
А element.innerHTML = content;
метод, который заменит старое содержимое новым, он перезапишет InnerHTML вашего элемента!
В то время как +=
оператор в element.innerHTML += content;
добавит ваш текст после старого контента.(как что document.write
делает.)
document.write
примерно так же устарели, как и они.Однако благодаря чудесам JavaScript вы можете просто назначить свою собственную функцию write
метод document
объект, который использует innerHTML
к элементу по вашему выбору, чтобы добавить предоставленный контент.
Могу ли я сначала получить некоторые разъяснения, чтобы убедиться, что я понял проблему?
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
элемента может просто сработать.
Я нутром чувствую, что это не сработает, но протестировать эту концепцию должно быть довольно просто.
Итак, вы используете метод DOM для создания script
элемент и добавьте его к существующему элементу, а затем это приведет к тому, что содержимое добавленного элемента script
элемент для выполнения?Это звучит неплохо.
Вы говорите, что тег сценария является частью более крупной HTML-страницы и поэтому не может быть выделен.Можете ли вы не дать тегу сценария идентификатор и настроить его таргетинг?Я, вероятно, упускаю здесь что-то очевидное.
Теоретически да, я могу таким образом выделить тег сценария.Проблема в том, что потенциально у нас есть десятки ситуаций, когда это происходит, поэтому я пытаюсь найти какую-то причину или документацию такого поведения.
Так же script
Тег больше не является частью DOM после загрузки.В нашей среде мой container
div остается пустым, поэтому я не могу получить script
ярлык.Однако это должно сработать, потому что в моем примере выше скрипт не выполняется, но все еще является частью DOM.