2011-08-24 95 views
30

我刚刚开始使用d3.js,并且有一个细节完全避开了我:只有在DOM准备好接收输入后,我如何才能让代码执行?d3.js和document.onReady

我当然可以使用类似jQuery的东西,但看起来过多。

every d3.js example我遇到过似乎没有特殊的document.onReady()类型的例程,但所有的例子工作完美无瑕。然而,当在我的端测试代码时,如果在DOM准备好之前执行代码,则代码完全失败(将我的代码投入window.onload证实了这一点)。

什么给?

回答

46

你会发现在他们的例子中,他们的javascript低于任何html元素,因此在开始执行javascript之前,部分dom被加载。

简单地把你的JavaScript放在身体的底部通常是足够好的。

+7

辉煌,谢谢。显然,我一直在jQuery土地太久。 – Roshambo

+2

这是不好的做法,为什么jQuery及其竞争对手中有这么多的已有变体。 – ijw

+0

ilw是对的。在某些移动WebViews上,它有时会在打开应用程序时报告不正确的屏幕宽度大小。在准备等待文件避免了这一点。 – phreakhead

5

有时你不能依赖DIV/HTML元素放置,例如当你需要将使用D3操作的元素动态地插入到文档中时。在这种情况下,一种解决方案是监视文档中的DOMNodeInserted事件,并在回调中插入D3代码(我相信这排除了IE版本在9之前)。下面是使用jQuery的例子:

$(document).bind('DOMNodeInserted', function(event) 
{ 
    if (event.target.id == "viz") 
    { 
     var sampleSVG = d3.select("#viz") 
       .append("svg:svg") 
       .attr("width", 100) 
       .attr("height", 100);  

     sampleSVG.append("svg:circle") 
       .style("stroke", "gray") 
       .style("fill", "white") 
       .attr("r", 40) 
       .attr("cx", 50) 
       .attr("cy", 50) 
       .on("mouseover", function() { 
         d3.select(this).style("fill", "aliceblue"); 
       }) 
       .on("mouseout", function() { 
         d3.select(this).style("fill", "white");} 
       ); 
    } 
}); 
+1

很好的答案。在将SVG动态加载到DOM中时,是否有办法触发SVG节点插入事件?如果是这样,那么当创建不相关的DOM元素(例如div,p等)时,会减少对SVG对象的重新呈现。 –

+0

伟大的技术,鲜为人知! – VividD

+1

不幸的是,突变事件(如'DOMNodeInserted')现在已被弃用 - https://developer.mozilla.org/en-US/docs/Web/Guide/Events/Mutation_events。我希望我能告诉你什么是最好的选择,但我不能(当我发现这个问题时,我正在试图发现它!) – Willl

2

您可以在体内把onload事件,并把所有d3js代码的功能。例如:

<body onload="yourFunctionName()"> 

而在你的JavaScript中,插入此:

function yourFunctionName() { 
    //Your d3js code goes here 
} 

只需粘贴在这个函数内全D3示例代码。 onload事件将在DOM准备就绪后发生。

+0

为了测试的目的,这很好,但请注意设置'body.onload'通常被认为是不好的形式,因为其他脚本可以覆盖它。 'addEventListener'比较好,但与'document.onReady'相比还是有点慢。 – Roshambo

3

标记为正确的答案不适用于我,实际上是错误的。这是一种黑客行为,不应被视为正确的答案。同样,你可以在setTimeout(function(){..},1000)内执行你的代码。它更可靠,因为你可以设置延迟: -/

在我的情况下,我需要等待所有元素进行处理,以了解他们的实际尺寸。当它们不被构建,处理和完成时,数字是不正确的。

已更新。这里是正确的答案:

很可能你会用d3.json()这样的异步调用来获得构建DOM的数据,这就是为什么它需要一些时间。由于异步调用是非阻塞的,因此即使在异步调用完成之前,您的后续代码也会被调用,从而导致问题,这就是您发布此问题的原因。

所以你试图通过在D3或其他任何地方寻找东西来解决这个问题,那会告诉你D3异步调用已经完成,现在你可以做下一件事了。有人建议做同步ajax调用。这是非常错误的。异步调用被创建为异步。

你实际需要做的是改变你的范例。只需将回调传递给该异步调用即可!类似的东西:

function thingsToDoWhenDOMisBuilt() { 
    ... 
} 

function buildDOM(rootNode, error, thingsToDoWhenDOMisBuilt) { 
    ... 
    // everything is built, so we can do our post-build thing against DOM 
    if (thingsToDoWhenDOMisBuilt) 
     thingsToDoWhenDOMisBuilt() 
} 

d3.json(urlToData, buildDOM) { 
    if (error) 
     console.log("oops") 
    buildDOM(rootNode, thingsToDoWhenDOMisBuilt) 
} 

而且,上述建议在async.js

绑定事件看一看也是一个可怕的想法。您应该使用.enter().exit()代替。 D3是数据驱动的,如果你需要事件驱动的流程,那么只需使用jQuery或者vanilla JS!