Foros del Web » Programando para Internet » Jquery »

live de jQuery + registro de eventos JSPlus

Estas en el tema de live de jQuery + registro de eventos JSPlus en el foro de Jquery en Foros del Web. Puede que los moderadores ya tomen esto como una provocación por poner este tema en JS y no en frameworks La verdad es que por ...
  #1 (permalink)  
Antiguo 22/09/2011, 16:21
Avatar de _cronos2
Colaborador
 
Fecha de Ingreso: junio-2010
Mensajes: 2.062
Antigüedad: 14 años, 5 meses
Puntos: 310
live de jQuery + registro de eventos JSPlus

Puede que los moderadores ya tomen esto como una provocación por poner este tema en JS y no en frameworks La verdad es que por el título podría parecer que debería en el otro sitio, pero a mi juicio la cosa tiene más que ver con JS puro y duro que con un framework.
Y voy a empezar cuál es el problema que he encontrado, o los problemas
El primero es la implementación del método live de jQuery. Tras rebuscar en el código fuente, me di cuenta de que en la documentación explica cómo funciona (), así que intenté comprenderlo.
Cita:
Iniciado por jQuery
Event Delegation
The .live() method is able to affect elements that have not yet been added to the DOM through the use of event delegation: a handler bound to an ancestor element is responsible for events that are triggered on its descendants. The handler passed to .live() is never bound to an element; instead, .live() binds a special handler to the root of the DOM tree. In the example above, when the new element is clicked, the following steps occur:

A click event is generated and passed to the <div> for handling.
No handler is directly bound to the <div>, so the event bubbles up the DOM tree.
The event bubbles up until it reaches the root of the tree, which is where .live() binds its special handlers by default.
* As of jQuery 1.4, event bubbling can optionally stop at a DOM element "context".
The special click handler bound by .live() executes.
This handler tests the target of the event object to see whether it should continue. This test is performed by checking if $(event.target).closest(".clickme") is able to locate a matching element.
If a matching element is found, the original handler is called on it.
Because the test in step 5 is not performed until the event occurs, elements can be added at any time and still respond to events.
Tal y como yo lo entiendo, que seguramente estaré equivocado, se le agrega un evento click al elemento html, y después se comprueba desde html que donde realmente se originó el evento fue en un elemento que es .clickme . Según esto, para click por ejemplo no hay problemas, pero si un input recibe el foco yo diría que el evento no bubblea hacia arriba.
Entonces la pregunta es: ¿cómo funciona live?

Mi segunda duda viene de mi intento de framework Este verano (o invierno, depende de quien lo lea) implementé un bind, unbind y trigger bastante básicos. Cuando se suponía que funcionaba lo di por terminado, sin embargo hace poco me di cuenta de un fallo que no he podido resolver. Pego el código:
Código Javascript:
Ver original
  1. // Eventos
  2.   eventos : {}, // Contenedor de los eventos [JSPlus]
  3.   enlazar : function(tipo, toDo, capture){ // jQuery -> bind
  4.    this.eventos[tipo] = this.eventos[tipo] || []; // Si no existe usamos un array vacío
  5.    var lisnrs = this.eventos[tipo]; // lisnrs -> la lista de eventos [JSPlus]
  6.    var este = this; // Referencia
  7.    toDo.realHandler = function(e){ // Función que se usará para evento, para ejecutar se usa toDo
  8.     // Invocamos la función, y si devuelve false usamos preventDefault y stopPropagation
  9.     if(toDo.call(este, e) === false){ // return false;
  10.      // IE
  11.      e.returnValue = false; // preventDefault
  12.      e.cancelBubble = true; // stopPropagation
  13.      // Chrome, FF, Opera...
  14.      if(e.preventDefault){ // Si existe preventDefault entonces también stopPropagation
  15.       e.preventDefault();
  16.       e.stopPropagation();
  17.      }
  18.     }
  19.    };
  20.    lisnrs.push(toDo); // Añadimos toDo a lisnrs -> eventos [JSPlus]
  21.    toDo.capture = capture; // Seteamos el capture
  22.    this.evento(tipo, toDo.realHandler, capture);
  23.    return this;
  24.   },
  25.   desenlazar : function(tipo, id){ // jQuery -> unbind
  26.    this.eventos[tipo] = this.eventos[tipo] || []; // Si no existe usamos un array vacío
  27.    var lisnrs = this.eventos[tipo]; // lisnrs -> la lista de eventos [JSPlus]
  28.    if(!id){ // Si no hay un id se borran todos
  29.     var este = this; // Referencia
  30.     lisnrs.forEach(function(fn){ este.borrarEvento(tipo, fn.realHandler, fn.capture); }); // Borramos los listeners
  31.     this.eventos[tipo] = []; // Borramos los handlers del eventos [JSPlus]
  32.     return this;
  33.    }
  34.    var fn; // Referencia al handler para poder usar borrarEvento
  35.    switch(typeof id){ // Aceptamos diferentes tipos de if
  36.     case 'string' : // Si es un string, comprobamos que sean iguales con toString
  37.      lisnsrs.forEach(function(act, i){ act.toString() == id && (fn = lisnrs.splice(i, 1)); });
  38.     break;
  39.     case 'number' : // Si es un número, accedemos a la lista de listeners y borramos ese índice
  40.      lisnrs[i] && (fn = lisnrs.splice(i, 1));
  41.     break;
  42.     case 'function' : // Si es un handler, lo buscamos en la lista
  43.      lisnsrs.forEach(function(act, i){ act == id && (fn = lisnrs.splice(i, 1)); });
  44.     break;
  45.    }
  46.    this.borrarEvento(tipo, fn.realHandler, fn.capture); // Usamos el realHandler para borrar
  47.    return this;
  48.   },
  49.   ejecutar : function(tipo, args){ // jQuery -> trigger
  50.    var lisnrs = this.eventos[tipo] = this.eventos[tipo] || [], este = this; // lisnrs -> la lista de eventos, y si no existe un array vacío
  51.    lisnrs.forEach(function(fn){ fn.apply(este, args); }); // Recorremos la lista de eventos y ejecutamos cada función
  52.    return this;
  53.   },
  54.   evento : function(tipo, toDo, capture){
  55.    if(this.addEventListener){ // Chrome, FF, Opera...
  56.     this.addEventListener(tipo, toDo, capture);
  57.    }else if(this.attachEvent){ // IE
  58.     var este = this, fn = function(){ toDo.call(este, window.event); };
  59.     this.attachEvent('on' + tipo, fn);
  60.     this[toDo.toString() + tipo] = fn;
  61.    }else{
  62.     var fn = this['on' + tipo] || function(){};
  63.     this['on' + tipo] = function(){ fn(); toDo(); };
  64.    }
  65.    return this;
  66.   },
