42 votes

Manière préférée de modifier des éléments qui n'ont pas encore été créés (en plus des événements)

Il ya beaucoup de questions à propos de la liaison de futures manipulations inexistante éléments qui tous ont répondu avec live/délégué. Je me demande comment faire pour exécuter un arbitraire de rappel (pour ajouter une classe ou d'un déclencheur d'un plugin, par exemple) à tous les éléments qui correspondent à un sélecteur dans le futur tous les éléments qui correspondent à la même sélecteur qui sont encore à créer.

Il semble que la principale fonctionnalité de l'livequery plugin dans le noyau, mais l'autre partie, fixation arbitraire des rappels ai perdu le long de la voie en quelque sorte.

Une autre réponse est l'événement de la délégation mais que faire si on n'a pas accès à tout le code du fournisseur qui est de la création d'éléments pour l'avoir à déclencher les événements?


Voici quelques codes réels:

// with livequery
$('input[type=text], input[type=password], textarea, .basic_form .block select, .order_form .form_item select, .order_form .form_item input')
    .livequery(function(){
        $(this)
            .focus(function(){
                $(this).addClass('active');
            })
            .blur(function(){
                $(this).removeClass('active');
            })
            .addClass('text');
    });

// with live
$('input[type=text], input[type=password], textarea, .basic_form .block select, .order_form .form_item select, .order_form .form_item input')
    .live('focus', function(){
            $(this).addClass('active');
        })
    .live('blur', function(){
            $(this).removeClass('active');
        });
    // now how to add the class to future elements?
    // (or apply another plugin or whatever arbitrary non-event thing)

Une approche serait de surveiller lorsque de nouveaux nœuds sont ajoutés/supprimés et re-déclencher nos sélecteurs. Merci à @arnorhs nous savons à propos de la DOMNodeInserted événement, que je ne tiendrait pas compte de la croix-navigateur problèmes dans l'espoir que ces petits IE correctifs pourraient un jour la terre en amont de jQuery ou de connaître le jQuery fonctions DOM pourrait être enveloppé.

Même si nous pouvions nous assurer que le DOMNodeInserted tiré de la croix-navigateur, cependant, il serait ridicule de le lier avec plusieurs sélecteurs. Des centaines d'éléments peuvent être créés à tout moment, et de faire des dizaines de sélecteur d'appels sur chacun de ces éléments d'analyse.

Ma meilleure idée jusqu'à présent

Serait-il peut-être préférable de surveiller DOMNodeInserted/Supprimé et/ou d'un crochet en jQuery DOM routines de manipulation de définir un indicateur qui une "re-init" qui doit arriver? Ensuite, il pourrait juste être une minuterie qui vérifie que le drapeau de toutes les x secondes, seulement l'exécution de tous ces sélecteurs/rappels lorsque le DOM a réellement changé.

Qui pourrait encore être vraiment mauvais si vous avez été l'ajout/suppression d'éléments en grand nombre à un rythme rapide (comme l'animation ou de l' __). Avoir à ré-analyser le DOM une fois pour chaque enregistré le sélecteur de toutes les x secondes peut-être trop intense si x est faible, et l'interface semble lent si x est élevé.

Toutes les autres solutions nouvelles?

Je vais ajouter une prime quand il me le permet. J'ai ajouté une aubaine pour la plupart des solution originale!

Fondamentalement, ce que je reçois à est un plus approche orientée aspect de manipulation du DOM. Celui qui peut permettre que de nouveaux éléments vont être créées à l'avenir, et elles doivent être créées avec le document initial.prêt modifications appliquées à eux.

JS a été en mesure de faire beaucoup de magie dernièrement que je suis en espérant qu'il sera évident.

10voto

jAndy Points 93076

À mon avis, les événements DOM Niveau 3 DOMNodeInsertedde l'aide (qui se déclenche seulement pour les nœuds) et DOMSubtreeModifiedde l'aide (qui tire pour pratiquement n'importe quelle modification, comme des modifications d'attributs) sont votre meilleur coup pour accomplir cette tâche.

Bien sûr, le gros point noir de ces événements est que l'Internet des Explorateurs de ce monde ne les supportent pas
(...eh bien, IE9 n').

L'autre solution raisonnable à ce problème, est d'accrocher en toute méthode Qui peut modifier le DOM. Mais alors nous devons nous demander ce qui est à notre portée ici?

Est-il juste assez à faire avec DOM méthodes de modification à partir d'une bibliothèque spécifique, comme jQuery? Que si, pour une raison une autre bibliothèque, c'est de modifier le DOM ou même une méthode native ?

Si c'est juste pour jQuery, nous n'avons pas besoin .sub() à tous. Nous pourrions écrire des crochets sous la forme de:

HTML

<div id="test">Test DIV</div>

JS

(function(_append, _appendTo, _after, _insertAfter, _before, _insertBefore) {
    $.fn.append = function() {
        this.trigger({
            type: 'DOMChanged',
            newnode: arguments[0]
        });
        return _append.apply(this, arguments);
    };
    $.fn.appendTo = function() {
        this.trigger({
            type: 'DOMChanged',
            newnode: this
        });
        return _appendTo.apply(this, arguments);
    };
    $.fn.after = function() {
        this.trigger({
             type: 'DOMChanged',
             newnode: arguments[0]
         });
        return _after.apply(this, arguments);
    };

    // and so forth

}($.fn.append, $.fn.appendTo, $.fn.after, $.fn.insertAfter, $.fn.before, $.fn.insertBefore));

$('#test').bind('DOMChanged', function(e) {
    console.log('New node: ', e.newnode);
});

$('#test').after('<span>new span</span>');
$('#test').append('<p>new paragraph</p>');
$('<div>new div</div>').appendTo($('#test'));

Un exemple vivant de le code ci-dessus peuvent être trouvés ici: http://www.jsfiddle.net/RRfTZ/1/

Bien sûr, cela nécessite une liste complète de DOMmanip méthodes. Je ne suis pas sûr si vous pouvez écraser des méthodes indigènes comme .appendChild() avec cette approche. .appendChild se trouve dans Element.prototype.appendChild par exemple, peut-être la peine d'essayer.

mise à jour

J'ai testé l'écrasement Element.prototype.appendChild etc. dans google Chrome, Safari et Firefox (officiel dernière version). Fonctionne dans Chrome et Safari mais pas sous Firefox!


Il y a peut être d'autres moyens pour faire face à l'exigence. Mais je ne peux pas penser à une seule approche qui est vraiment satisfaisante, comme le comptage / regarder tous les descendants d'un nœud (qui aurait besoin d'un interval ou timeouts, eeek).

