jQuery实战教程源码系列(十四)自定义事件
沉沙 2018-07-10 来源 : 阅读 1019 评论 0

摘要:本篇jQuery教程通过代码讲解了自定义事件,希望阅读本篇文章以后大家有所收获,帮助大家对jQuery的理解更加深入。

原生事件

其实 JS 的原生事件已经做得挺好了,只是 jQuery 将其进行封装,做的更好。

关于 document.createEvent,下面是一个简单的事件点击的例子:

var fn = function(){
  console.log('click');
}
var button = document.getElementById('#id');
button.addEventListener('click', fn);
// 点击事件 MouseEventvar myClick = document.createEvent('MouseEvent');
myClick.initMouseEvent('click', false, false, null);
// 执行
button.dispatchEvent(myClick); // 'click'

   

除了鼠标事件,还可以自定义事件:

// 随便自定义一个事件 test.click
button.addEventListener('test.click', fn);
var testEvent = document.createEvent('CustomEvent');// customEvent 也可以初始化为鼠标事件,不一定非要自定义事件
testEvent.initCustomEvent('test.click', false, false, null);
 
button.dispatchEvent(testEvent); // 'click'

   

JS 原生的模拟事件,使用起来还是很方便的,以上便是原生的。

不过 jQuery 也有自己的一套自定义事件方案。

jQuery.trigger

jQuery.trigger 可以和 HTMLElement.dispatchEvent 事件拿来对比,他们都是用来模拟和执行监听的事件。

如何使用

关于使用,则比较简单了.trigger():

var $body = $(document.body);
// 先绑定事件
$body.on('click', function(){
  console.log('click');
})
// 执行
$body.trigger('click'); //'click'

   

trigger 还支持更多的参数,同样可以自定义事件:

$body.on('click.test', function(e, data1, data2){
  console.log(data1 + '-' + data2);
})
 
$body.trigger('click.test', ['hello', 'world']);

   

trigger 源码

trigger 的源码有些简单,因为还是要借助于 jQuery.event 来处理:

 
jQuery.fn.extend( {
  trigger: function(type, data){
    return this.each(function(){
      jQuery.event.trigger(type, data, this);
    })
  },
  // triggerHandler 处理第一个且不触发默认事件
  triggerHandler: function( type, data ) {
    var elem = this[ 0 ];
    if ( elem ) {
      return jQuery.event.trigger( type, data, elem, true );
    }
  }
} );

   

所以 trigger 事件的起点又回到了 jQuery.event。

jQuery.event.trigger

其实 trigger 和 add + handler 函数很类似,大致都是从 data cache 中搜索缓存,执行回调函数。需要考虑要不要执行默认事件,即第四个参数为 true 的情况。