El código es bastante espeso, pero en principio el fallo estaría en la función enlazar. El problema es que al hacer algo como esto:
Código Javascript:
Ver original
  1. P('div').click(function(){
  2.  // stuff
  3. });
  4.  
  5. P('#clickme').click(function(){
  6.  // more stuff
  7. });
Al mirar los eventos registrados en el click de cualquier div, debería aparecer sólo la función stuff. Igual, al mirar los de #clickme, debería aparecer sólo more stuff. Sin embargo, salen las dos funciones en todos los elementos del DOM. Si en vez de 2 funciones hubiera 7 pasaría lo mismo: todas las funciones de un tipo de evento salen al mirar los eventos de ese tipo de todo el DOM. Para que se me entienda bien, en el ejemplo anterior:
Código Javascript:
Ver original
  1. P('body').eventos.click; // Se supone que undefined, pero en realidad
  2. /*
  3. [function(){
  4.  // stuff
  5. }, function(){
  6.  // more stuff
  7. }]
  8. */
Pensé que el problema podía ser this, pero al hacer un console.log de this dentro de la función me da el elemento correcto.
Así que, la segunda pregunta es: ¿WTF está pasando aquí dentro?
Puede que me haya explicado fatal y que no me entienda nadie, así que por favor si el texto es ininteligible decídmelo y trataré de explicarme mejor
Saludos y gracias :D
__________________
" Getting older’s not been on my plans
but it’s never late, it’s never late enough for me to stay. "
Cigarettes - Russian Red
  #2 (permalink)  
Antiguo 22/09/2011, 17:10
Avatar de zerokilled
Javascripter
 
Fecha de Ingreso: abril-2009
Ubicación: Isla del Encanto, La Borinqueña [+>==]
Mensajes: 8.050
Antigüedad: 15 años, 6 meses
Puntos: 1485
Respuesta: live de jQuery + registro de eventos JSPlus

buenas,
es cierto que focus al igual que otros eventos no burbujean. sin embargo, ¿cómo lo hace jquery? la verdad no lo sé y tampoco he revisado muy bien el código fuente. no obstante, asumo yo que el truco esta en el método de captura. es decir, en lugar de capturar el evento en la fase bubble, se captura en la fase capture el cual es cuando el objeto se propaga desde el nivel más alto en la jerarquía (usualmente self) hasta llegar al elemento que lo inicio. esto se logra indicando true en el tercer argumento de addEventListener. por desgracia, iexplorer tiene un modelo distinto el cual no comprende los diferentes tipos de fases y solo admite bubbling. desconozco si esto ha cambiado en las últimas versiones de iexplorer, al menos en el 8 sigue siendo el modelo de siempre. supongo que en teoría eso es lo que hace jquery y quizas con algo adicional para darle soporte a iexplorer. si miras el código fuente de jquery sin compresar, busca un comentario que cita // Create "bubbling" focus and blur events. como no tengo ánimo de interpretar el código jquery, pues no estoy seguro si lo antes explicado es como jquery lo implementa.

