【问题标题】:How to execute javascript in external HTML/SVG file in pure JavaScript?如何在纯 JavaScript 的外部 HTML/SVG 文件中执行 javascript?
【发布时间】:2018-10-15 00:08:20
【问题描述】:

我有一个 SVG 文件,它使用 JavaScript 动态定义了它的一些样式和 <defs>

我在 HTML 文件中使用上述 SVG 文件。

  • 如果我自己打开 SVG 文件,它的 JavaScript 就会被执行。
  • 如果使用 jQuery,我通过 AJAX 将 SVG 文件包含到 HTML 文件中(将 SVG 附加到 HTML 文档),那么 SVG 的 JavaScript 也会被执行。
  • 但是,使用纯 JavaScript:如果我通过 AJAX 将 SVG 文件包含到 HTML 文件中(将 SVG 附加到 HTML 文档)那么 SVG 的 JavaScript 不会被执行强>。

我正在尝试理解并修复该行为。

作为 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,但在我的测试中,为 callee 使用 HTML 文件时的行为是相同的。

【问题讨论】:

    标签: javascript jquery html ajax svg


    【解决方案1】:

    不执行使用 DOMParser 解析的 HTML 规范脚本 https://html.spec.whatwg.org/multipage/scripting.html#script-processing-noscript

    禁用脚本定义意味着以下脚本将不会执行:XMLHttpRequest 的 responseXML 文档中的脚本、DOMParser 创建的文档中的脚本、由 XSLTProcessor 的 transformToDocument 功能创建的文档中的脚本以及首先插入的脚本通过脚本进入使用 createDocument() API 创建的 Document。 [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)
    });
    

    【讨论】:

    • 谢谢,这是最有用的,背景信息很有见地。我也会回答我自己的问题以添加一些方便的发展。
    【解决方案2】:

    回答我自己的问题,为教授的奥尔曼的回答添加一些实用细节。

    在这种情况下要记住的事情:

    • 实际上,SVG 的 JavaScript 逻辑很可能取决于 SVG 的内容。因此,请在尝试执行其脚本之前添加 SVG。
    • 通过.appendChild() 将 SVG 添加到文档中,技术上会移动节点。因此,在我的示例中,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
        });
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-12-25
      • 1970-01-01
      • 1970-01-01
      • 2021-11-23
      • 1970-01-01
      • 2023-04-08
      • 2014-11-22
      • 1970-01-01
      相关资源
      最近更新 更多