jQuery.extend(jQuery.event, {
  // onleyHandlers 表示不考虑冒泡事件
  trigger: function( event, data, elem, onlyHandlers ) {
 
    var i, cur, tmp, bubbleType, ontype, handle, special,
      eventPath = [ elem || document ],
      type = hasOwn.call( event, "type" ) ? event.type : event,
      namespaces = hasOwn.call( event, "namespace" ) ? event.namespace.split( "." ) : [];
 
    cur = tmp = elem = elem || document;
 
    // Don't do events on text and comment nodes
    if ( elem.nodeType === 3 || elem.nodeType === 8 ) {
      return;
    }
 
    // 异步不冲突
    if ( rfocusMorph.test( type + jQuery.event.triggered ) ) {
      return;
    }
 
    if ( type.indexOf( "." ) > -1 ) {
 
      // Namespaced trigger; create a regexp to match event type in handle()
      namespaces = type.split( "." );
      type = namespaces.shift();
      namespaces.sort();
    }
    ontype = type.indexOf( ":" ) < 0 && "on" + type;
 
    // 改装原生的 event 事件
    event = event[ jQuery.expando ] ?
      event :
      new jQuery.Event( type, typeof event === "object" && event );
 
    // 判断是否只执行当前 trigger 事件,不冒泡
    event.isTrigger = onlyHandlers ? 2 : 3;
    event.namespace = namespaces.join( "." );
    event.rnamespace = event.namespace ?
      new RegExp( "(^|\\.)" + namespaces.join( "\\.(?:.*\\.|)" ) + "(\\.|$)" ) :
      null;
 
    // Clean up the event in case it is being reused
    event.result = undefined;
    if ( !event.target ) {
      event.target = elem;
    }
 
    // Clone any incoming data and prepend the event, creating the handler arg list
    data = data == null ?
      [ event ] :
      jQuery.makeArray( data, [ event ] );
 
    // Allow special events to draw outside the lines
    special = jQuery.event.special[ type ] || {};
    if ( !onlyHandlers && special.trigger && special.trigger.apply( elem, data ) === false ) {
      return;
    }
 
    // 向 document 冒泡并把冒泡结果存储到 eventPath 数组中
    if ( !onlyHandlers && !special.noBubble && !jQuery.isWindow( elem ) ) {
 
      bubbleType = special.delegateType || type;
      if ( !rfocusMorph.test( bubbleType + type ) ) {
        cur = cur.parentNode;
      }
      for ( ; cur; cur = cur.parentNode ) {
        eventPath.push( cur );
        tmp = cur;
      }
 
      // Only add window if we got to document (e.g., not plain obj or detached DOM)
      if ( tmp === ( elem.ownerDocument || document ) ) {
        eventPath.push( tmp.defaultView || tmp.parentWindow || window );
      }
    }
 
    // 按需求来执行
    i = 0;
    while ( ( cur = eventPath[ i++ ] ) && !event.isPropagationStopped() ) {
 
      event.type = i > 1 ?
        bubbleType :
        special.bindType || type;
 
      // 从 data cache 中获得回调函数
      handle = ( dataPriv.get( cur, "events" ) || {} )[ event.type ] &&
        dataPriv.get( cur, "handle" );
      if ( handle ) {
        // 执行
        handle.apply( cur, data );
      }
 
      // Native handler
      handle = ontype && cur[ ontype ];
      if ( handle && handle.apply && acceptData( cur ) ) {
        event.result = handle.apply( cur, data );
        if ( event.result === false ) {
          event.preventDefault();
        }
      }
    }
    event.type = type;
 
    // If nobody prevented the default action, do it now
    if ( !onlyHandlers && !event.isDefaultPrevented() ) {
 
      if ( ( !special._default ||
        special._default.apply( eventPath.pop(), data ) === false ) &&
        acceptData( elem ) ) {
 
        // Call a native DOM method on the target with the same name as the event.
        // Don't do default actions on window, that's where global variables be (#6170)
        if ( ontype && jQuery.isFunction( elem[ type ] ) && !jQuery.isWindow( elem ) ) {
 
          // Don't re-trigger an onFOO event when we call its FOO() method
          tmp = elem[ ontype ];
 
          if ( tmp ) {
            elem[ ontype ] = null;
          }
 
          // Prevent re-triggering of the same event, since we already bubbled it above
          jQuery.event.triggered = type;
          elem[ type ]();
          jQuery.event.triggered = undefined;
 
          if ( tmp ) {
            elem[ ontype ] = tmp;
          }
        }
      }
    }
 
    return event.result;
  },
})

   

本文由职坐标整理发布,学习更多的jQuery相关知识,请关注职坐标WEB前端jQuery频道!

本文由 @沉沙 发布于职坐标。未经许可,禁止转载。
喜欢 | 0 不喜欢 | 0
看完这篇文章有何感觉?已经有0人表态,0%的人喜欢 快给朋友分享吧~
评论(0)
后参与评论

您输入的评论内容中包含违禁敏感词

我知道了

助您圆梦职场 匹配合适岗位
验证码手机号,获得海同独家IT培训资料
选择就业方向:
人工智能物联网
大数据开发/分析
人工智能Python
Java全栈开发
WEB前端+H5

请输入正确的手机号码

请输入正确的验证码

获取验证码

您今天的短信下发次数太多了,明天再试试吧!

提交

我们会在第一时间安排职业规划师联系您!

您也可以联系我们的职业规划师咨询:

小职老师的微信号:z_zhizuobiao
小职老师的微信号:z_zhizuobiao

版权所有 职坐标-一站式IT培训就业服务领导者 沪ICP备13042190号-4
上海海同信息科技有限公司 Copyright ©2015 www.zhizuobiao.com,All Rights Reserved.
 沪公网安备 31011502005948号    

©2015 www.zhizuobiao.com All Rights Reserved

208小时内训课程