mass Framework event模块
此模块此用于屏蔽DOM事件的浏览器差异的,并提供强大的事件代理机制(delegate,undelegate,live,die):
//==========================================
// 事件模块 by 司徒正美 2011.8.21
//==========================================
(function(global,DOC){
var dom = global[DOC.URL.replace(/(#.+|\W)/g,'')];
dom.define("event", "emitter,travel",function(){
dom.log("加载dom.event模块成功")
var types = "contextmenu,click,dblclick,mouseout,mouseover,mouseenter,mouseleave,mousemove,mousedown,mouseup,mousewheel," +
"abort,error,load,unload,resize,scroll,change,input,select,reset,submit,"+"blur,focus,focusin,focusout,"+"keypress,keydown,keyup";
dom.eventSupport = function( eventName,el ) {
el = el || DOC.createElement("div");
eventName = "on" + eventName;
var ret = eventName in el;
if (el.setAttribute && !ret ) {
el.setAttribute(eventName, "return;");
ret = typeof el[eventName] === "function";
}
el = null;
return ret;
};
var events = dom.events, specials = events.special, rword = dom.rword;
//用于在标准浏览器下模拟mouseenter与mouseleave
//现在除了IE系列支持mouseenter/mouseleave/focusin/focusout外
//opera11也支持这四个事件,同时它们也成为w3c DOM3 Event的规范
//详见http://www.filehippo.com/pl/download_opera/changelog/9476/
//http://dev.w3.org/2006/webapi/DOM-Level-3-Events/html/DOM3-Events.html
var brokenMouseEnter = !dom.eventSupport("mouseenter");
"mouseenter_mouseover,mouseleave_mouseout".replace(rword,function(types){
types = types.split("_");
var obj = specials[ types[0] ] = {
setup:function(target){
dom.bind(target, types[1],function(){
obj[uuid(target)+"_handle"] = arguments.callee;
e = events.fix(e);
var parent = e.relatedTarget;
try {
while ( parent && parent !== target ) {
parent = parent.parentNode;
}
if ( parent !== target ) {
e.type = types[0];
events.handle.call(target,e);
}
} catch(e) { };
});
},
teardown :function(target){
events.teardown(target, types[1],obj[uuid(target)+"_handle"]);
delete obj[uuid(target)+"_handle"]
}
};
obj.liveSetup = obj.setup;
obj.liveTeardown = obj.teardown;
if(!brokenMouseEnter){
delete obj.setup;
delete obj.teardown;
}
});
if(!dom.eventSupport("focusin")){
"focusin_focus,focusout_blur".replace(rword,function(types){
types = types.split("_");
var attaches = 0;
function handler(e) {
events.fire(e.target, types[0]);
}
specials[ types[0] ] = {
type: types[1],
setup:function(){
if ( attaches++ === 0 ) {
DOC.addEventListener( types[1], handler, true );
}
},
teardown: function() {
if ( --attaches === 0 ) {
DOC.removeEventListener( types[1], handler, true );
}
}
}
});
}
//http://www.w3help.org/zh-cn/causes/SD9013
//https://prototype.lighthouseapp.com/projects/8886/tickets/697-eventfire-to-support-all-events-not-only-custom-ones
//http://www.quirksmode.org/dom/events/scroll.html
if(!dom.eventSupport("mousewheel")){
specials.mousewheel = {
type : "DOMMouseScroll"//FF
}
}
//取得事件发送器的uniqueID
function uuid(target){
return dom.data(target,"uuid")
}
//submit事件的冒泡情况----IE6-9 :form ;FF: document; chrome: window;safari:window;opera:window
if(!dom.eventSupport("submit") && !DOC.dispatchEvent ){
var submitCode = dom.oneObject("13,108");
var submitButton = dom.oneObject("submit,image");
var submitInput = dom.oneObject("text,password,textarea");
var submitRoom = specials.submit = {
liveSetup: function(target){
//将事件回调函数保存到一个在卸载时可以找到它的地方
submitRoom[uuid(target)+"_handle"] = function(){
var e = events.fix(event), el = e.target, type = el.type;
if( el.form && ( submitButton[type] || submitCode[ e.which ] && submitInput[type]) ){
dom.log("模拟IE下的submit事件冒泡 ");
e.type = "submit";
events.handle.call(target, e);
}
}
"onclick,onkeypress".replace(rword,function(type){
target.attachEvent(type ,submitRoom[uuid(target)+"_handle"] );
})
},
liveTeardown: function(target){
"onclick,onkeypress".replace(rword,function(type){
target.detachEvent(type ,submitRoom[uuid(target)+"_handle"]||dom.noop );
});
delete submitRoom[uuid(target)+"_handle"];
}
}
}
//reset事件的冒泡情况----FF与opera能冒泡到document,其他浏览器只能到form
if(!dom.eventSupport("reset") ){
var resetRoom = specials.reset = {
liveSetup:DOC.dispatchEvent ? 0 : function(target){
resetRoom[uuid(target)+"_handle"] = function(){
var e = events.fix(event), el = e.target;
if( el.form && (e.which === 27 || el.type == "reset") ){
dom.log("模拟reset事件冒泡 ");
e.type = "reset";
events.handle.call(target, e);
}
}
"onclick,onkeypress".replace(rword,function(type){
target.attachEvent(type , resetRoom[uuid(target)+"_handle"]);
});
},
liveTeardown:DOC.dispatchEvent ? 0 : function(target){
"onclick,onkeypress".replace(rword,function(type){
target.dettachEvent(type ,resetRoom[uuid(target)+"_handle"]);
})
delete resetRoom[uuid(target)+"_handle"];
}
}
}
//change事件的冒泡情况----FF与opera能冒泡到document,其他浏览器完全不冒泡
if(!dom.eventSupport("change") ){
function getVal( node ) {
var type = node.type, val = node.value;
if ( type === "radio" || type === "checkbox" ) {
val = node.checked;
} else if ( type === "select-multiple" ) {
val = node.selectedIndex === -1 ? "":
dom.lang( node.options).map(function( node ) {
return node.selected;
}).join("-") ;
} else if ( type === "select-one" ) {
val = node.selectedIndex;
}
return val;
}
function changeHandle( e ) {
var eType = e.type,node = e.srcElement,nType = node.type
//如果不是表单元素,又或者处于只读状态下,直接返回
if ( !node.form || node.readOnly ) {
return;
}
if ( eType === "keydown" ) {
var flag = false;
if ( (e.keyCode === 13 && nType !== "textarea" ) ||
(e.keyCode === 32 && ( nType === "checkbox" || nType === "radio")) ||
nType === "select-multiple" ) {
flag = true;
}
if(!flag){
return;
}
}
//取得之前的数据
var oldData = dom.data( node, "_change_data" );
//获取现在的数据
var newData = getVal(node);
// focusout是不用重设数据的
if ( eType !== "focusout" || nType !== "radio" ) {
dom.data( node, "_change_data", newData );
}
if ( newData === undefined || newData === oldData ) {
return;
}
if ( oldData != null || newData ) {
e = events.fix(e);
e.type = "change";
events.handle.call(node, e);
}
}
var changeRoom = specials.change = {
liveSetup: function(node){
//此事件用于收集数据
node.attachEvent("onbeforeactivate", function( ) {
changeRoom[uuid(node)+event.type+"_handler"] = arguments.callee;
dom.data( node, "_change_data", getVal(node) );
});
////当点击目标元素时,再点击页面的其他位置时,依次会发生如下事件beforeactivate click | beforedeactivate focusout
"onfocusout,onbeforedeactivate,onclick,onkeydown".replace(rword,function(type){
node.attachEvent(type ,function(){
changeRoom[uuid(node)+event.type+"_handler"] = arguments.callee;
changeHandle.call(node, event);
});
});
},
liveTeardown:function(node){
var uid = uuid(node);
"focusout,beforedeactivate,click,keydown,beforeactivate".replace(rword,function(type){
node.detachEvent("on"+type,changeRoom[uid+type+"_handler"]||dom.noop );
delete changeRoom[uid+type+"_handler"]
});
}
}
}
//当一个元素,或者其内部任何一个元素获得焦点的时候会触发这个事件。
//这跟focus事件区别在于,他可以在父元素上检测子元素获取焦点的情况。
//=================================
dom.include({
toggleClick:function(/*fn1,fn2,fn3*/){
var fns = [].slice.call(arguments), i = 0;
return this.click(function(e){
var fn = fns[i++] || fns[i = 0, i++];
fn.call(this,e);
})
},
hover: function( fnOver, fnOut ) {
return this.mouseenter( fnOver ).mouseleave( fnOut || fnOver );
}
});
"bind,unbind,fire".replace(rword, function(method){
dom.fn[method] = function(){
var args = arguments;
return this.each(function(target){
events[method].apply(target, args);
});
}
});
//事件代理的原理就是把事件侦听器绑定在顶层元素上,通过判定下层冒泡或捕获上来的事件源元素的特定,执行相应的回调
"delegate,undelegate".replace(rword,function(method){
dom.fn[method] = function(expr,type,callback){
var special = events.special[ type ] || {};
var bag = {
live: expr,
type: type,
callback:callback
}
bag.uuid = callback.uuid = dom.uuid++;
//选取可用的事件类型,如mouseenter在标准浏览器下就不能用,需要用mouseover冒充
type = special.type || type
return this.each(function(node){
events[method === "delegate" ? "bind" : "unbind"].apply(node, [type, bag, true]);
});
}
});
"live,die".replace(rword,function(method){
dom.fn[method] = function(type,callback){
var expr = this.selector;
var doc = this.doc || DOC;
if(!expr){
expr = dom.noop;
}
return dom(doc)[method === "live" ? "delegate" : "undelegate"](expr, type, callback);
}
});
types.replace(rword,function(type){
dom.fn[type] = function(callback, phase, trust){
return this.bind(type, callback, phase, trust);
}
});
});
})(this,this.document);
机器瞎学/数据掩埋/模式混淆/人工智障/深度遗忘/神经掉线/计算机幻觉/专注单身二十五年
浙公网安备 33010602011771号