Как выполнить JavaScript во внешнем файле HTML / SVG в чистом JavaScript? - PullRequest
0 голосов
/ 04 мая 2018

У меня есть файл SVG, который определяет некоторые из его стилей и <defs> динамически с JavaScript.

Я использую указанный SVG-файл внутри HTML-файла.

  • Если я сам открою файл SVG, его JavaScript будет выполнен.
  • Если, используя jQuery, я включаю файл SVG в файл HTML через AJAX (добавляя SVG к документу HTML), то JavaScript SVG также выполняется.
  • Однако с использованием чистого JavaScript: если я включаю файл SVG в файл HTML через AJAX (добавляя SVG к документу HTML) , тогда JavaScript SVG НЕ выполняется .

Я пытаюсь понять и исправить поведение.

Как MCVE:

ajax-callee.svg:

<?xml version="1.0" encoding="UTF-8"?>
<svg version="1.1"
    baseProfile="full"
    xmlns="http://www.w3.org/2000/svg"
    xmlns:xlink="http://www.w3.org/1999/xlink"
    xmlns:ev="http://www.w3.org/2001/xml-events"
    >
    <script><![CDATA[

    console.log( 'ajax-callee.svg › script tag' );

    /** When the document is ready, this self-executing function will be run. **/
    (function() {

        console.log( 'ajax-callee.svg › script tag › self-executing function' );

    })();   /* END (anonymous function) */

    ]]></script>
</svg>

ajax-caller-jquery-withSVG.html (отлично работает):

<!DOCTYPE html>
<html>

<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>

<body>

    <p>(Check out the console.)</p>

<script src="//ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
<script>

    $( document ).ready(function() {

        $.ajax({
            method: "GET",
            url: "ajax-callee.svg",
            dataType: "html"
        }).done(function( html ) {
            /** Loading the external file is not enough to have, it has to be written to the doc too for the JS to be run. **/
                $( "body" ).append( html );
        });

    });
</script>

</body>
</html>

ajax-caller-pureJS-withSVG-notworking.html

<!DOCTYPE html>
<html>

<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>

<body>

    <p>(Check out the console.)</p>

<script>

    /** AJAX CALLER **/

    /** When the document is ready, this self-executing function will be run. **/
    (function() {

        var ajax = new XMLHttpRequest();

        ajax.open("POST", "ajax-callee.svg", true);
        ajax.send();

        /**
         * Append the external SVG to this file.
         * Gets appended okay…
         * …but its JavaScript won't get executed.
         */
        ajax.onload = function(e) {

            /** Parse the response and append it **/
            var parser = new DOMParser();
            var ajaxdoc = parser.parseFromString( ajax.responseText, "image/svg+xml" );
            document.getElementsByTagName('body')[0].appendChild( ajaxdoc.getElementsByTagName('svg')[0] );

        }

    })();   /* END (anonymous function) */

</script>

</body>
</html>
  • Что jQuery делает по-другому, что приводит к выполнению JavaScript?
  • Что я могу сделать, чтобы запустить включенный SVG JS?
  • Что-нибудь остерегаться?

К вашему сведению, я пытаюсь использовать SVG, но в моих тестах поведение было таким же при использовании файлов HTML для callee .

Ответы [ 2 ]

0 голосов
/ 04 мая 2018

Отвечая на мой вопрос, чтобы добавить некоторые практические детали к ответу профессора Аллмана.

Что следует иметь в виду в этом контексте:

  • На практике логика JavaScript SVG, скорее всего, будет зависеть от содержимого SVG. Поэтому добавьте SVG, прежде чем пытаться выполнить его скрипт.
  • Добавление SVG к документу через .appendChild() технически перемещает узел. Итак, в моем примере ajaxdoc.querySelectorAll("script") будет undefined после вставки. Поэтому мы хотим убедиться, что мы ищем его с правого узла.
  • Мы хотим сохранить все в чистоте и избегать дублирования тегов сценария.
  • В оригинальном SVG мы хотим быть осторожнее с нашими предположениями. Например: SVG может содержать таблицу стилей, но не документ HTML, который будет выполнять код.

Или:

ajax.onload = function(e) {
    /** Parse the response **/
    var parser = new DOMParser();
    var ajaxdoc = parser.parseFromString( ajax.responseText, "image/svg+xml" );


    /** Append the SVG **/
    var svg = document.getElementsByTagName('body')[0].appendChild( ajaxdoc.getElementsByTagName('svg')[0] )


    /** Execute the SVG's script **/
    svg.querySelectorAll("script").forEach((scriptElement) => {
        let script = document.createElement("script");
        script.text = scriptElement.textContent;
        document.head.appendChild(script);
        scriptElement.remove(); // avoid duplicate script tags
    });
0 голосов
/ 04 мая 2018

Из спецификации HTML скрипты, которые анализируются с помощью DOMParser, не выполняются https://html.spec.whatwg.org/multipage/scripting.html#script-processing-noscript

Определение сценариев отключено означает, что, среди прочего, следующие сценарии не будут выполняться: сценарии в документах responseXML XMLHttpRequest, сценарии в документах, созданных DOMParser, сценарии в документах, созданных функцией transformToDocument XSLTProcessor, и сценарии, которые вставляются первыми с помощью сценария в документ, который был создан с помощью API createDocument (). [XHR] [DOMPARSING] [XSLTP] [DOM]

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

http://code.jquery.com/jquery-3.3.1.js

DOMEval( node.textContent.replace( rcleanScript, "" ), doc, node );

function DOMEval( code, doc, node ) {
    doc = doc || document;
    var i,
        script = doc.createElement( "script" );

    script.text = code;
    if ( node ) {
        for ( i in preservedScriptAttributes ) {
            if ( node[ i ] ) {
                script[ i ] = node[ i ];
            }
        }
    }
    doc.head.appendChild( script ).parentNode.removeChild( script );
}

Так что для своего кода вы можете сделать то же самое:

ajaxdoc.querySelectorAll("script").forEach((scriptElement) => {
    let script = document.createElement("script");
    script.text = scriptElement.textContent;
    document.head.appendChild(script)
});
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...