jQuery源码分析之Event事件分析

对于事件的操作无非是addEvent,fireEvent,removeEvent这三个事 件方法。一般lib都会对浏览器的提供的函数做一些扩展,解决兼容性内存泄漏等问题。第三个问题就是如何得到domReady的状态。
  6.1 event的包裹

  浏览器的事件兼容性是一个令人头疼的问题。IE的event在是在全局的window下, 而mozilla的event是事件源参数传入到回调函数中。还有很多的事件处理方式也一样。

  Jquery提供了一个 event的包裹,这个相对于其它的lib提供的有点简单,但是足够使用。


代码如下:

//对事件进行包裹。
  fix : function(event) {
    if (event[expando] == true) return event;//表明事件已经包裹过
    //保存原始event,同时clone一个。
    var originalEvent = event;                ①
    event = { originalEvent : originalEvent};
    for (var i = this.props.length, prop;i;) {
       prop = this.props[--i];
      event[prop] = originalEvent[prop];
     }   
    event[expando] = true;   
    //加上preventDefault and stopPropagation,在clone不会运行
    event.preventDefault = function() {          ②
      // 在原始事件上运行
      if (originalEvent.preventDefault)
       originalEvent.preventDefault();
       originalEvent.returnValue = false;
    };
    event.stopPropagation = function() {
      // 在原始事件上运行
      if (originalEvent.stopPropagation)
        originalEvent.stopPropagation();
      originalEvent.cancelBubble = true;
    };
    // 修正 timeStamp
    event.timeStamp = event.timeStamp || now();
    // 修正target
    if (!event.target)                    ③
      event.target = event.srcElement || document;    
    if (event.target.nodeType == 3)//文本节点是父节点。
      event.target = event.target.parentNode;
    // relatedTarget
    if (!event.relatedTarget && event.fromElement)   ④
      event.relatedTarget = event.fromElement == event.target
         ? event.toElement : event.fromElement;
     // Calculate pageX/Y if missing and clientX/Y available
    if (event.pageX == null && event.clientX != null) { ⑥
      var doc = document.documentElement, body = document.body;
     event.pageX = event.clientX
       + (doc && doc.scrollLeft || body && body.scrollLeft || 0)
         - (doc.clientLeft || 0);
      event.pageY = event.clientY
       + (doc && doc.scrollTop || body && body.scrollTop || 0)
         - (doc.clientTop || 0);
    }
  
    // Add which for key events
   if (!event.which && ((event.charCode || event.charCode === 0) ⑦
            ? event.charCode : event.keyCode))
      event.which = event.charCode || event.keyCode;
  
  // Add metaKey to non-Mac browsers
    if (!event.metaKey && event.ctrlKey)            ⑧
      event.metaKey = event.ctrlKey;
   // Add which for click: 1 == left; 2 == middle; 3 == right
  // Note: button is not normalized, so don't use it
    if (!event.which && event.button)             ⑨
      event.which = (event.button & 1 ? 1 : (event.button & 2
         ? 3 : (event.button & 4 ? 2 : 0)));
    return event;
},

  上面的代码①处保留原始事件的引用,同时clone原始事件。在这个clone的事件上进行包裹。②处在原始事件上运行 preventDefault 和 stopPropagation两个方法达到是否阻止默认的事件动作发生和是否停止冒泡事件事件向上传递。

   ③处是修正target个,IE中采用srcElement,同时对于文本节点事件,应该把target传到其父节点。

  ④处 relatedTarget只是对于mouseout、mouseover有用。在IE中分成了to和from两个Target变量,在mozilla中 没有分开。为了保证兼容,采用relatedTarget统一起来。

  ⑥处是进行event的坐标位置。这个是相对于page。如果页面 可以scroll,则要在其client上加上scroll。在IE中还应该减去默认的2px的body的边框。

  ⑦处是把键盘事件的按 键统一到event.which的属性上。Ext中的实现ev.charCode || ev.keyCode || 0; ⑨则是把鼠标事件的按键统一把event.which上。charCode、ev.keyCode一个是字符的按键,一个不是字符的按键。⑨处采 用&的方式来进行兼容性的处理。 Ext 通过下面三行解决兼容问题。

 var btnMap = Ext.isIE ? {1:0,4:1,2:2} : (Ext.isSafari ? {1:0,2:1,3:2} : {0:0,1:1,2:2}); this.button = e.button ? btnMap[e.button] : (e.which ? e.which-1 : -1);

   ①②③④⑤⑥⑦⑧⑨⑩

  6.2 事件的处理

  Jquery提供了一些来进行regist,remove,fire事件 的方法。

  6.2.1 Register

  对于注册事件,jquery提供了bind、one、toggle、 hover四种注册事件的方法, bind是最基本的方法。One是注册只运行一次的方法,toggle注册交替运行的方法。Hover是注册鼠标浮过的方法。


