如何检查嵌入的 SVG 文档是不是加载到 html 页面中?

Posted

技术标签:

【中文标题】如何检查嵌入的 SVG 文档是不是加载到 html 页面中?【英文标题】:How to check if an embedded SVG document is loaded in an html page?如何检查嵌入的 SVG 文档是否加载到 html 页面中? 【发布时间】:2010-09-25 03:16:42 【问题描述】:

我需要编辑(使用 javascript)嵌入在 html 页面中的 SVG 文档。

加载 SVG 后,我可以访问 SVG 的 dom 及其元素。但我无法知道 SVG dom 是否已准备好,因此在加载 html 页面时,我无法在 SVG 上执行默认操作。

要访问 SVG dom,我使用以下代码:

var svg = document.getElementById("chart").getSVGDocument();

其中“chart”是嵌入元素的 id。

如果我在 html 文档准备好时尝试访问 SVG,这样:

jQuery(document).ready( function() 
var svg = document.getElementById("chart").getSVGDocument();
...

svg 始终为空。我只需要知道它什么时候不为空,这样我就可以开始操作它了。 不知道有没有办法?

【问题讨论】:

【参考方案1】:

在主文档中的嵌入元素(例如“embed”、“object”、“iframe”)上添加一个调用您的函数的onload 属性,或者在脚本中添加事件监听器,例如embeddingElm.addEventListener('load', callbackFunction, false)。另一种选择可能是收听DOMContentLoaded,这取决于您想要它的用途。

您还可以在主文档上添加负载侦听器。 jQuery(document).ready 并不意味着所有资源都已加载,只是文档本身有一个准备好执行操作的 DOM。但是请注意,如果您在整个文档上监听负载,则在该文档中的所有资源(css、javascript 等)加载之前,您的回调函数不会被调用。

如果您使用内联 svg,那么 jQuery(document).ready 将可以正常工作。

进一步说明,您可能需要考虑使用embeddingElm.contentDocument(如果可用)而不是embeddingElm.getSVGDocument()

【讨论】:

如果在脚本运行时已经加载了 embeddingElm,则 embeddingElm.addEventListener('load', callbackFunction, false) 将不起作用。如果您链接 SVG 中的图像(如背景图像),则 DOMContentLoaded 将不起作用。您(不应该)想要做:类似于:window.onload 的事情,因为那样您就必须等到所有外部资源也被下载(例如跟踪脚本和广告) 你还知道如何在 Angular 测试中触发 SVG 对象上的这个加载事件监听器吗? 在 Safari 上,如果 SVG 内容已经加载,则永远不会触发 load 如果将分配给 DIV 之类的 SVG 文档更改为导致该文档被加载的内容,那么 onload 会起作用吗?这整个'我们什么时候知道真正加载了 DOM 和内容,以便可以调用 SVG 中定义的定义的 ECMAscript 函数或查询 DOM 根据我所听到的,在 2018 年似乎仍然是一个命中/未命中命题来自一些人。 @jBoive :关于“embeddingElm.addEventListener('load', callbackFunction, false) 如果在脚本运行时已经加载了 embeddingElm,则将不起作用。”:然后类似于***.com/a/39993735/923560 的解决方案将起作用。【参考方案2】:

您可以使用 onload 事件进行检查。

假设 some.svg 嵌入在 object 标签中:

<body>    
<object id="svgholder" data="some.svg" type="image/svg+xml"></object>
</body>

jQuery

var svgholder = $('body').find("object#svgholder");

svgholder.load("image/svg+xml", function() 
    alert("some svg loaded");
);

javascript

var svgholder = document.getElementById("svgholder");

svgholder.onload = function() 
    alert("some svg loaded");

【讨论】:

注意:考虑使用addEventListener('load', handler) 而不是设置onload 属性,以确保不会覆盖其他负载处理程序。但是,古代浏览器不支持这一点。 问题: jQuery 的load 是我尝试使用的第一个方法,但是如果没有'image/svg+xml' 作为第一个参数,它将无法工作。你能解释一下这个魔法吗?我在 jQuery 文档中找不到解释。它只是将参数提到为url(这里我们给出了一个 MIME 类型)。再说一遍,为什么我们不需要 onload 这样的东西? 我认为可以肯定地说,如果您假设浏览器能够显示嵌入式 SVG,那么您可以确定它也实现了 addEventListener svgholder.load("image/svg+xml", function()... 似乎正在调用 jquery ajax 加载。在 v3.0 之前,jquery 根据提供的参数确定要调用的负载。在第一个参数中使用字符串,jquery 尝试将 'image/svg+xml' 作为 url 执行 GET。由于它将加载的内容放置在选定的元素中,然后调用提供的回调,这可能看起来像一个加载的通知,但它正在做其他事情。在您的控制台中查找 404。此外,从 3.0 开始不推荐使用 .load 事件处理程序。【参考方案3】:

假设您的 SVG 位于 &lt;embed&gt; 标签中:

<embed id="embedded-image" src="image.svg" type="image/svg+xml" />

SVG 图像本质上是在一个子文档中,该子文档将有一个单独的load 事件到主document 的事件。但是,您可以侦听此事件并进行处理:

var embed = document.getElementById("embedded-image");
embed.addEventListener('load', function()

    var svg = embed.getSVGDocument();
    // Operate upon the SVG DOM here
);

这比轮询要好,因为您对 SVG 所做的任何修改都会在它第一次绘制之前发生,从而减少了闪烁和绘制所花费的 CPU 工作量。

【讨论】:

要在给定元素上使用 JQuery 进行操作,请执行以下操作: var svg = $(embed.getSVGDocument().documentElement);【参考方案4】:

嵌入元素(例如对象)的加载事件是我的偏好,但如果由于某种原因这不是一个可行的解决方案,我发现的唯一通用且可靠的 SVG DOM 测试是 getCurrentTime 方法SVG 根元素:

var element = document.getElementById( 'elementId' );
var svgDoc = element.contentDocument;
var svgRoot = svgDoc ? svgDoc.rootElement : null;

if ( svgRoot
    && svgRoot.getCurrentTime
    && ( svgRoot.getCurrentTime() > 0 ))

    /* SVG DOM ready */

W3C SVG recommendation 声明 getCurrentTime 在 SVGSVGElement 上:

返回相对于当前 SVG 文档片段的开始时间的当前时间(以秒为单位)。如果在文档时间线开始之前调用 getCurrentTime(例如,在调度文档的 SVGLoad 事件之前通过在“脚本”元素中运行的脚本),则返回 0。

【讨论】:

【参考方案5】:

使用 jQuery,您可以绑定到 Erik 提到的窗口加载事件:

$(window).load(function()
    var svg = document.getElementById("chart").getSVGDocument();
);

【讨论】:

我想通过这种方式你可以知道html页面中SVG对象何时加载,但是你仍然不知道SVG的DOM是否准备好了。 当我将 jquery 嵌入到独立的 SVG 中时,我发现它可以工作 - 谢谢!【参考方案6】:

供将来参考:Angular(8)/Typescript 解决方案如下所示:

  @ViewChild('startimage', static:false)
  private startimage: ElementRef;
...
  this.startimage.nativeElement.addEventListener('load', () => 
    alert('loaded');
  );

您可以通过const svg = this.startimage.nativeElement.getSVGDocument(); 访问 svg

【讨论】:

【参考方案7】:

您可以将 onload 事件处理程序分配给 SVG 文档中的元素,并让它在 html 页面中调用 javascript 函数。 onload 映射到 SVGLoad。

http://www.w3.org/TR/SVG11/interact.html#LoadEvent

在用户代理完全解析元素及其后代并准备好对该元素采取适当行动时触发事件

【讨论】:

不,我无法编辑 SVG 文档。我可以在网页中操作它。 父级的加载不起作用,只有实际的 svg。【参考方案8】:

您可以尝试每隔一段时间进行一次轮询。

function checkReady() 
    var svg = document.getElementById("chart").getSVGDocument();
    if (svg == null) 
        setTimeout("checkReady()", 300);
     else 
        ...
    

【讨论】:

是的,它有效。没有考虑超时解决方案...谢谢。 轮询不是这样做的好方法。请改用“加载”事件侦听器。 @ErikDahlström load 事件监听器有问题。

以上是关于如何检查嵌入的 SVG 文档是不是加载到 html 页面中?的主要内容,如果未能解决你的问题,请参考以下文章

检查是不是通过嵌入到 HTML 页面来加载 SWF(直接访问)?

如何让 SVG 图像从 HTML 文档继承颜色?

带有 SVG 文档的 jQuery

如何将 SVG 嵌入到来自 Cross Origin url 的 html <object> 标签中(s3_url/image.svg)

在 SVG 中嵌入 SVG?

如何在保存在 Mongoose 之前检查数据库中是不是存在嵌入式文档