Не могу добавить элемент <script>


276

Любая идея, почему фрагмент кода ниже не добавляет элемент сценария в DOM?

var code = "<script></script>";
$("#someElement").append(code);

4
определить «не работает» - хотя я подозреваю, что проблема в том, что сценарии на самом деле не являются частью дерева dom.
Джоэл Коухорн

1
Держу пари, что узел сценария добавляется в DOM, но браузер просто не выполняет сценарий.
Outlaw Programmer

Дэн, как ты на самом деле это проверил?
Джеймс

1
@Joel - "не работает" = это не имеет никакого эффекта, т.е. код в скрипте не выполняется @Outlaw Programmer - узел не добавлен в DOM @Jimmy Да, я проверил его, и он не работает
Дэн Burzo

Ответы:


259

Я видел проблемы, когда некоторые браузеры не учитывают некоторые изменения, когда вы делаете их напрямую (я имею в виду создание HTML из текста, как вы пытаетесь с помощью тега script), но когда вы делаете их с помощью встроенных команд дела идут лучше. Попробуй это:

var script = document.createElement( 'script' );
script.type = 'text/javascript';
script.src = url;
$("#someElement").append( script );

От: JSON для jQuery


18
Тег <script> необходимо добавить в сам DOM, а не в innerHTML существующего элемента.
Диодей - Джеймс Макфарлейн,

6
@Diodeus innerHTML является частью DOM и анализируется браузером на лету, так что это верный случай.
Кристиан Тома


5
Не просто используйте приложение jQuery, если вы действительно хотите, чтобы элемент появился в DOM. Используйте родной appendChild для достижения этой цели.
Minqi Pan

8
$("#someElement")[0].appendChild( script );
Минки Пан

352

Хорошая новость:

Это на 100% работает.

Просто добавьте что-нибудь внутри тега script, например alert('voila!');. Правильный вопрос, который вы, возможно, захотите задать, возможно, «Почему я не видел его в DOM?» ,

Карл Сведберг сделал приятное объяснение комментарию посетителя на сайте jQuery API . Я не хочу повторять все его слова, вы можете прочитать прямо здесь, здесь (мне было трудно ориентироваться в комментариях там) .

Все методы вставки jQuery используют функцию domManip для очистки / обработки элементов до и после их вставки в DOM. Одна из функций, которую выполняет функция domManip, - это извлекать любые элементы сценария, которые собираются вставить, и запускать их через «подпрограмму evalScript», а не вставлять их с остальным фрагментом DOM. Он вставляет сценарии отдельно, оценивает их, а затем удаляет их из DOM.

Я считаю, что одной из причин, по которой jQuery делает это, является предотвращение ошибок «Permission Denied», которые могут возникать в Internet Explorer при вставке сценариев при определенных обстоятельствах. Это также позволяет избежать повторной вставки / оценки одного и того же сценария (который потенциально может вызвать проблемы), если он находится внутри содержащего элемента, который вставляется, а затем перемещается по DOM.

Следующее, я подведу итог плохих новостей, используя .append()функцию для добавления скрипта.


И плохие новости это ..

Вы не можете отлаживать свой код.

Я не шучу, даже если вы добавите debugger;ключевое слово между строкой, которую вы хотите установить в качестве точки останова, вы в конечном итоге получите только стек вызовов объекта, не увидев точку останова в исходном коде (не говоря уже о том, что это ключевое слово работает только в браузере webkit, во всех других основных браузерах это ключевое слово отсутствует) .

Если вы полностью понимаете, что делает ваш код, то это будет незначительным недостатком. Но если вы этого не сделаете, вы в конечном итоге добавите debugger;ключевое слово повсеместно, просто чтобы выяснить, что не так с вашим (или моим) кодом. В любом случае, есть альтернатива, не забывайте, что javascript может манипулировать HTML DOM.


Обходной путь.

Используйте JavaScript (не JQuery) для управления HTML DOM

Если вы не хотите терять возможность отладки, тогда вы можете использовать нативную манипуляцию HTML DOM на JavaScript. Рассмотрим этот пример:

var script   = document.createElement("script");
script.type  = "text/javascript";
script.src   = "path/to/your/javascript.js";    // use this for linked script
script.text  = "alert('voila!');"               // use this for inline script
document.body.appendChild(script);

Вот оно, как в старые добрые времена, не так ли? И не забывайте очищать вещи в DOM или в памяти для всех объектов, на которые ссылаются и которые больше не нужны, чтобы предотвратить утечки памяти. Вы можете рассмотреть этот код, чтобы очистить вещи:

