2012-12-13 8 views
7

Ho cercato di utilizzare documentFragments in un'app Backbone.js e mi chiedevo perché vedo esempi in cui "cloneNode" viene utilizzato quando si aggiunge DocumentFragment all'elemento DOM padre.Perché è necessario utilizzare cloneNode durante l'aggiunta di un documentoFragment?

Un esempio può essere visto here. Se si guarda in basso verso la sezione DocumentFragment vedrete questo:

oFrag = document.createDocumentFragment(); 
for (var i = 0, imax = aElms.length; i < imax; i++) { 
oFrag.appendChild(aElms[i]); 
} 

o.innerHTML = ''; 
o.appendChild(oFrag.cloneNode(true)); 

Perché "oFrag" Get clonato invece di aggiungerlo? Un altro blog post non usa "cloneNode" (come confronto).

+0

+1, molto interessante. La mia unica (e piuttosto selvaggia) ipotesi è che l'utilizzo di 'cloneNode' ci dia un controllo migliore sull'ambito' oFrag'. – raina77ow

+0

Non penso che questo meriti di essere forgiato in una risposta completa, ma comunque ... Semplicemente cercando 'documentFragment cloneNode' ho trovato [questo post] (http://ejohn.org/blog/dom- documentfragments /) di John Resig.) Nell'argomento di questo post un gruppo di nodi dovrebbe essere inserito in DOM _several_ volte, quindi la clonazione del documentoFragment è davvero una scelta migliore. – raina77ow

risposta

5

vostro first link riferisce al blog post dove l'autore utilizza document.getElementsByTagName anziché document.getElementById, come nel caso di test. Se si desidera un più elementi (vale a dire: div) da dare lo stesso documentFragment, è necessario clonarlo:

Se bambino è un riferimento a un nodo esistente nel documento, appendChild si muove dalla sua posizione attuale la nuova posizione (ovvero non è necessario rimuovere il nodo dal nodo principale prima di aggiungerlo ad un altro nodo).

Ciò significa anche che un nodo non può essere in due punti del documento contemporaneamente. Quindi se il nodo ha già un genitore, viene prima rimosso, quindi aggiunto alla nuova posizione.

via MDN

Molto probabilmente l'autore (o qualcun altro) copia-incollato il codice senza prendere in considerazione questo. Provalo tu stesso: puoi utilizzare appendChild senza cloneNode e tutto funziona correttamente.

Un'altra possibilità è che qualcuno che ha creato questo test case su jsperf non abbia ottenuto molto come funziona il codice di preparazione ed era preoccupato che il primo test svuoterebbe l'array aElms e non funzionerà più. Il codice di preparazione In fact viene eseguito prima di ogni iterazione temporizzata, quindi non è necessario preoccuparsi dei suoi contenuti.

L'ultima cosa riguarda le prestazioni. Se si desidera testare realmente l'inserimento reale , è necessario clonare il nodo. In caso contrario, testare l'albero ricollegamento (vedere il link MDN sopra).

Si prega di notare che cloning destroys event listeners.

Felice frammento! ;)

2

Non sono esattamente sicuro, ma nel contesto del collegamento che hai fornito (test delle prestazioni) lo oFrag.cloneNode(true) potrebbe essere una salvaguardia dal riutilizzo degli elementi già aggiunti in DOM nelle precedenti esecuzioni del ciclo, che risulterebbero in modo esecuzione più veloce del test.

Non vedo alcun motivo per usarlo nei normali casi d'uso di documentFragments.

+0

+1 Suppongo che questa sia la vera ragione. – raina77ow

0

Non credo sia necessario. Immagino sia stato usato solo per staccare lo aElms da riferimenti statici, dove avrebbero dovuto essere rimossi dai loro ex genitori quando si chiamava appendChild. È solo per le prestazioni in questo test.

Tuttavia, il seguente codice (più simile alla prova appendChild) avrebbe più senso per me:

var oFrag = document.createDocumentFragment(); 
for (var i = 0, imax = aElms.length; i < imax; i++) 
    oFrag.appendChild(aElms[i].cloneNode(true)); 
// using it here:    ^^^^^^^^^^^^^^^^ 
o.appendChild(oFrag); 

se potrebbe essere più lento di chiamare una sola volta su tutto il frammento, in cui l'albero dei nodi è recidivato con codice nativo.

controllare anche http://jsperf.com/cloning-fragments :-)

2

Se si aggiunge una DocumentFragment a un elemento e in seguito si cancellano i nodi aggiunti da quell'elemento, anche documentFragment sarà vuoto e non può più essere riutilizzato! L'aggiunta di un clone del documento deframmentazione impedisce questo e consente più riutilizzo del documento documentFragment.

Suppongo che l'autore del frammento jsperf stia testando per un caso del genere.

Esempio: menu a discesa con una relazione padre-figlio. Diciamo che hai un menu a discesa in cui selezioni un continente e un secondo menu a discesa che elenca tutti i paesi del continente. Se si desidera memorizzare nella cache i documenti documentFragments con i nodi opzione dopo la creazione, è necessario utilizzare cloneNode. Immagina che qualcuno scelga l'Europa, poi l'africa e poi l'europa: puoi ricreare l'intero frammento di documento, salvarlo nella cache.

ho creato un frammento jsperf per illustrare la differenza di prestazioni di ricreare le documentFragments vs cache e clonazione dei frammenti:

http://jsperf.com/documentfragment-cache-vs-recreate

+0

grazie per l'informazione, è piuttosto interessante. – codecraig