2009-12-02 4 views
4

Salut, je voudrais faire dom la sélection et la manipulation hors de la dom.sélection de noeuds et manipulation hors du dom (Quel est le truc de jQuery?)

Le but est de construire mon widget hors du dom et de l'insérer dans le dom seulement une fois qu'il est prêt.

Mon problème est que getElementById n'est pas pris en charge sur un fragment de document. J'ai aussi essayé createElement et cloneNode, mais ça ne marche pas non plus. J'essaye de faire cela en js simple. Je suis habitué à le faire avec jQuery qui le gère bien. J'ai essayé de trouver le truc dans la source jQuery, mais sans succès jusqu'à présent ...

Olivier

+0

Pouvez-vous faire votre manipulation à l'intérieur d'un div avec son écran réglé sur aucun? –

+1

Je peux mais c'est trop lent. Je voudrais faire la sélection de noeuds et la manipulation hors du dom afin d'éviter des accès dom coûteux et des remboursements inutiles. – Olivvv

+1

En fait, Sizzle (que jQuery intègre) ne fonctionne pas non plus sur les objets 'DocumentFragment'. Vérifiez la source vous-même: http://github.com/jeresig/sizzle/blob/master/sizzle.js ~ ligne 28. Les objets 'DocumentFragment' ont un' nodeType' de '11', et donc si' context' est un fragment de document, Sizzle/jQuery simplement bails et ne fait rien. –

Répondre

1

Je l'ai fait quelque chose de semblable, mais ne savez pas si elle répondra à vos besoins. Créez une "zone d'attente" telle qu'une plaine <span id="spanReserve"></span> ou <td id="cellReserve"></td>. Ensuite, vous pouvez faire quelque chose comme ça dans la fonction JS:

var holdingArea = document.getElementById('spanReserve'); holdingArea.innerHTML = widgetHTMLValue;

+0

Je peux, mais cela irait à l'encontre du but. Je veux qu'il soit hors de la dom, afin de garder le dom aussi petit que possible, et éviter les accès dom coûteux lors de la sélection d'un nœud. – Olivvv

+1

Étant donné les nombreuses réponses et commentaires merveilleux sur cette page, et en trouvant que vous êtes assez limité en termes de fonctions DOM natives lorsque vous travaillez avec Fragments, peut-être une solution maison pour faire ce que vous voulez sur le fragment plutôt que dans le document. pas plus efficace que de s'appuyer sur l'implémentation 'getElementById 'native du navigateur et de prendre le" hit "de la performance de cette façon. Le seul vrai moyen de savoir à quel point cela est coûteux, ce serait pour vous de le tester dans les deux sens dans votre situation particulière. Bonne chance! – Funka

-1

On dirait que vous faites des choses bonnes. Je ne sais pas pourquoi ça ne marche pas.



// if it is an existing element 
var node = document.getElementById("footer").cloneNode(true); 

// or if it is a new element use 
// document.createElement("div"); 

// Here you would do manipulation of the element, setAttribute, add children, etc. 
node.childNodes[1].childNodes[1].setAttribute("style", "color:#F00; font-size:128px"); 

document.documentElement.appendChild(node) 



+0

S'il y avait des balises dans le innerHTML de votre "objet", alors getElementById ne fonctionnerait pas dessus. Il semble que les objets renvoyés par cloneNode soient similaires à documentFragment, et que seules les méthodes de support définies dans le nœud API http://www.w3.org/TR/2000/REC-DOM-Level-2-Core-20001113/core.html # ID-1950641247 pas ceux définis dans le doublement api. Mais il doit y avoir une solution de contournement, car jQuery est totalement capable de travailler avec des structures qui sont hors de la dom. Je voudrais comprendre le truc de jQuery et le reproduire. – Olivvv

+0

Je suis confus. Donc, dans l'exemple ci-dessus. J'ai pris l'élément de bas de page de cette page, je l'ai cloné, j'ai modifié son style, puis je l'ai ajouté au document. Cela laisse le pied de page original comme il était. En fin de compte, c'est pourquoi jQuery et la famille existe -> le DOM est un gâchis. –