Conclusion

Un mélange d'événements DOM Niveau 3 où la prise en charge et accroché DOMmanip méthodes est probablement le meilleur que vous pouvez faire ici.

6voto

arnorhs Points 6107

J'ai été lire sur la nouvelle version de jQuery, la version 1.5 et j'ai immédiatement pensé à cette question.

Avec jQuery 1.5 vous pouvez réellement créer votre propre version de jQuery en utilisant quelque chose qui s'appelle jQuery.sub();

De cette façon, vous pouvez effectivement remplacer la valeur par défaut .append(), insert(), .html(), .. les fonctions de jQuery et créer votre propre événement appelé quelque chose comme "mydomchange" - sans que cela n'affecte tous les autres scripts.

Si vous pouvez faire quelque chose comme ceci (copié à partir de l' .sub() documentation avec de légères mod.):

var sub$ = jQuery.sub();
sub$.fn.insert = function() {
    // New functionality: Trigger a domchange event
    this.trigger("domchange");
    // Be sure to call the original jQuery remove method
    return jQuery.fn.insert.apply( this, arguments );
};

Vous devez faire cela pour toutes les méthodes de manipulation du dom...

jQuery.sub() en jQuery documention: http://api.jquery.com/jQuery.sub/

2voto

arnorhs Points 6107

La grande question

Il semble y avoir un événement personnalisé, vous pouvez lier: http://javascript.gakaa.com/domnodeinserted-description.aspx

Donc je suppose que vous pourriez faire quelque chose comme:

$(document).bind('DOMNodeInserted',function(){ /* do stuff */ });

Mais je n'ai pas essayé donc je n'ai pas la moindre idée..

btw.: question connexe: Peut javascript écouter "onDomChange" sur tous les éléments du Dom?

0voto

MightyE Points 2212

Il n'est pas simple moyen évident de le faire. Le seul infaillible approche active est d'interrogation, ce qui provoque un rendu hoquet entre le moment où le nouvel élément est créé et lors de l'interrogation de la note. Qui peut également rendre votre page prennent beaucoup de ressources en fonction de la fréquence de sondage de la page. Vous pouvez également ajoutez à cela, comme vous l'avez remarqué, avec la liaison de plusieurs navigateur d'événements spécifiques pour au moins faire les choses fonctionnent mieux dans ces navigateurs.

Vous pouvez remplacer jQuery DOM modification des fonctions de déclencher une coutume événement de changement (et l'utilisation de $.vivre pour attraper ces événements pour la manipulation), mais quand je l'ai essayé dans le passé, il est subtilement cassé divers plugins jQuery (je suppose que certains de ces plugins, faire quelque chose de similaire). À la fin, j'ai renoncé à le faire de manière fiable depuis que je ne veux pas renoncer à l'exécution et à rendre le hoquet à l'actif de l'interrogation, et il n'y a pas d'autres éléments de la façon de le faire. Au lieu de cela j'ai une initialisation cas je fais en sorte de déclencheur pour chaque DOM changement que j'ai fait, et je me lient la manipulation des événements de la place.

Attention, il est facile de rester coincé dans une infinité de cas de la boucle si vous n'avez pas penser les choses à travers, et cela peut aussi être subtil et difficile à suivre; et le pire peut encore arriver pour un angle cas, votre appareil de test ne permet pas de (de sorte que vos utilisateurs l'expérience au lieu de simplement vous). La coutume déclenchée manuellement l'initialisation de l'événement est plus facile de diagnostiquer dans ce sens, parce que vous savez toujours exactement où vous êtes le déclenchement d'elle.

-1voto

Erik Reppen Points 2769

Eh bien, tout d’abord, vous ne devriez même pas utiliser des sélecteurs comme celui-ci si vous vous inquiétez pour la performance.

 $('input[type=text], input[type=password], textarea, .basic_form .block select, .order_form .form_item select, .order_form .form_item input')
 

Tout navigateur qui ne possède pas d'implémentations natives de xpath (plus que juste IE iirc) ou de getElementsByClassName (IE 7 et inférieur) pourrait facilement passer quelques secondes à mâcher cela sur un gros site, une interrogation serait donc totalement hors de question. si vous le voulez aussi large.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X