博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
jQuery事件处理一瞥
阅读量:6983 次
发布时间:2019-06-27

本文共 10514 字,大约阅读时间需要 35 分钟。

以前部门一直都是使用一个名为QTT的JS框架。最近老大提出要转用jQuery框架,需要将旧框架的一些JQ没有实现的功能移植到JQ中去。当我移植到event库的时候,以下是其代码:

QTT.event = {	KEYS : {		BACKSPACE : 8,		TAB : 9,		RETURN : 13,		ESC : 27,		SPACE : 32,		LEFT : 37,		UP : 38,		RIGHT : 39,		DOWN : 40,		DELETE : 46	},	extendType : /(click|mousedown|mouseover|mouseout|mouseup|mousemove|scroll|contextmenu|resize)/i,	_eventListDictionary : {},	_fnSeqUID : 0,	_objSeqUID : 0,	addEvent : function(obj, eventType, fn, argArray) {		var cfn = fn,			res = false, l;		if (!obj) {			return res;		}		if (!obj.eventsListUID) {			obj.eventsListUID = "e" + (++QTT.event._objSeqUID);			QTT.event._eventListDictionary[obj.eventsListUID] = {};		}		l = QTT.event._eventListDictionary[obj.eventsListUID];		if (!fn.__elUID) {			fn.__elUID = "e" + (++QTT.event._fnSeqUID) + obj.eventsListUID;		}		if (!l[eventType]) {			l[eventType] = {};		}				if(typeof(l[eventType][fn.__elUID])=='function'){			return false;		}				if (QTT.event.extendType.test(eventType)) {			var argArray = argArray || [];			cfn = function(e) {
//吐槽音:为啥这里不用obj而用了null, 害得我在回调事件中不能用this -_-!! return fn.apply(null, ([QTT.event.getEvent(e)]).concat(argArray)); }; } if (obj.addEventListener) { obj.addEventListener(eventType, cfn, false); res = true; } else if (obj.attachEvent) { res = obj.attachEvent("on" + eventType, cfn); } else { res = false; } if (res) { l[eventType][fn.__elUID] = cfn; } return res; }, removeEvent : function(obj, eventType, fn) { var cfn = fn, res = false, l; if (!obj) { return res; } if (!cfn) { return QTT.event.purgeEvent(obj, eventType); } if (!obj.eventsListUID) { obj.eventsListUID = "e" + (++QTT.event._objSeqUID); QTT.event._eventListDictionary[obj.eventsListUID] = {}; } l = QTT.event._eventListDictionary[obj.eventsListUID]; if (!fn.__elUID) { fn.__elUID = "e" + (++QTT.event._fnSeqUID) + obj.eventsListUID; } if (!l[eventType]) { l[eventType] = {}; } if (QTT.event.extendType.test(eventType) && l[eventType] && l[eventType][fn.__elUID]) { cfn = l[eventType][fn.__elUID]; } if (obj.removeEventListener) { obj.removeEventListener(eventType, cfn, false); res = true; } else if (obj.detachEvent) { obj.detachEvent("on" + eventType, cfn); res = true; } else { return false; } if (res && l[eventType]) { delete l[eventType][fn.__elUID]; } return res; }, purgeEvent : function(obj, type) { var l; if (obj.eventsListUID && (l=QTT.event._eventListDictionary[obj.eventsListUID]) && l[type]) { for (var k in l[type]) { if (obj.removeEventListener) { obj.removeEventListener(type, l[type][k], false); } else if (obj.detachEvent) { obj.detachEvent('on' + type, l[type][k]); } } } if (obj['on' + type]) { obj['on' + type] = null; } if (l) { l[type] = null; delete l[type]; } return true; }, getEvent : function(evt) { var evt = evt || window.event; if (!evt && !QTT.userAgent.ie) { var c = this.getEvent.caller, cnt = 1; while (c) { evt = c.arguments[0]; if (evt && Event == evt.constructor) { break; }else if(cnt > 32){ break; } c = c.caller; cnt++; } } return evt; }, getButton : function(evt) { var e = QTT.event.getEvent(evt); if (!e) { return -1 } if (QTT.userAgent.ie) { return e.button - Math.ceil(e.button / 2); } else { return e.button; } }, getTarget : function(evt) { var e = QTT.event.getEvent(evt); if (e) { return e.target || e.srcElement; } else { return null; } }, getCurrentTarget : function(evt) { var e = QTT.event.getEvent(evt); if (e) { return e.currentTarget || document.activeElement; } else { return null; } }, cancelBubble : function(evt) { evt = QTT.event.getEvent(evt); if (!evt) { return false } if (evt.stopPropagation) { evt.stopPropagation(); } else { if (!evt.cancelBubble) { evt.cancelBubble = true; } } }, preventDefault : function(evt) { evt = QTT.event.getEvent(evt); if (!evt) { return false } if (evt.preventDefault) { evt.preventDefault(); } else { evt.returnValue = false; } }, mouseX : function(evt) { evt = QTT.event.getEvent(evt); return evt.pageX || (evt.clientX + (document.documentElement.scrollLeft || document.body.scrollLeft)); }, mouseY : function(evt) { evt = QTT.event.getEvent(evt); return evt.pageY || (evt.clientY + (document.documentElement.scrollTop || document.body.scrollTop)); }, getRelatedTarget: function(ev) { ev = QTT.event.getEvent(ev); var t = ev.relatedTarget; if (!t) { if (ev.type == "mouseout") { t = ev.toElement; } else if (ev.type == "mouseover") { t = ev.fromElement; } else { } } return t; }, bind : function(obj, method) { var args = Array.prototype.slice.call(arguments, 2); return function() { var _obj = obj || this; var _args = args.concat(Array.prototype.slice.call(arguments, 0)); if (typeof(method) == "string") { if (_obj[method]) { return _obj[method].apply(_obj, _args); } } else { return method.apply(_obj, _args); } } }};

以上方法中,addEvent、removeEvent、purgeEvent、bind这几个方法在JQ中有直接实现的。但好像在JQ的api中并没有跟getEvent、getButton、getTarget、getCurrentTarget、cancelBubble、preventDefault、mouseX、mouseY、getRelatedTarget这几个方法相关的事件。

但是JQ库这么强大,不可能没考虑这些通用函数的。既然API手册没有说,就只能翻出了jQuery的源码来看下了。

 

我在jQuery.event这个命名空间下发现了这个方法:

fix: function( event ) {	if ( event[ expando ] ) {		return event;	}	// store a copy of the original event object	// and "clone" to set read-only properties	var originalEvent = event;	event = jQuery.Event( originalEvent );	for ( var i = this.props.length, prop; i; ) {		prop = this.props[ --i ];		event[ prop ] = originalEvent[ prop ];	}	// Fix target property, if necessary	if ( !event.target ) {		event.target = event.srcElement || document; // Fixes #1925 where srcElement might not be defined either	}	// check if target is a textnode (safari)	if ( event.target.nodeType === 3 ) {		event.target = event.target.parentNode;	}	// Add relatedTarget, if necessary	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 && doc.clientLeft||body && body.clientLeft||0);		event.pageY = event.clientY + (doc && doc.scrollTop||body && body.scrollTop||0)                - (doc && doc.clientTop||body && body.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 (use ctrl for PC's and Meta for Macs)	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 !== undefined ) {		event.which = (event.button & 1 ? 1 : ( event.button & 2 ? 3 : ( event.button & 4 ? 2 : 0 ) ));	}	return event;},

顿时廓然开朗。从功能上看,jQuery.event.fix() 的功能是修复event对象,让事件在各种浏览器下表现一致。它修复的事件属性包括:

1.event.target          =====>被触发的对象,可替代QTT.event.getTarget()

2.event.relatedTarget                  =====>可替代QTT.event.getRelatedTarget()

3.event.pageX和event.pageY        =====>事件触发时的鼠标位置,可替代QTT.event.mouseX()和QTT.event.mouseY()

4.event.which                             =====>事件触发时的按键,包括键盘和鼠标。可替代QTT.event.getButton()

5.event.metaKey                         =====>事件触发时有没按下ctrl键(Mac下是meta键)

值得注意的是上面的event.which,它既可以用来获得键盘输入,也可以获得鼠标输入。标准的button采用0,1,2表示鼠标的左,中,右键。jQuery的which则使用用1,2,3。

 

除了对事件属性的修复,它还对最关键的event对象进行了修复:

var originalEvent = event;   event = jQuery.Event( originalEvent );

这个jQuery.Event的代码如下:

jQuery.Event = function( src ) {	// Allow instantiation without the 'new' keyword	if ( !this.preventDefault ) {		return new jQuery.Event( src );	}	// Event object	if ( src && src.type ) {		this.originalEvent = src;		this.type = src.type;	// Event type	} else {		this.type = src;	}	// timeStamp is buggy for some events on Firefox(#3843)	// So we won't rely on the native value	this.timeStamp = now();	// Mark it as fixed	this[ expando ] = true;};jQuery.Event.prototype = {	preventDefault: function() {		this.isDefaultPrevented = returnTrue;		var e = this.originalEvent;		if ( !e ) {			return;		}				// if preventDefault exists run it on the original event		if ( e.preventDefault ) {			e.preventDefault();		}		// otherwise set the returnValue property of the original event to false (IE)		e.returnValue = false;	},	stopPropagation: function() {		this.isPropagationStopped = returnTrue;		var e = this.originalEvent;		if ( !e ) {			return;		}		// if stopPropagation exists run it on the original event		if ( e.stopPropagation ) {			e.stopPropagation();		}		// otherwise set the cancelBubble property of the original event to true (IE)		e.cancelBubble = true;	},	stopImmediatePropagation: function() {		this.isImmediatePropagationStopped = returnTrue;		this.stopPropagation();	},	isDefaultPrevented: returnFalse,	isPropagationStopped: returnFalse,	isImmediatePropagationStopped: returnFalse};

可见经过处理后,event对象就拥有stopPropagation和preventDefault两个方法,可替代QTT.event.cancelBubble()和QTT.event.preventDefault()。

并且不需要通过QTT.event.getEvent()这样的方式去获取event对象了。

于是如果你需要在事件回调函数中阻止冒泡或者默认事件的话,这样写即可:

1.event.stopPropagation();

事件处理过程中,阻止了事件冒泡,但不会阻击默认行为(例如超链接的跳转)

2.return false;

事件处理过程中,阻止了事件冒泡,并且也阻止了默认行为

3.event.preventDefault();

事件处理过程中,不阻击事件冒泡,但阻击默认行为

 

还有一点,就是getEvent这个函数是干什么用的呢?先看一下其定义:

getEvent : function(evt) {		var evt = evt || window.event;		if (!evt && !QTT.userAgent.ie) {			var c = this.getEvent.caller,				cnt = 1;			while (c) {				evt = c.arguments[0];				if (evt && Event == evt.constructor) {					break;				}else if(cnt > 32){					break;				}				c = c.caller;				cnt++;			}		}		return evt;	},

本来没看懂的,后来看了后明白了。

例如<button οnclick="go(event)">click</button>假如函数写成go(),那FF这些浏览器就无法获取到event对象。这时就得通过caller调用父层函数的参数来获得event对象了。

 

经过一番分析挖掘之后,QTT.event类就只剩下QTT.event.KEYS和QTT.event.getCurrentTarget是需要移植的了。前者是一些常量,直接移植即可。而这个getCurrentTarget到底是什么呢?再往回翻代码看:

getCurrentTarget : function(evt) {	var e = QTT.event.getEvent(evt);	if (e) {			return  e.currentTarget || document.activeElement;	} else {		return null;	}}

部门的前辈对这个函数的解释是“返回获得焦点的对象”,跟target有什么不同呢?

在jQuery中搜索activeElement,没有;搜索currentTarget,发现在这几个方法中有用到:

jQuery.event.trigger

jQuery.event.handle
liveHandler

JQ没有将其单独成一个方法。暂时写到这里,等以后有时间再慢慢研究这个currentTarget。

 

转载于:https://www.cnblogs.com/lefeng/archive/2012/05/13/2497971.html

你可能感兴趣的文章
动态设置uitableview高度,参考
查看>>
lintcode 中等题:A + B Problem A + B 问题
查看>>
一亩三分地帖子
查看>>
MySql绿色版安装过程记录
查看>>
Struts2文件上传的大小限制问题
查看>>
maven web项目build失败
查看>>
jQuery-1.9.1源码分析系列(六) 延时对象应用——jQuery.ready
查看>>
关于Kingfisher--备用
查看>>
段错误调试神器 - Core Dump详解
查看>>
审计参数 audit_trail
查看>>
linux shell的输出效果修改方法(界面颜色)
查看>>
《TCP/IP具体解释》读书笔记(18章)-TCP连接的建立与中止
查看>>
Matlab Command Window 进度提示
查看>>
利用redis写webshell
查看>>
IO 延迟与Queue Depth
查看>>
IOS 设备信息读取
查看>>
不可重复读和幻读的区别
查看>>
LeetCode_Path Sum II
查看>>
CF 439C(251C题)Devu and Partitioning of the Array
查看>>
更新整理本人全部博文中提供的代码与工具(Java,2014.09)
查看>>