+0

Il est probablement une fausse idée d'utiliser "object" comme nom de variable. J'ai essayé votre code dans firebug (objet remplacé par obj) et cela fonctionne très bien. childNodes est pris en charge par le dom api, donc pas de surprise ici. – Olivvv

0

EDIT:

Qu'en est-il quelque chose de simple le long de ces lignes:

DocumentFragment.prototype.getElementById = function(id) { 
    for(n in this.childNodes){ 
     if(id == n.id){ 
     return n; 
     } 
    } 

    return null; 
    } 

Pourquoi ne pas simplement utiliser jQuery ou l'API de sélection dans tout autre que vous êtes en utilisant lib? AFAIK toutes les bibliothèques majeures supportent la sélection sur des fragments. Si vous souhaitez ignorer une bibliothèque plus grande telle que jQ/Prototype/Dojo/etc., vous pouvez utiliser Sizzle, c'est-à-dire le moteur de sélection qui alimente jQ et Dojo et qui est proposé en mode autonome. Si c'est hors de question, alors je suppose que vous pourriez plonger dans la source Sizzle et voir ce qui se passe. Dans l'ensemble, il semble que beaucoup d'efforts pour éviter quelques 100k avec la probalité supplémentaire que le code que vous venez de créer sera plus lent que tout le travail tiré dans Sizzle ou une autre bibliothèque open source.

http://sizzlejs.com/

Oh aussi ... Je pense (deviner) truc de jQ est que les éléments ne sont pas hors du DOM. Je peux me tromper, mais je pense que quand vous faites quelque chose comme:

$('<div></div>'); 

est en fait dans le DOM documentent son tout simplement pas partie des nœuds corps/tête. Pourrait être totalement faux à ce sujet, c'est juste une supposition.

Alors vous m'avez curieux haha. J'ai jeté un oeil à Sizzle .. que la réponse est - il n'utilise pas les méthodes DOM. Il semble utiliser un algorithme qui compare les différentes propriétés DOMNode mappées aux types de sélecteurs - sauf si im manque quelque chose ... ce qui est tout à fait possible :-)

Cependant, comme indiqué ci-dessous dans les commentaires, il semble que Sizzle NE FONCTIONNE PAS sur DocumentFragments. ..Pour revenir à la case départ :-)

+0

Ceci est vraiment une grande application, plusieurs équipes travaillant dessus, donc je ne peux pas faire des changements structurels de ma propre initiative. Nous avons sous le capot une version fourchue de yui 2.2, qui se brise apparemment sur documentFragment. Oui, ajouter une petite touche au mixage est une excellente idée, mais avant cela, j'aimerais comprendre comment ces libs fonctionnent pour travailler sur des fragments de document. Aussi 100k est énorme! J'essaie de réduire cette application partout où je peux. – Olivvv

+0

