2011-08-24 94 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!