Динамическая вставка javascript в HTML, который использует document.write

В настоящее время я загружаю всплывающее окно в стиле лайтбокса, которое загружает его 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) этого поведения.

Может ли кто-нибудь уточнить, должно ли это работать или не должно работать? Спасибо.

Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
18
0
25 908
7
Перейти к ответу Данный вопрос помечен как решенный

Ответы 7

Могу я сначала получить разъяснения, чтобы убедиться, что я понял проблему?

Вызовы 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 элемента, может просто сработать.

Мне кажется, что это не сработает, но проверить концепцию должно быть довольно просто.

«Вывод document.write будет происходить в том месте разметки, где функция определена, а не там, где она вызывается». - Неправда, у меня есть тестовая страница, подтверждающая это: jsbin.com/inuka

vsync 24.09.2009 23:09

Я создал простую тестовую страницу, которая иллюстрирует проблему:

<!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, и изменение написанного элемента не решит проблему.

Kamiel Wanrooij 10.09.2008 18:05
Ответ принят как подходящий

Обычно теги скрипта не выполняются при использовании 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)

Eric Bréchemier 08.12.2009 01:27

Спасибо! Некоторое время назад мы работали над этим, но это выглядит выполнимым!

Kamiel Wanrooij 11.12.2009 17:48

Это действительно умное решение. Сохранено для справки!

hybernaut 07.11.2010 00:09

Используйте document.writeln(content); вместо document.write(content).

Однако лучший метод - использовать конкатенацию innerHTML, например:

element.innerHTML += content;

Метод element.innerHTML = content; заменит старое содержимое новым, что перезапишет innerHTML вашего элемента!

В то время как использование оператора += в element.innerHTML += content добавит ваш текст после старого содержимого. (аналогично тому, что делает document.write.)

Другие вопросы по теме