代码如下:

bind : function(type, data, fn) {
  return type == "unload" ? this.one(type, data, fn) : this
    .each(function() {// fn || data, fn && data实现了data参数可有可无
         jQuery.event.add(this, type, fn || data, fn && data);
       }); },

  Bind中对于unload的事件,只能运行一次,其它的就采用默认的注册方式。

// 为每一个匹配元素的特定事件(像click)绑定一个一次性的事件处理函数。
// 在每个对象上,这个事件处理函数只会被执行一次。其他规则与bind()函数相同。
// 这个事件处理函数会接收到一个事件对象,可以通过它来阻止(浏览器)默认的行为。
// 如果既想取消默认的行为,又想阻止事件起泡,这个事件处理函数必须返回false。


代码如下:

  one : function(type, data, fn) {
   var one = jQuery.event.proxy(fn || data, function(event) {
       jQuery(this).unbind(event, one);
      return (fn || data).apply(this, arguments);/this->当前的元素
       });
      return this.each(function() {
       jQuery.event.add(this, type, one, fn && data);
      });
   },

  One与bind基 本上差不多,不同的在调用jQuery.event.add时,把注册的事件处理的函数做了一个小小的调整。One调用了 jQuery.event.proxy进行了代理传入的事件处理函数。在事件触发调用这个代理的函数时,先把事件从cache中删除,再执行注册的事件函 数。这里就是闭包的应用,通过闭包得到fn注册的事件函数的引用。

//一个模仿悬停事件(鼠标移动到一个对象上面及移出这个对 象)的方法。
//这是一个自定义的方法,它为频繁使用的任务提供了一种“保持在其中”的状态。
//当鼠标移动到一个匹配的元素上面时,会 触发指定的第一个函数。当鼠标移出这个元素时,
/会触发指定的第二个函数。而且,会伴随着对鼠标是否仍然处在特定元素中的检测(例如,处在div 中的图像),
 //如果是,则会继续保持“悬停”状态,而不触发移出事件(修正了使用mouseout事件的一个常见错误)。
    hover : function(fnOver, fnOut) {
      return this.bind('mouseenter', fnOver).bind('mouseleave', fnOut);
   },

  Hover则是建立在bind的基础之上。

//每次点击后依次调用函数。
toggle : function(fn) {  
var args = arguments, i = 1;
while (i < args.length)//每个函数分配GUID
    jQuery.event.proxy(fn, args[i++]);//修改后的还在args中
return this.click(jQuery.event.proxy(fn, function(event) {//分配GUID     this.lastToggle = (this.lastToggle || 0) % i;//上一个函数      event.preventDefault();//阻止缺省动作
    //执行参数中的第几个函数,apply可以采用array-like的参数
    return args[this.lastToggle++].apply(this,arguments)||false;
  }));
  },

   Toggle中参数可以是多个fn。先把它们代码生成UUID。之后调用click的方法来注册再次进行代理的callback。这个函数在事件触发时 运行,它先计算上一次是执行了参数中的那个函数。之后阻止缺省动作。之后找到下一个函数运行。

