Home > Web Front-end > JS Tutorial > jQuery-1.9.1 Source Code Analysis Series (10) Event Packaging of Event System_jquery

jQuery-1.9.1 Source Code Analysis Series (10) Event Packaging of Event System_jquery

WBOY
Release: 2016-05-16 15:30:50
Original
1213 people have browsed it

In the previous article, I introduced you to the jQuery-1.9.1 source code analysis series (10) event system event architecture. This article continues to introduce to you the relevant knowledge of the jquery1.9.1 source code analysis series. Please see below for details.

First of all, you need to understand that the browser's native events are read-only, which limits jQuery's operations on them. A simple example will help you understand why jQuery must construct a new event object.

In delegation processing, node a delegates node b to execute the fn function when a is clicked. When the event bubbles to node b, the context environment needs to be correct when executing fn. It is node a that executes fn, not node b. How to ensure that the context of executing fn is node a: look at the source code (red part)

//执行
ret = ( (jQuery.event.special[ handleObj.origType ] || {}).handle || handleObj.handler ).apply( matched.elem, args );

Copy after login

Use apply to replace the context of the execution function with a node (matched.elem). Another point is that args[0] is the event object event. How to ensure that the event is an event of node a? This is the function of the important attribute event.currentTarget, so one step is done before executing apply

event.currentTarget = matched.elem;
Copy after login

Directly change the currentTarget property of the event object, which is not possible in browser local events. That's why we have jQuery's event object constructed based on local events.

There are two types of events: mouse events and keyboard events (I don’t know when touch events can be added). Take a look at the detailed properties of these two

 

Some of them are browser-specific and not W3C standards. jQuery divides event properties into three parts

Properties shared by mouse and keyboard events jQuery.event.props: "altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" ")

Keyboard event-specific properties jQuery.event.keyHooks.props: "char charCode key keyCode".split(" ")

Mouse event-specific properties jQuery.event.mouseHooks.props: "button buttons clientX clientY fromElement offsetX offsetY pageX pageY screenX screenY toElement".split(" ")

a. Construct a new event object jQuery.event.fix(originalEvent)

Constructing a new event object is completed in three steps

In the first step, use event = new jQuery.Event(originalEvent) to construct a new event object (if you don’t understand the role of new, please click here), and add isDefaultPrevented, originalEvent, type, and timeStamp when creating the event. And the event has been corrected mark (optimized use to avoid unnecessary processing). The source code of jQuery.Event(src, props) is as follows

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;
};
Copy after login

The event object constructed in the first step

 

The second step is to identify what kind of event the current event is, and then copy the corresponding attributes one by one from the browser's local event originalEvent

 //创建可写的事件对象副本,并格式化一些特征名称
  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 ];
  }
Copy after login

The third step is compatibility processing of related attributes

 // IE<9修正target特征值
  if ( !event.target ) {
    event.target = originalEvent.srcElement || document;
  }
  // Chrome 23+, Safari&#63;,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 &#63; fixHook.filter( event, originalEvent ) : event;
Copy after login

The last line of code performs compatible adaptation processing for mouse events and keyboard events.

fixHook.filter may be jQuery.event.keyHooks.filter

keyHooks.filter: function( event, original ) {
  //给键盘事件添加which特征值
  if ( event.which == null ) {
    event.which = original.charCode != null &#63; original.charCode : original.keyCode;
  }
  return event;
}
Copy after login

or this 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 &#63; original.toElement : fromElement;
  }
  //添加点击事件which特征值: 1 === left; 2 === middle; 3 === right
  //备注:button不标准,因此不要是使用
  if ( !event.which && button !== undefined ) {
    event.which = ( button & 1 &#63; 1 : ( button & 2 &#63; 3 : ( button & 4 &#63; 2 : 0 ) ) );
  }
  return event;
}
Copy after login

The latest event object completed is as follows (taking mouse events as an example)

 

Original events are saved in originalEvent, target saves the target node (delegated node, event source), and other information is skipped

b. Overload event method

When constructing a new event object event = new jQuery.Event(originalEvent), the event will inherit the methods in jQuery.event.prototype. Let’s take a look at the methods

 

We previously analyzed the role of the overloaded stopPropagation method in jQuery.event.prototype: in addition to calling the event object's method to prevent bubbling, there is also a role when the delegated node has multiple delegated events waiting to be processed. , one of the events calling event.stopPropagation() will prevent the execution of subsequent event processing. Click here to search for keywords to view

The preventDefault function also has a similar effect. This code was added to the preventDefault function

this.isPropagationStopped = returnTrue;
Copy after login

在触发事件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();
  }
}
Copy after login

以上就是本文给大家介绍的jQuery-1.9.1源码分析系列(十)事件系统之事件包装,希望大家喜欢。

source:php.cn
Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn
Popular Tutorials
More>
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template