document.body.removechild(document.body.lastChild);
delete UnusedReferencedObjects; // replace UnusedReferencedObject with any object you created in the script you load.

Недостаток этого обходного пути заключается в том, что вы можете случайно добавить дубликат сценария, и это плохо. Отсюда вы можете слегка имитировать .append()функцию, добавив проверку объекта перед добавлением и удалив сценарий из DOM сразу после его добавления. Рассмотрим этот пример:

function AddScript(url, object){
    if (object != null){
        // add script
        var script   = document.createElement("script");
        script.type  = "text/javascript";
        script.src   = "path/to/your/javascript.js";
        document.body.appendChild(script);

        // remove from the dom
        document.body.removeChild(document.body.lastChild);
        return true;
    } else {
        return false;
    };
};

function DeleteObject(UnusedReferencedObjects) {
    delete UnusedReferencedObjects;
}

Таким образом, вы можете добавить скрипт с возможностью отладки, в то же время не допуская дублирования скриптов. Это всего лишь прототип, вы можете расширить его так, как хотите. Я использовал этот подход и вполне доволен этим. Конечно же, я никогда не буду использовать jQuery .append()для добавления скрипта.


2
Отличное объяснение, спасибо! Но был ли "UnusedReferencedObjects"?
Acme

Спасибо. Я предполагаю, что вы имели в виду первое появление «UnusedReferencedObjects», которое должно быть любым объектом, который вы создали в скрипте, который вы загружаете. Я думаю, вы лучше поймете, что если вы видите, что делает функция DeleteObject, она просто удаляет любой объект, который вы передали в функцию. Я добавлю некоторые комментарии в коде, чтобы быть понятным. :)
Хендра Узия

Супер пост! Пример aCrosman у меня не сработал, и после того, как я подготовил ваш пост, я заменил $ ("# someElement"). Append (script); с $ ("# someElement") [0] .appendChild (script); Который исправил это :) Спасибо за объяснение
Мартен Кифт

7
$.getScriptвстроен в JQuery.
zzzzBov

SourceURLs ( blog.getfirebug.com/2009/08/11/… ) могут помочь с проблемами отладки.
Всевик

23

Можно динамически загрузить файл JavaScript с помощью функции jQuerygetScript

$ .getScript ('http://www.whwhat.com/shareprice/shareprice.js', function () {
  Display.sharePrice ();
});

Теперь будет вызываться внешний скрипт, и если он не может быть загружен, он будет постепенно ухудшаться.


7
Это ничего не вставляет в DOM. Это звонки eval().
nh2

20

Что значит "не работает"?

jQuery обнаруживает, что вы пытаетесь создать элемент SCRIPT, и автоматически запускает содержимое элемента в глобальном контексте. Вы говорите мне, что это не работает для вас? -

$('#someElement').append('<script>alert("WORKING");</script>');

Изменить: Если вы не видите элемент SCRIPT в DOM (например, в Firebug) после запуска команды, потому что jQuery, как я уже сказал, запустит код и затем удалит элемент SCRIPT - я считаю, что элементы SCRIPT всегда добавляются к телу ... но в любом случае - размещение не имеет абсолютно никакого отношения к выполнению кода в этой ситуации.


17

Это работает:

$('body').append($("<script>alert('Hi!');<\/script>")[0]);

Кажется, что jQuery делает что-то умное со скриптами, поэтому вам нужно добавить элемент html, а не объект jQuery.


2
Это единственное решение, которое работает в моем случае. Другие вышеупомянутые решения зависят от кода javascript, присутствующего заранее в html-файле. Поскольку я добавляю код динамически, такой код javascript не может быть известен заранее! СПАСИБО Дарвин !!
tgoneil

14

Попробуйте это может быть полезно:

var fileref=document.createElement('script');
fileref.setAttribute("type","text/javascript");
fileref.setAttribute("src","scriptAnalytics.js");
document.getElementsByTagName("head")[0].appendChild(fileref);

9
Понятия не имею, почему этот парень отрицает, что он единственный, кто не настолько глуп, чтобы продолжать использовать jquery для всего!
SSpoke

Вероятно, большинство ответов использует jQuery, потому что в этом вопросе OP использует jQuery.
Санбор

3

Я хочу сделать то же самое, но добавить тег сценария в другой кадр!

