我有一个SVG文件,它使用JavaScript动态定义了一些样式和<defs>
。
我在HTML文件中使用了所说的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>
仅供参考,我正在尝试使用SVG,但在我的测试中,当使用被调用者的HTML文件时,行为是相同的。
答案 0 :(得分:3)
从HTML规范中,不执行使用DOMParser解析的脚本 https://html.spec.whatwg.org/multipage/scripting.html#script-processing-noscript
禁用脚本的定义意味着以下脚本将不会执行:XMLHttpRequest的responseXML文档中的脚本,DOMParser创建的文档中的脚本,XSLTProcessor的transformToDocument功能创建的文档中的脚本以及首先插入的脚本通过脚本将文档创建为使用createDocument()API创建的文档。 [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)
});
答案 1 :(得分:1)
回答我自己的问题,为教授的奥尔曼答案添加一些实用细节。
在这种背景下要记住的事情:
.appendChild()
将SVG添加到文档中从技术上移动节点。因此,在我的示例中,ajaxdoc.querySelectorAll("script")
在插入后将为undefined
。所以我们要确保从正确的节点中寻找它。或者:
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
});