sobre la segunda duda, como de costumbre, recuerda poner un enlace de una copia reciente de JPlus. seguro han habido cambios. más que nada para que otros puedan realizar las pruebas.

__________________
la maldad es una virtud humana,
y la espiritualidad es la lucha del hombre contra su maldad.
  #3 (permalink)  
Antiguo 23/09/2011, 10:42
Avatar de _cronos2
Colaborador
 
Fecha de Ingreso: junio-2010
Mensajes: 2.062
Antigüedad: 14 años, 5 meses
Puntos: 310
Respuesta: live de jQuery + registro de eventos JSPlus

Pues sí, es cierto, jQuery usa el método capture para los eventos. Sin embargo no he sido capaz de dilucidar qué hacen en IE8 e inferior, tendré que releerlo a ver si puedo sacar algo en claro de esa maraña de código

Cita:
Iniciado por zerokilled
sobre la segunda duda, como de costumbre, recuerda poner un enlace de una copia reciente de JPlus. seguro han habido cambios. más que nada para que otros puedan realizar las pruebas.
Y como de costumbre, a mí se me olvidó y tiene que venir @zerokilled a recordármelo porque soy un desastre Lamentablemente el hosting gratuito está teniendo problemas y no me deja subir .js, así que lo puse en pastebin. Como decía, el problema debería de venir de enlazar, porque es ahí donde se hace el push, pero no encontré nada sospechoso.
Saludos y gracias (:
__________________
" Getting older’s not been on my plans
but it’s never late, it’s never late enough for me to stay. "
Cigarettes - Russian Red
  #4 (permalink)  
Antiguo 23/09/2011, 22:03
Avatar de zerokilled
Javascripter
 
Fecha de Ingreso: abril-2009
Ubicación: Isla del Encanto, La Borinqueña [+>==]
Mensajes: 8.050
Antigüedad: 15 años, 6 meses
Puntos: 1485
Respuesta: live de jQuery + registro de eventos JSPlus

¡que tal va el asunto, cronos!
el problema esta en la linea marcada en negrita.
Código:
// de la variable privado ;
 enlazar: function (tipo, toDo, capture) { // jQuery -> bind
            console.log('this', this);
            this.eventos[tipo] = this.eventos[tipo] || []; // Si no existe usamos un array vacío
            var lisnrs = this.eventos[tipo]; // lisnrs -> la lista de eventos [JSPlus]
            ...
        },
recuerda que los objetos se pasan por referencia. cuando tu aplicas extender a un elemento, le estas asignando una referencia de la propiedad eventos en privado al elemento. de modo que elemento.eventos es el mismo objeto que privado.eventos. por tanto, cualquier cambio que tu le hagas, se va ver reflejado en todos los elementos extendidos. la solución debería ser crear un objeto eventos único al extender elementos.

offtopic: si bien recuerdo, hace como un mes alguien tuvo un problema parecido. no recuerdo el tema, pero creo que participaron panino5001 y aijona.
__________________
la maldad es una virtud humana,
y la espiritualidad es la lucha del hombre contra su maldad.
  #5 (permalink)  
Antiguo 24/09/2011, 14:54
Avatar de _cronos2
Colaborador
 
Fecha de Ingreso: junio-2010
Mensajes: 2.062
Antigüedad: 14 años, 5 meses
Puntos: 310
Respuesta: live de jQuery + registro de eventos JSPlus

Cita:
Iniciado por zerokilled
de modo que elemento.eventos es el mismo objeto que privado.eventos.
Obvio! Debería haberme dado cuenta De hecho, este fallo también se aplica a la cola de efectos, puesto que es un array. Deberé hacer alguna reestructuración importante
Saludos y gracias (:
__________________
" Getting older’s not been on my plans
but it’s never late, it’s never late enough for me to stay. "
Cigarettes - Russian Red
  #6 (permalink)  
Antiguo 03/10/2011, 16:09
Avatar de Panino5001
Me alejo de Omelas
 
Fecha de Ingreso: mayo-2004
Ubicación: -34.637167,-58.462984
Mensajes: 5.148
Antigüedad: 20 años, 5 meses
Puntos: 834
Respuesta: live de jQuery + registro de eventos JSPlus

No sé si ya resolviste esto, pero si no, quizá te interese ver los eventos focusin y focusout, que sí burbujean, y que imagino es lo que usa jQuery
http://help.dottoro.com/ljmusasd.php

Etiquetas: eventos, funcion, html, js, live, registro
Atención: Estás leyendo un tema que no tiene actividad desde hace más de 6 MESES, te recomendamos abrir un Nuevo tema en lugar de responder al actual.
Respuesta




La zona horaria es GMT -6. Ahora son las 08:46.