var url = 'library.js'; 
var script = window.parent.frames[1].document.createElement('script' ); 
script.type = 'text/javascript'; 
script.src = url;
$('head',window.parent.frames[1].document).append(script);

3
<script>
    ...
    ...jQuery("<script></script>")...
    ...
</script>

</script>В строковых литералов Завершает весь сценарий, чтобы избежать этого , "</scr" + "ipt>"можно использовать вместо.


Или не вставляйте свой JavaScript прямо в HTML-документ. Внешние файлы сценариев не имеют этой проблемы.
Ян Клелланд

Побег последовательности: "\x3cscript\x3e\x3c/script\x3e". В XHTML вам нужно только вставить закомментированный блок CDATA.
Эли Грей

2
Скорее </, это не разрешено. См. Stackoverflow.com/questions/236073/…
Гамбо

2

Добавление sourceURL в файл сценария помогло, как упоминалось на этой странице: https://blog.getfirebug.com/2009/08/11/give-your-eval-a-name-with-sourceurl/

  1. В файле сценария добавьте оператор с sourceURL, например "// @ sourceURL = foo.js"
  2. Загрузите скрипт с помощью jQuery $ .getScript (), и скрипт будет доступен на вкладке «sources» в инструментах Chrome Dev

1

Ваш скрипт выполняется, вы просто не можете использовать document.writeего. Используйте предупреждение, чтобы проверить его и избегать использования document.write. Операторы вашего js-файла с document.writeне будут выполнены, а остальные функции будут выполнены.


1

Это то, что я считаю лучшим решением. Google Analytics вводится таким образом.

var (function(){
    var p="https:" == document.location.protocol ? "https://" : "http://";
        d=document,
        g=d.createElement('script'),
        s=d.getElementsByTagName('script')[0];
        g.type='text/javascript';
        g.src=p+'url-to-your-script.js';
        s.parentNode.insertBefore(g,s); })();

1

Вам не нужен jQuery для создания DOM-элемента Script . Это можно сделать с помощью vanilla ES6 примерно так:

const script = "console.log('Did it work?')"
new Promise((resolve, reject) => {
  (function(i,s,o,g,r,a,m){
      a=s.createElement(o),m=s.getElementsByTagName(o)[0];
      a.innerText=g;
      a.onload=r;m.parentNode.insertBefore(a,m)}
  )(window,document,'script',script, resolve())
}).then(() => console.log('Sure did!'))

Его не нужно переносить в a Promise, но это позволяет разрешить обещание при загрузке сценария, что помогает предотвратить состояние гонки для долго выполняющихся сценариев.



0

Другой способ сделать это, если вы хотите добавить код, - использовать document.createElementметод, но затем использовать .innerHTMLвместо .src.

var script = document.createElement( 'script' );
script.type = 'text/javascript';
script.innerHTML = 'alert("Hey there... you just appended this script to the body");';
$("body").append( script );

0

Я попробовал это одно и работает отлично. Просто замените <символ этим \x3C.

// With Variable
var code = "\x3Cscript>SomeCode\x3C/script>";
$("#someElement").append(code);

или

//Without Variable
$("#someElement").append("\x3Cscript>SomeCode\x3C/script>");

Вы можете проверить код здесь .


0

Можно попробовать вот так

var code = "<script></" + "script>";
$("#someElement").append(code);

Единственная причина, по которой вы не можете этого сделать, "<script></script>"заключается в том, что строка не разрешена внутри javascript, потому что слой DOM не может анализировать, что такое js и что такое HTML.


0

Я написал npmпакет, который позволяет вам взять строку HTML, включая теги сценария, и добавить ее в контейнер при выполнении сценариев.

Пример:

import appendHtml from 'appendhtml';

const html = '<p>Hello</p><script src="some_js_file.js"></script>'; 
const container = document.getElementById('some-div');

await appendHtml(html, container);

// appendHtml returns a Promise, some_js_file.js is now loaded and executed (note the await)

Найдите его здесь: https://www.npmjs.com/package/appendhtml


-1

Просто создайте элемент, проанализировав его с помощью jQuery.

<div id="someElement"></div>
<script>
    var code = "<script>alert(123);<\/script>";
    $("#someElement").append($(code));
</script>

Рабочий пример: https://plnkr.co/edit/V2FE28Q2eBrJoJ6PUEBz


Это все еще та же проблема, некоторые браузеры не уважают это.
Мартин Массера

Не могли бы вы сообщить мне, какие браузеры и какую версию jQuery вы используете? Спасибо!
Санбор
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.