//为jquery对象增加常用 的事件方法
jQuery.each(
   ("blur,focus,load,resize,scroll,unload,click,dblclick,"
  + "mousedown,mouseup,mousemove,mouseover,mouseout,change,select,"
+ "submit,keydown,keypress,keyup,error").split(","),
function(i, name) {jQuery.fn[name] = function(fn) {
         return fn ? this.bind(name, fn) : this.trigger(name);
       };});

   Jquery增加了一个常用的事件处理方法,包含上面调用的click。这里可以看出这里还是调用bind进行注册。当然这里还可以通过程序实现去触发 事件。

  上面的众多方法都是注册事件,其最终都落在jQuery.event.add();来完成注册的功能。如果我们采用Dom0或DOM1 的事件方法,我们会采用elem.onclick=function(){}来为元素的某一种事件来注册处理函数。这个最大的缺点就是每个一个事件只是一 个处理函数。在dom1的方式中有改进,我们可以采用elem.addEventListener(type, handle, false)为元素的事件注册多个处理函数。

  这样的处理方式还不是很完美,如果我们只这个事件运行一次就有点麻烦了。我们要在事件的处 理函数中最后进行elem.removeEventListener来取消事件的监听。这样做可能会有事务上的问题。如果第一个事件处理函数在没有取消事 件监听之前,就再次触发了怎么办?

  还有采用浏览器的方式,它不支持自定义事件的注册和处理,还不能为多个事件注册同一个处理函数。


代码如下:

