Dans l'article précédent, je vous ai présenté l'architecture d'événements du système d'événements de la série d'analyses de code source jQuery-1.9.1 (10) Cet article continue de vous présenter les connaissances pertinentes de jquery1. 9.1 série d'analyses du code source Veuillez voir ci-dessous pour plus de détails.
Tout d'abord, vous devez comprendre que les événements natifs du navigateur sont en lecture seule, ce qui limite les opérations de jQuery sur ceux-ci. Un exemple simple vous aidera à comprendre pourquoi jQuery doit construire un nouvel objet événement.
Dans le traitement de la délégation, le nœud a délègue le nœud b pour exécuter la fonction fn lorsque l'on clique sur a. Lorsque l'événement se propage vers le nœud b, l'environnement contextuel doit être correct lors de l'exécution de fn. C'est le nœud a qui exécute fn, pas le nœud b. Comment s'assurer que le contexte d'exécution de fn est le nœud a : regardez le code source (partie rouge)
//执行 ret = ( (jQuery.event.special[ handleObj.origType ] || {}).handle || handleObj.handler ).apply( matched.elem, args );
Utilisez apply pour remplacer le contexte de la fonction d'exécution par un nœud (matched.elem). Un autre point est que args[0] est l'événement objet événement. Comment s'assurer que l'événement est un événement du nœud a ? C'est la fonction de l'attribut important event.currentTarget, donc une étape est effectuée avant d'exécuter apply
event.currentTarget = matched.elem;
Modifiez directement la propriété currentTarget de l'objet événement, ce qui n'est pas possible dans les événements locaux du navigateur. C'est pourquoi l'objet événement de jQuery est construit sur la base d'événements locaux.
Il existe deux types d'événements : les événements de souris et les événements de clavier (je ne sais pas quand des événements tactiles peuvent être ajoutés). Jetez un œil aux propriétés détaillées de ces deux
Certains d'entre eux sont spécifiques au navigateur et non aux normes du W3C. jQuery divise les propriétés des événements en trois parties
Propriétés partagées par les événements de souris et de clavier jQuery.event.props : "bulles altKey annulables ctrlKey currentTarget eventPhase metaKey RelatedTarget shiftKey target timeStamp view which".split(" ")
Propriétés spécifiques aux événements de clavier jQuery.event.keyHooks.props : "char charCode key keyCode".split(" ")
Propriétés spécifiques aux événements de la souris jQuery.event.mouseHooks.props : "bouton boutons clientX clientY fromElement offsetX offsetY pageX pageY screenX screenY toElement".split(" ")
a. Construire un nouvel objet événement jQuery.event.fix(originalEvent)
La construction d'un nouvel objet événementiel se déroule en trois étapes
Dans la première étape, utilisez event = new jQuery.Event(originalEvent) pour construire un nouvel objet événement (si vous ne comprenez pas le rôle de new, veuillez cliquer ici), et ajoutez isDefaultPrevented, originalEvent, tapez et timeStamp lors de la création de l'événement. Et l'événement a été corrigé (utilisation optimisée pour éviter des traitements inutiles). Le code source de jQuery.Event(src, props) est le suivant
jQuery.Event = function( src, props ) { // Allow instantiation without the 'new' keyword if ( !(this instanceof jQuery.Event) ) { return new jQuery.Event( src, props ); } //src为事件对象 if ( src && src.type ) { this.originalEvent = src; this.type = src.type; //事件冒泡的文档可能被标记为阻止默认事件发生;这个函数可以反应是否阻止的标志的正确值 this.isDefaultPrevented = ( src.defaultPrevented || src.returnValue === false || src.getPreventDefault && src.getPreventDefault() ) ? returnTrue : returnFalse; //src为事件类型 } else { this.type = src; } //将明确提供的特征添加到事件对象上 if ( props ) { jQuery.extend( this, props ); } //创建一个时间戳如果传入的事件不只一个 this.timeStamp = src && src.timeStamp || jQuery.now(); //标记事件已经修正过 this[ jQuery.expando ] = true; };
L'objet événement construit dans la première étape
La deuxième étape consiste à identifier de quel type d'événement il s'agit, puis à copier les attributs correspondants un par un à partir de l'événement local originalEvent du navigateur
//创建可写的事件对象副本,并格式化一些特征名称 var i, prop, copy, type = event.type, originalEvent = event, fixHook = this.fixHooks[ type ]; if ( !fixHook ) { this.fixHooks[ type ] = fixHook = //rmouseEvent=/^(?:mouse|contextmenu)|click/ rmouseEvent.test( type ) ? this.mouseHooks : //rkeyEvent=/^key/ rkeyEvent.test( type ) ? this.keyHooks : {}; } //获得要从原生事件中拷贝过来的属性列表 copy = fixHook.props ? this.props.concat( fixHook.props ) : this.props; ... //将原生的属性都拷贝到新的事件上 i = copy.length; while ( i-- ) { prop = copy[ i ]; event[ prop ] = originalEvent[ prop ]; }
La troisième étape est le traitement de compatibilité des attributs associés
// IE<9修正target特征值 if ( !event.target ) { event.target = originalEvent.srcElement || document; } // Chrome 23+, Safari?,Target特征值不能是文本节点 if ( event.target.nodeType === 3 ) { event.target = event.target.parentNode; } // IE<9,对于鼠标/键盘事件, 如果metaKey没有定义则设置metaKey==false event.metaKey = !!event.metaKey; //调用hooks的filter return fixHook.filter ? fixHook.filter( event, originalEvent ) : event;
La dernière ligne de code effectue un traitement d'adaptation compatible pour les événements de souris et les événements de clavier.
fixHook.filter peut être jQuery.event.keyHooks.filter
keyHooks.filter: function( event, original ) { //给键盘事件添加which特征值 if ( event.which == null ) { event.which = original.charCode != null ? original.charCode : original.keyCode; } return event; }
ou ce jQuery.event.mouseHooks.filter
mouseHooks.filter: function( event, original ) { var body, eventDoc, doc, button = original.button, fromElement = original.fromElement; //如果事件pageX/Y特征不见了,用可用的clientX/Y来计算出来 if ( event.pageX == null && original.clientX != null ) { eventDoc = event.target.ownerDocument || document; doc = eventDoc.documentElement; body = eventDoc.body; event.pageX = original.clientX + ( doc && doc.scrollLeft || body && body.scrollLeft || 0 ) - ( doc && doc.clientLeft || body && body.clientLeft || 0 ); event.pageY = original.clientY + ( doc && doc.scrollTop || body && body.scrollTop || 0 ) - ( doc && doc.clientTop || body && body.clientTop || 0 ); } //如果必要的话添加relatedTarget特征 if ( !event.relatedTarget && fromElement ) { event.relatedTarget = fromElement === event.target ? original.toElement : fromElement; } //添加点击事件which特征值: 1 === left; 2 === middle; 3 === right //备注:button不标准,因此不要是使用 if ( !event.which && button !== undefined ) { event.which = ( button & 1 ? 1 : ( button & 2 ? 3 : ( button & 4 ? 2 : 0 ) ) ); } return event; }
Le dernier objet événement complété est le suivant (en prenant les événements de souris comme exemple)
Les événements d'origine sont enregistrés dans originalEvent, la cible enregistre le nœud cible (nœud délégué, source d'événement) et les autres informations sont ignorées
b. Méthode d'événement de surcharge
Lors de la construction d'un nouvel objet événement event = new jQuery.Event(originalEvent), l'événement héritera des méthodes de jQuery.event.prototype. Jetons un coup d'œil aux méthodes
Nous avons précédemment analysé le rôle de la méthode stopPropagation surchargée dans jQuery.event.prototype : en plus d'appeler la méthode de l'objet événement pour éviter le bouillonnement, il existe également un rôle lorsque le nœud délégué a plusieurs événements délégués en attente de traitement. , l'un des événements appelant event.stopPropagation() empêchera l'exécution du traitement événementiel ultérieur. Cliquez ici pour rechercher des mots-clés à afficher
La fonction PreventDefault a également un effet similaire. Ce code a été ajouté à la fonction PreventDefault
this.isPropagationStopped = returnTrue;
在触发事件trigger函数和模拟冒泡simulate函数中都会根据isPropagationStopped()判断是否要执行DOM节点的默认操作。源码如下
isImmediatePropagationStopped是stopPropagation特殊用法,isImmediatePropagationStopped会直接阻止掉当前的处理和后面等待执行的事件处理,而stopPropagation会执行完当前的处理,然后阻止后面等待执行的事件处理。
源码如下
// jQuery.Event基于DOM事件所指定的ECMAScript语言绑定 // http://www.w.org/TR//WD-DOM-Level--Events-/ecma-script-binding.html jQuery.Event.prototype = { isDefaultPrevented: returnFalse, isPropagationStopped: returnFalse, isImmediatePropagationStopped: returnFalse, preventDefault: function() { var e = this.originalEvent; this.isDefaultPrevented = returnTrue; if ( !e ) {return; } if ( e.preventDefault ) { e.preventDefault(); //IE支持 } else { e.returnValue = false; } }, stopPropagation: function() { var e = this.originalEvent; this.isPropagationStopped = returnTrue; if ( !e ) {return; } if ( e.stopPropagation ) { e.stopPropagation(); } // IE支持 e.cancelBubble = true; }, stopImmediatePropagation: function() { this.isImmediatePropagationStopped = returnTrue; this.stopPropagation(); } }
以上就是本文给大家介绍的jQuery-1.9.1源码分析系列(十)事件系统之事件包装,希望大家喜欢。