Неможливо додати елемент <script>


276

Будь-яка ідея, чому фрагмент коду нижче не додає елемент сценарію до DOM?

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

4
визначте "не працює" - хоча я підозрюю, що проблема полягає в тому, що сценарії насправді не є частиною дерева dom.
Joel Coehoorn

1
Моя справа в тому, що вузол сценарію додається до DOM, але браузер просто не виконує сценарій.
Програматор поза законом

Ден, як ти насправді це випробував?
Джеймс

1
@Joel - «не працює» = це не має ніякого ефекту, тобто код в сценарії не виконується @Outlaw Програміст - вузол не додається в DOM @Jimmy Так, я перевірив його і він не працює
Dan Бурцо

Відповіді:


259

Я бачив проблеми, коли деякі веб-переглядачі не поважають деяких змін, коли ви робите їх безпосередньо (під якими я маю на увазі створення HTML з тексту, як ви намагаєтеся з тегом сценарію), але коли ви робите їх із вбудованими командами справи йдуть краще. Спробуйте це:

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

Від: JSON для jQuery


18
Тег <script> потрібно додати до самого DOM, а не до внутрішньогоHTML існуючого елемента.
Діод - Джеймс Макфарлайн

6
@Diodeus innerHTML є частиною DOM, і він розбирається на ходу браузером, тому це дійсний випадок.
Крістіан Тома


5
Не використовуйте просто додаток jQuery, якщо ви дійсно хочете, щоб елемент з’явився у DOM. Для цього використовуйте нативний додатокChild.
Пан Minqi

8
$("#someElement")[0].appendChild( script );
Minqi Pan

352

Хороша новина:

Це на 100% працює.

Просто додайте щось всередині тегу сценарію, наприклад alert('voila!');. Можливо, ви, можливо, захочете поставити правильне запитання: "Чому я цього не бачив у DOM?" .

Карл Сведберг зробив приємне пояснення до коментаря відвідувача на сайті API jQuery . Я НЕ хочу повторювати все його слова, ви можете прочитати прямо тут тут (я знайшов його важко переміщатися з коментарів там) .

Усі методи вставки jQuery використовують внутрішню функцію domManip для очищення / обробки елементів до та після того, як вони вставляються в DOM. Однією з речей, яку виконує функція domManip, є витягнути будь-які елементи скрипту, які збираються вставити, та запустити їх через "процедуру evalScript", а не вставити їх з рештою фрагмента DOM. Він вставляє сценарії окремо, оцінює їх, а потім видаляє їх з DOM.

Я вважаю, що одна з причин jQuery робить це уникнути помилок "Відмовлено у дозволі", які можуть виникнути в Internet Explorer під час вставки скриптів за певних обставин. Це також дозволяє уникнути повторного вставлення / оцінки одного і того ж сценарію (що потенційно може спричинити проблеми), якщо він знаходиться в складі елемента, який ви вставляєте, а потім пересуваєтеся по DOM.

Наступне - я підсумую погані новини, використовуючи .append()функцію для додавання сценарію.


І погані новини ...

Ви не можете налагоджувати код.

Я не жартую, навіть якщо ви додасте debugger;ключове слово між рядком, який ви хочете встановити як точку розриву, ви в кінцевому підсумку отримаєте лише стек виклику об'єкта, не побачивши точки вихідного коду у вихідному коді (не кажучи вже про це ключове слово працює тільки в браузері WebKit, всі інші основні браузери , здається, опустять це ключове слово) .

Якщо ви повністю розумієте, що робить ваш код, це буде незначним недоліком. Але якщо ви цього не зробите, ви в кінцевому підсумку додасте debugger;ключове слово, щоб дізнатись, що не так у вашому (або моєму) коді. У будь-якому випадку є альтернатива, не забувайте, що JavaScript може власним чином маніпулювати HTML DOM.


Обхід.

Використовуйте javascript (не jQuery) для маніпулювання HTML DOM

Якщо ви не хочете втрачати можливість налагодження, тоді ви можете використовувати маніпуляції з власним HTML-кодом HTML DOM. Розглянемо цей приклад:

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"?
акме

Дякую. Я припускаю, що ви мали на увазі перше виникнення "UnusedReferencedObjects", який повинен бути будь-яким об'єктом, який ви створили в завантажуваному сценарії. Я думаю, ви краще зрозумієте, якщо ви бачите, що робить функція DeleteObject, вона просто видалить будь-який об’єкт, який ви передали функції. Я додам трохи коментаря в код, щоб було зрозуміло. :)
Хендра Узія

Супер пост! Приклад aCrosman не працював для мене, і після підготовки вашої публікації я замінив $ ("# someElement"). Append (script); з $ ("# someElement") [0] .appendChild (скрипт); Що це зафіксувало :) Thnx для пояснення
Maarten Kieft

7
$.getScriptвбудований у jQuery.
zzzzBov

SourceURL ( blog.getfirebug.com/2009/08/11/… ) може допомогти у вирішенні проблем налагодження.
vsevik

23

Можливо динамічно завантажувати файл JavaScript за допомогою функції jQuerygetScript

$ .getScript ('http://www.wwhat.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, оскільки у запитанні ОП використовує 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. У зовнішніх файлах скриптів немає цієї проблеми.
Ian Clelland

Втеча послідовності: "\x3cscript\x3e\x3c/script\x3e". У XHTML вам потрібно лише ввести коментований блок CDATA.
Елі Грей

2
Це швидше те, </що заборонено. Дивіться stackoverflow.com/questions/236073/…
Gumbo

2

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

  1. У файл сценарію додайте оператор з sourceURL на зразок "// @ sourceURL = foo.js"
  2. Завантажте скрипт, використовуючи jQuery $ .getScript (), і сценарій буде доступний на вкладці "джерела" в інструментах хромованого розробника

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 . Це можна зробити з ваніллю 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!'))

Його не потрібно загортати в Promise, але це дозволяє вам вирішити обіцянку, коли скрипт завантажується, допомагаючи запобігти умовам гонки для тривалих сценаріїв.


0

Додавання сценарію до тіла:

$(document).ready(function() {
    $("<script>", {  src : "bootstrap.min.js",  type : "text/javascript" }).appendTo("body");
});

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.