Bien sizzle est seulement 25k (pas sûr si c'est compressé ou non). Cependant, étant donné la nature de l'équipe de développement - je suppose que vos options sont de jeter un oeil à la source Sizzle et voir ce qui se passe.Je penserais qu'il serait plus facile de traquer que JQ lui-même puisque vous avez enlevé tous les jQ "cruft de l'équation". Une autre idée serait de poster cette question directement sur les listes de diffusion jQ et/ou Sizzle. – prodigitalson

+0

Sizzle ne fonctionne pas sur 'DocumentFragments'. –

1

jQuery essayera d'abord d'utiliser getElementById, et si cela ne fonctionne pas, il recherchera ensuite tous les éléments DOM en utilisant getAttribute("id") jusqu'à ce qu'il trouve celui dont vous avez besoin.

Par exemple, si vous avez construit la structure DOM suivante qui est pas attaché à la document et il a été affecté au javascript var widget:

<div id="widget"> 
    <p><strong id="target">Hello</strong>, world!</p> 
</div> 

Vous pouvez ensuite effectuer les opérations suivantes:

var target; 

// Flatten all child elements in the div 
all_elements = widget.getElementsByTagName("*"); 

for(i=0; i < all_elements.length; i++){ 
    if(all_widget_elements[i].getAttribute("id") === "target"){ 
     target = all_widget_elements[i]; 
     break; 
    } 
} 

target.innerHTML = "Goodbye"; 

Si vous avez besoin de plus qu'une simple recherche par ID, je vous suggère d'installer Sizzle plutôt que de dupliquer la fonctionnalité Sizzle. En supposant que vous avez la possibilité d'installer une autre bibliothèque.

Espérons que cela aide!

+1

Je pense que votre approche est intéressante, mais je viens de lire un commentaire de John Resig lui-même (trouvé dans un lien prodigitalson laissé dans un commentaire ailleurs sur cette page) qui indique ce qui suit: "Les navigateurs ne fournissent pas les méthodes basiques Pour sélectionner des éléments dans un fragment de document, par exemple, il n'y a pas de 'getElementsByTagName' Certains des nouveaux navigateurs supportent' querySelectorAll' sur des fragments, mais cela n'est pas garanti dans tous les navigateurs. " – Funka

+0

Oui, il n'y a pas getElementByTagsName pour documentFragments. De plus, IE fait apparemment semblant de documentFragments, et n'a aucune différence de performance avec les éléments "normaux" créés à partir de dom. Les avantages de documentFragments semblent donc très limités. – Olivvv

0

Les navigateurs modernes (lire: pas IE) ont la méthode querySelector dans Element API. Vous pouvez l'utiliser pour obtenir et element by id dans un DocumentFragment.

jQuery utilise sizzle.js

Ce qu'il fait sur DocumentFragments est: profondément boucle à travers tous les éléments du fragment vérifier si l'attribut d'un élément (dans votre cas « id ») est celui que vous recherchez. À ma connaissance, sizzle.js utilise aussi querySelector, si disponible, pour accélérer les choses.

Si vous recherchez une compatibilité croisée, ce qui est probablement le cas, vous devrez écrire votre propre méthode ou vérifier la méthode querySelector.

+1

Sizzle source: http://github.com/jeresig/sizzle/blob/master/sizzle.js si 'context' est un' DocumentFragment', 'return []'. En outre, Resig croit que l'API de Selectors est cassée par rapport à 'DocumentFragment': http://groups.google.com/group/sizzlejs/msg/517c78d0aad82c78 –

+0

" Navigateurs modernes (lire: pas IE) ":) – Tom

+0

Crescent Fresh, Resig seulement a déclaré que ce n'est pas un navigateur croisé. Mais son commentaire sur les groupes google est perspicace quant à la raison pour laquelle Olivier vit une période difficile. http://groups.google.com/group/sizzlejs/msg/517c78d0aad82c78 –

-1

Vous avez vraiment deux outils pour travailler, html() et en utilisant les opérateurs de manipulation jQuery normales sur un document XML, puis l'insérer dans le DOM.

Pour créer un widget, vous pouvez utiliser html():

$('#target').html('<div><span>arbitrarily complex JS</span><input type="text" /></div>'); 

Je suppose que ce n'est pas ce que vous voulez. Par conséquent, regardez les comportements supplémentaires du sélecteur jQuery: lorsque vous passez un second paramètre, il peut s'agir de son propre fragment XML, et une manipulation peut se produire sur ces documents. par exemple.

$('<div />').append('<span>').find('span').text('arbitrarily complex JS'). etc. 

Tous les opérateurs comme append, appendTo, emballage, etc. peuvent travailler sur des fragments comme celui-ci, et ils peuvent être insérés dans les DOM. Un mot d'avertissement, cependant: jQuery utilise les fonctions natives du navigateur pour manipuler ceci (autant que je sache), donc vous obtenez des comportements différents sur les différents navigateurs. Assurez-vous de bien formé XML. Je l'ai même fait rejeter des fragments HTML mal formés. Dans le pire des cas, cependant, revenez en arrière et utilisez la concaténation de chaînes et la méthode html().

+0

Désolé, mais vous avez mal compris la question. Je ne veux pas apprendre à utiliser jQuery, et les documentFragments auxquels je fais référence ne sont pas des fragments XML mais des DOM documentFragments. – Olivvv

Questions connexes