jQuery.event = {// add 事件到一个元素上。
add : function(elem, types, handler, data) {
if (elem.nodeType == 3 || elem.nodeType == 8) return;// 空白节点或注释
  // IE不能传入window,先复制一下。
if (jQuery.browser.msie && elem.setInterval) elem = window;
// 为handler分配一个全局唯一的Id
if (!handler.guid)  handler.guid = this.guid++;
// 把data附到handler.data中
if (data != undefined) {                       ①
var fn = handler;
handler =this.proxy(fn,function(){return fn.apply(this,arguments);});
handler.data = data;
  }
// 初始化元素的events。如果没有取到events中值,就初始化data: {}    ②
var events =jQuery.data(elem,"events")||jQuery.data(elem,"events",{}),
// 如果没有取到handle中值,就初始化data: function() {....}     ③
handle = jQuery.data(elem, "handle")|| jQuery.data(elem, "handle",
function() {//处理一个触发器的第二个事件和当page已经unload之后调用一个事件。
    if (typeof jQuery != "undefined"&& !jQuery.event.triggered)
      return jQuery.event.handle.apply(//callee.elem=handle.elem
          arguments.callee.elem, arguments);
      });
// 增加elem做为handle属性,防止IE由于没有本地Event而内存泄露。
handle.elem = elem;
// 处理采用空格分隔多个事件名,如jQuery(...).bind("mouseover mouseout", fn);
jQuery.each(types.split(/s+/), function(index, type) {    ④
  // 命名空间的事件,一般不会用到。
var parts = type.split(".");type = parts[0];handler.type = parts[1];
  // 捆绑到本元素type事件的所有处理函数
var handlers = events[type];                     ⑤
if (!handlers) {// 没有找到处理函数列表就初始化事件队列
    handlers = events[type] = {};
   // 如果type不是ready,或ready的setup执行返回false         ⑥
if (!jQuery.event.special[type]|| jQuery.event.special[type].setup
    .call(elem, data) === false) {// 调用系统的事件函数来注册事件
if(elem.addEventListener)elem.addEventListener(type,handle,false);
else if (elem.attachEvent)elem.attachEvent("on" + type, handle);
     }
}
// 把处理器的id和handler形式属性对的形式保存在handlers列表中,
// 也存在events[type][handler.guid]中。
handlers[handler.guid] = handler;                  ⑦
// 全局缓存这个事件的使用标识
jQuery.event.global[type] = true;
});
  
  elem = null; // 防止IE内存泄露。
  },
  guid : 1,
  global : {},

  jQuery.event.add通过jQuery.data把事件相关的事件名和处理函数有机有序地组合起存放在 jQuery.cache中与该元素对应的空间里。我们就一个例子分析一下add的过程中:假如我们招待下面 jQuery(e1).bind("mouseover mouseout", fn0);jQuery(e1).bind("mouseover mouseout", fn1)的语句。

  在jQuery(e1).bind("mouseover mouseout", fn0);时,②③都不可能从cache取到数,先初始化。此时的cache:{e1_uuid:{events:{},handle:fn}}。接着在 ⑤会为mouseover mouseout名初始化。此时的cache: {e1_uuid:{events:{ mouseover:{}, mouseout:{}},handle:fn}}。在⑥处向浏览器的事件中注册处理函数。接着⑦会把处理函数到事件名中。此时的cache: {e1_uuid:{events:{mouseover:{fn0_uuid:fn0},mouseout:{ fn0_uuid:fn0}},handle:fn}}。这里可以看出为采用proxy为函数生成uuid的作用了。

   在jQuery(e1).bind("mouseover mouseout", fn1)时,②③都从cache取到数据{e1_uuid:{events:{mouseover:{fn0_uuid:fn0},mouseout:{ fn0_uuid:fn0}},接着在⑤取到mouseover:{fn0_uuid:fn0},mouseout:{ fn0_uuid:fn0}的引用。接着⑦会把处理函数注册到事件名中。此时的cache: {e1_uuid:{events:{mouseover:{fn0_uuid:fn0, fn1_uuid:fn1,},mouseout:{ fn0_uuid:fn0, fn1_uuid:fn1}},handle:fn}}。

  jQuery.event.add很重要的任务 就是把注册的事件函数有序地存放起来。以便remove和fire事件的函数能找到。

//{elem_uuid_1:{events:{mouseover:{fn_uuid:fn1,fn_uuid1:fn2},
       //mouseout:{fn_uuid:fn1,fn_uuid1:fn2}},handle:fn}}

   6.2.2 trigger

  注册了事件,如onclick。那么当用户点击这个元素时,就会自动触发这个事件的已经注册的事件处理函数。但是我们有的时候要采用程 序来模拟事件的触发就得采用强迫触发某个事件。在IE中我们可以采用.fireEvent()来实现。如:<form onsubmit="a()" >中,如果button的form.submit()的方式提交表单,是不会主动触发onsumbit事件的,如果必须的话,就要在submit 前$(“:form”)[0].fireEvent("onsubmit”,),这样就会触发该事件。

  在mozilla中有三个步骤:   var  evt  =  document.createEvent('HTMLEvents');

   evt.initEvent('change',true,true);  t.dispatchEvent( evt );

  在 prototype是采用这样的方式来实现的。那么jquery中呢,它的实现方式有一点不一样。


代码如下:

trigger : function(type, data, fn) {
return this.each(function() {
    jQuery.event.trigger(type, data, this, true, fn);
      }); },

   Trigger有三个参数,data参数是为了注册的事件函数提供了实传。如果data[0]中preventDefault存在,data[0]就可 以做为用户自定义的包裹事件的空间。Fn是可以为事件提供一个即时即用的事件处理方法。也就是在没有注册事件的情况下也可以通过传入处理函数来处理事件。 如果已经注册了,那就是在原来的事件处理函数之后执行。

  //这个方法将会触发指定的事件类型上所有绑定的处理函数。但不会 执行浏览器默认动作.
triggerHandler : function(type, data, fn) {
return this[0]&& jQuery.event.trigger(type,data,this[0],false,fn);
   },

  triggerHandle通过把jQuery.event.trigger的donative参数设为false,来阻止执行浏览器 默处理方法。它与trigger不现的一点,还在于它只是处理jquery对象的第一个元素。

  上面两个方法都调用了 jQuery.event.trigger来完成任务:


代码如下:

trigger : function(type, data, elem, donative, extra) {
  data = jQuery.makeArray(data);//data可以为{xx:yy}
  //支持getData!这样的形式,exclusive = true表现会对add的注册的
  //事件的所有函数进行命名空间的分种类的来执行。
if (type.indexOf("!") >= 0) {             ①
    type = type.slice(0, -1);var exclusive = true;
    }
if (!elem) {// 处理全局的fire事件            ②
  if (this.global[type])
    jQuery.each(jQuery.cache, function() {
     // 从cache中找到所有注册该事件的元素,触发改事件的处理函数
      if (this.events && this.events[type])
       jQuery.event.trigger(type, data, this.handle.elem);
      });
  } else {// 处理单个元素事件的fire事件          ③
   if (elem.nodeType == 3 || elem.nodeType == 8)  return undefined;
   var val, ret, fn = jQuery.isFunction(elem[type] || null),
   // 如果data参数传进入的不是浏览器的event对象的话,event变量为true.
  //如果data参数本身是娄组,那么第一个元素不是 浏览器的event对象时为true.
  //对于event为true。即没有event传进入,先构建一个伪造的event对象存在 data[0]。
  event = !data[0] || !data[0].preventDefault;
  // 在没有传入event对象的情况下,构建伪造event对象。
  if (event) {//存到数组中的第一个             ④
     data.unshift( { type : type,target : elem,
       preventDefault : function() {},stopPropagation :
function() {}, timeStamp : now()  });
    data[0][expando] = true; // 不需要修正伪造的event对象
    }
   data[0].type = type; //防止事件名出错
  //表现会进行事件注册函数的分类(命名空间)执行。不是所有的。
    if (exclusive) data[0].exclusive = true;
  
  //与prototype等传统的处理 方式不一样,没有采用fireEvent来
  //来fire通过注册到浏览器事件中的事件处理方法。
  //这里分了三步,先fire 通过jQuery.event.add来注册的事件,这个事件
  //有可能是自定义的事件(没有注册到浏览器事件中)。
  //第二步 是fire通过elem.onclick方式注册的事件的本地处理函数
   //第三步是fire默认的事件处理方式(在本地的onclick的方式注册
   //不存在的情况下)。  
// 这里是触发通过jQuery.event.add来注册的事件,
   var handle = jQuery.data(elem, "handle");      ⑤
   if (handle)val = handle.apply(elem, data); //这里data分成多个参数
  //处理触发通过elem.onfoo=function()这样的注册本地处理方法,
  //但是是 对于links 's .click()不触发,这个不会执行通过addEvent
  //方式注册的事件处理方式。     
  if ((!fn || (jQuery.nodeName(elem, 'a') && type == "click")) ⑥
     && elem["on"+ type]&& elem["on"+type].apply(elem,data) === false)
   val = false;
//额外的函 数参数的开始几个是通过data给定的。这里会把伪造加上的event给去掉。
//它的最后一个参数是一系列的事件处理函数返回的结果,一般为 bool值
//这个函数可以根据这个结果来处理一个扫尾的工作。
  if (event) data.shift();
// 处理触发extra给定的函数处理。
  if (extra && jQuery.isFunction(extra)) {           ⑦
    ret = extra.apply(elem, val == null ? data : data.concat(val));
    //如果这个函数有返回值,那么trigger的返回值就是它的返回值
    //没有的 话就是串连的事件处理函数的最后一个返回值。一般为bool
    if (ret !== undefined)  val = ret;
    }
  // 触发默认本地事件方法,它是在没有如.onclick注册事件
  //加上前面的执行事件处理函数返回值都不为 false的情况下,才会执行。
  //它还可以通donative来控制是否执行。
  //如form中可以采用 this.submit()来提交form.
  if (fn && donative !== false && val !== false     ⑧
       && !(jQuery.nodeName(elem, 'a') && type == "click")) {
    this.triggered = true;
    try {elem[type]();  //对于一些hidden的元素,IE会报错
       } catch (e) {}
    }
  this.triggered = false;
  }
return val;
},

  Jquery的fire事件的方法与prototype中实现是完全不一样的。Ext、YUI没有提供强迫触发事件的方法。对于一般的 思维,程序来触发浏览器的事件就应该采用fireEvent或dispatchEvent方法来运行。

  但是jquery采用一种不同的 方法。对于通过jquery.event.add来注册的事件(不管是自定义的还是注册到浏览器事件),它保存在一个与元素及事件名相对应的cache 中。在浏览器的触发中,这个是没有什么作用。但是它是为了通过等程序来强迫触发时,从cache中取到对应的事件处理函数。这个时候就抛开了浏览器的事 件。在这里还可以执行一些自定义的事件函数。如⑤处。

  对于通过html的标签中如click或 elem.onclick=function(){}形式注册的事件函数。在⑥处它采用执行元素的如onclick形式的回调函数就可以。通过这种 dom0的方式只能注册一个函数。

  有的时候,如果没有onclick这样的事件处理函数,浏览器会执行默认的处理函数。如 form.submit()。⑧处可以看出对于这样的默认的事件处理,还可以通过参数donative来控制。

  程序手动强迫触发事件, 有一点问题就是event是怎么生成,就是没有浏览器生成event传入到函数中。Prototype采用了是新生成的dataavailable的事 件。这样的事件也没有什么作用。Jquery也采用fake的方式伪造一个一个事件,如④,它比prototype的事件好处在于它能通过trigger 的函数的参数来传入需要的event。Prototype则不能。

  通过上面的分析,隐隐可以看出Jquery是通过模拟浏览器的触发事 件的执行过程来构建这个trigger的函数的。先执行dom1方式(addEvent)注册的事件,再执行dom0方式注册的事件,最后看看要不要执行 默认的事件处理。

  在⑦处,我们可以看出trigger还可能通过传入回调函数和参数来完成对执行的事件处理函数的结果进行判断处理,形 成新结果通过trigger的函数返回。这在有的时候是很有用的。

  除了这些,它还能对于事件的处理函数进行分类(namespace),可以在合适的时候调用事件的不同分类的的处理函数(通过 jquery.event.add来注册)。这个分类的处理在handle实现。


代码如下:

  handle : function(event) {
    // 返回 undefined or false
    var val, ret, namespace, all, handlers;
    //修改了传入的参数,这里是引用。
    event = arguments[0] = jQuery.event.fix(event || window.event);
    // 命名空间处理
     namespace = event.type.split(".");
    event.type = namespace[0];
     namespace = namespace[1];
    // all = true 表明任何 handler,namespace不存在,同时
    //event.exclusive不存在或为假时,all=true.
    all = !namespace && !event.exclusive;
    // 找到元素的events中缓存的事件名的处理函数列表
    handlers = (jQuery.data(this, "events") || {})[event.type];
    for (var j in handlers) {// 每个处理函数执行
       var handler = handlers[j];
      // Filter the functions by class
       if (all || handler.type == namespace) {
       // 传入引用,为了之后删除它们
        event.handler = handler;
       event.data = handler.data;//add的时候加上的
       ret = handler.apply(this, arguments);// 执行事件处理函数
        if (val !== false)
         val = ret;// 只要有一个处理函数返回false,本函数就返回false.
       if (ret === false) {// 不执行浏览器默认的动作
         event.preventDefault();
          event.stopPropagation();
       }
      }
    }
    return val;  }

(0)

相关推荐

  • jQuery.event兼容各浏览器的event详细解析

    介绍之前先介绍jQuery的一个方法 jQuery.event.fix(event || window.event); 此方法个浏览器的event对象转换为 jQuery.event; 如果您的事件是通过jQuery方法绑定的,就不需要进行转换了! jQuery在遵循W3C规范的情况下,对事件的常用属性进行了封装,使得事件处理在各大浏览器下都可以正常的运行而不需要进行浏览器类型判断. 1.event.type属性该方法作用是可以获取到时间的类型 复制代码 代码如下: $("a").cl

  • jquery 关于event.target使用的几点说明介绍

    event.target说明:引发事件的DOM元素. this和event.target的区别js中事件是会冒泡的,所以this是可以变化的,但event.target不会变化,它永远是直接接受事件的目标DOM元素: this和event.target的相同点this和event.target都是dom对象,如果要使用jquey中的方法可以将他们转换为jquery对象:$(this)和$(event.target); 这使我想起了以前写的一个例子: 复制代码 代码如下: //del event 

  • jquery中event对象属性与方法小结

    JQuery读书笔记–Event属性说明 JQuery事件中的Event属性是经常性的被忽略的.大多数时间你的确不怎么用它,但有些时候它还是它还是有作用的.如获知触发时用户的环境(是否按了shift etc).每个浏览器对event都有不同的地方,Jquery对Event做了标准化所以可以放心用. * .target  这个反应触发事件的DOM对象,可以在事件冒泡的时候判断是否是事件源头(compare event.target to this) * .pageX:  鼠标的left属性,相对于

  • Jquery阻止事件冒泡 event.stopPropagation

    描述: 防止事件冒泡到DOM树上,也就是不触发的任何前辈元素上的事件处理函数. version added: 1.0event.stopPropagation() 我们可以用 event.isPropagationStopped() 来确定这个方法是否(在那个事件对象上)调用过了. 这个方法对 trigger() 来自定义的事件同样有效. 注意,这不会阻止同一个元素上的其它事件处理函数的运行. Additional Notes: 自从.live()方法处理事件一旦传播到文档的顶部,live事件是

  • jquery利用event.which方法获取键盘输入值的代码

    实例 显示按了哪个键: $("input").keydown(function(event){ $("div").html("Key: " + event.which); }); 亲自试一试 定义和用法 which 属性指示按了哪个键或按钮. 语法 event.which参数 描述 event 必需.规定要检查的事件.这个 event 参数来自事件绑定函数. jQuery丢弃了标准的 button 属性采用 which,这有点让人费解. whic

  • Jquery中Event对象属性小结

    JS的Event对象是触发事件的时候传递给事件处理函数的一个对象,这个对象中存在触发事件的基本信息.如:触发事件的事件源.键盘码(如果存在)等基本信息. 1.通过event.type获取事件的类型 复制代码 代码如下: <script> $(function(){     $("a").click(function(event) {       alert(event.type);//获取事件类型       //return false;//阻止链接跳转       ev

  • jQuery源码解读之addClass()方法分析

    本文较为详细的分析了jQuery源码解读之addClass()方法.分享给大家供大家参考.具体分析如下: 给jQuery原型对象扩展addClass功能,jQuery.fn就是jQuery.prototype 复制代码 代码如下: jQuery.fn.extend({ /* 可以看出这是一个函数名叫addClass的插件方法. */     addClass: function( value ) {         var classes, elem, cur, clazz, j, finalV

  • jQuery源码解读之hasClass()方法分析

    本文较为详细的分析了jQuery源码解读之hasClass()方法.分享给大家供大家参考.具体分析如下: 复制代码 代码如下: jQuery.fn.extend({     hasClass: function( selector ) { //将要检查的类名selector赋值给className, l为选择器选择的当前要检查的jQuery对象数组的长度.         var className = " " + selector + " ",          

  • jQuery源码解读之removeAttr()方法分析

    本文较为详细的分析了jQuery源码解读之removeAttr()方法.分享给大家供大家参考.具体分析如下: 扩展jQuery原型对象的方法: 复制代码 代码如下: jQuery.fn.extend({ //name,传入要DOM元素要移除的属性名.     removeAttr: function( name ) { //使用jQuery.fn对象,即jQuery原型对象的each方法遍历当前选择器选择的jQuery对象数组,并返回该jQuery对象以便链式调用.         return

  • jQuery源码解读之removeClass()方法分析

    本文较为详细的分析了jQuery源码解读之removeClass()方法.分享给大家供大家参考.具体分析如下: removeClass()方法和addClass()差别不大.这就来看看: 复制代码 代码如下: jQuery.fn.extend({     removeClass: function( value ) {         var classes, elem, cur, clazz, j, finalValue,             i = 0,             len

  • jQuery源码分析之Event事件分析

    对于事件的操作无非是addEvent,fireEvent,removeEvent这三个事 件方法.一般lib都会对浏览器的提供的函数做一些扩展,解决兼容性内存泄漏等问题.第三个问题就是如何得到domReady的状态. 6.1 event的包裹 浏览器的事件兼容性是一个令人头疼的问题.IE的event在是在全局的window下, 而mozilla的event是事件源参数传入到回调函数中.还有很多的事件处理方式也一样. Jquery提供了一个 event的包裹,这个相对于其它的lib提供的有点简单,

  • jQuery源码分析-03构造jQuery对象-工具函数

    作者:nuysoft/高云 QQ:47214707 EMail:nuysoft@gmail.com 声明:本文为原创文章,如需转载,请注明来源并保留原文链接. 读读写写,不对的地方请告诉我,多多交流共同进步,本章的的PDF等本章写完了发布. jQuery源码分析系列的目录请查看 http://nuysoft.iteye.com/blog/1177451,想系统的好好写写,目前还是从我感兴趣的部分开始,如果大家有对哪个模块感兴趣的,建议优先分析的,可以告诉我,一起学习. 3.4 其他静态工具函数

  • jQuery源码分析-01总体架构分析

    1. 总体架构 1.1 自调用匿名函数 self-invoking anonymous function 打开jQuery源码,首先你会看到这样的代码结构: 复制代码 代码如下: (function( window, undefined ) { // jquery code })(window); 1. 这是一个自调用匿名函数.什么东东呢?在第一个括号内,创建一个匿名函数:第二个括号,立即执行 2. 为什么要创建这样一个"自调用匿名函数"呢? 通过定义一个匿名函数,创建了一个"

  • jQuery源码分析之jQuery.fn.each与jQuery.each用法

    本文实例讲述了jQuery源码分析之jQuery.fn.each与jQuery.each用法.分享给大家供大家参考.具体分析如下: 先上例子,下面代码的作用是:对每个选中的div元素,都给它们添加一个red类 复制代码 代码如下: $('div').each(function(index, elem){       $(this).addClass('red'); } }); 上面用的的.each,即jQuery.fn.each,其内部是通过jQuery.each实现的 复制代码 代码如下: j

  • jQuery源码分析之Callbacks详解

    代码的本质突出顺序.有序这一概念,尤其在javascript--毕竟javascript是单线程引擎. javascript拥有函数式编程的特性,而又因为javascript单线程引擎,我们的函数总是需要有序的执行.优秀代码常常 把函数切割成各自的模块,然后在某一特定条件下执行,既然这些函数是有序的执行,那么我们为什么不编写一个统一管理的对象,来帮助我们管理这些函数--于是,Callbacks(回调函数)诞生. 什么是Callbacks javascript中充斥着函数编程,例如最简单的wind

  • YOLOv5中SPP/SPPF结构源码详析(内含注释分析)

    目录 一.SPP的应用的背景 二.SPP结构分析 三.SPPF结构分析 四.YOLOv5中SPP/SPPF结构源码解析(内含注释分析) 总结 一.SPP的应用的背景 在卷积神经网络中我们经常看到固定输入的设计,但是如果我们输入的不能是固定尺寸的该怎么办呢? 通常来说,我们有以下几种方法: (1)对输入进行resize操作,让他们统统变成你设计的层的输入规格那样.但是这样过于暴力直接,可能会丢失很多信息或者多出很多不该有的信息(图片变形等),影响最终的结果. (2)替换网络中的全连接层,对最后的卷

随机推荐