Skip to content

Instantly share code, notes, and snippets.

@zhoumengkang
Last active December 21, 2015 02:45
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save zhoumengkang/e713d2591d7e3c8dc6b2 to your computer and use it in GitHub Desktop.
Save zhoumengkang/e713d2591d7e3c8dc6b2 to your computer and use it in GitHub Desktop.
ThinkSNS的自定义事件监听
/****************************************************
* *
* Sociax HTML 标签关联模型 *
* *
****************************************************/
/**
* HTML 标签关联模型
* @model-node 模型节点的标签属性标记
* @event-node 模型下事件节点的标签属性标记
* @author _慢节奏
*/
(function(window) {
var document = window.document;
/**
* 激活模型
*
* @param node 元素节点
* @param node 父模型节点,若为空则将node 作为父模型节点
* @param fns 挂载到标签上的事件方法,格式说明如下:
* {
* model: {
* method1 : {
* click : function(){},
* mouseover : function(){},
* mouseout : function(){},
* load : function(){}
* },
* method2 : {
* blur : function(){},
* focus : function(){},
* submit : function(){}
* }
* },
* event: {
* method1 : {
* click : function(){},
* mouseover : function(){},
* mouseout : function(){},
* load : function(){}
* },
* method2 : {
* blur : function(){},
* focus : function(){},
* submit : function(){}
* }
* }
* }
*/
var module = function( node, fns ) {
module.addFns(fns);
if ( node ) {
// 预清除,防止重复模型化引起的双重缓存
module.nodes.init( node );
}
};
/**
* 保存事件的方法
*
* @param fns 挂载到标签上的事件方法,格式说明同module 函数的fns 参数
*/
module.addFns = function( fns ) {
if ( !fns ) return module;
if ( fns.model ) {
module.addModelFns( fns.model );
}
if ( fns.event ) {
module.addEventFns( fns.event );
}
return module;
};
/**
* 保存模型事件的方法
*
* @param fns 挂载到模型上的事件方法,格式说明如下:
* {
* method1 : {
* click : function(){},
* mouseover : function(){},
* mouseout : function(){},
* load : function(){}
* },
* method2 : {
* blur : function(){},
* focus : function(){},
* submit : function(){}
* }
* }
*/
module.addModelFns = function( fns ) {
if ( "object" != typeof fns ) return module;
var name;
for ( name in fns ) {
module.nodes.models.fns[name] = fns[name];
}
return module;
};
/**
* 保存模型下事件节点的方法
*
* @param fns 挂载到模型上的事件方法,属性说明同module.addModelFns 的fns 参数
*/
module.addEventFns = function( fns ) {
if ( "object" != typeof fns ) return module;
var name;
for ( name in fns ) {
module.nodes.events.fns[name] = fns[name];
}
return module;
};
/**
* 获取节点的参数
*
* @param node 模型/事件节点
*/
module.getArgs = function( node ) {
return node.getAttribute( "model-node" ) ? module.getModelArgs( node ) : module.getEventArgs( node );
};
/**
* 设置节点的参数
*
* @param node 模型/事件节点
* @param uri URI 格式的参数
*/
module.setArgs = function( node, uri ) {
return node.getAttribute( "model-node" ) ? module.setModelArgs( node, uri ) : module.setEventArgs( node, uri );
};
/**
* 获取模型节点的参数
*
* @param node 模型节点
*/
module.getModelArgs = function( node, uri ) {
node.args || ( node.args = module.URI2Obj( node.getAttribute( "model-args" ) ) );
return node.args;
};
/**
* 设置模型节点的参数
*
* @param node 模型节点
*/
module.setModelArgs = function( node, uri ) {
node.args = undefined;
node.setAttribute( "model-args", uri );
return module;
};
/**
* 获取事件节点的参数
*
* @param node 事件节点
*/
module.getEventArgs = function( node ) {
node.args || ( node.args = module.URI2Obj( node.getAttribute( "event-args" ) ) );
return node.args;
};
/**
* 设置事件节点的参数
*
* @param node 事件节点
*/
module.setEventArgs = function( node, uri ) {
node.args = undefined;
node.setAttribute( "event-args", uri );
return module;
};
/**
* 将uri转换为对象格式
*
* @param uri URI 格式的数据
*/
module.URI2Obj = function( uri ) {
if ( ! uri ) return {};
var obj = {},
args = uri.split( "&" ),
l, arg;
l = args.length;
while ( l -- > 0 ) {
arg = args[l];
if ( ! arg ) {
continue;
}
arg = arg.split( "=" );
obj[arg[0]] = arg[1];
}
return obj;
};
/**
* 获取全局内指定的模型节点
*
* @param name 模型节点的命名
*/
module.getModels = function( name ) {
return module.nodes.models[name];
};
/**
* 获取全局内指定的事件节点
*
* @param name 事件节点的命名
*/
module.getEvents = function( name ) {
return module.nodes.events[name];
}
/**
* 删除节点上的监听
*
* @param object node 节点对象
*/
module.removeListener = function( node ) {
module.nodes.removeListener( node );
return module;
};
/**
* 为节点添加监听
*
* @param object node 节点对象
* @param object events 监听的事件
* {
* click : function(){},
* mouseover : function(){},
* mouseout : function(){}
* }
*/
module.addListener = function( node, events ) {
module.nodes.addListener( node, events );
return module;
};
module.getPreviousModel = function( node, siblingName ) {
return module.nodes.getPreviousModel( node, siblingName );
};
module.getNextModel = function( node, siblingName ) {
return module.nodes.getNextModel( node, siblingName );
};
module.getPreviousEvent = function( node, siblingName ) {
return module.nodes.getPreviousEvent( node, siblingName );
};
module.getNextEvent = function( node, siblingName ) {
return module.nodes.getNextEvent( node, siblingName );
};
/**
* 模型化节点对象
*
* @property function init 初始化模型
* @property function _init 逐级扫描指定节点下的各级子元素的模型结构,并缓存模型和事件的DOM对象
* @property function clear 清楚元素节点的子模型节点和子事件节点合集对象
* @property function getParentModel
* @property function addListener 为模型和事件节点附加事件方法
* @property object _onload 自定义onload 事件
* @property object _onload.execute 执行onload 事件队列
* @property object _onload.queue onload 事件队列
* @property object models 罗列并缓存模型节点
* @property object events 罗列并缓存事件节点
* @property object models.fns 存放模型节点的事件方法
* @property object events.fns 存放事件节点的事件方法
*/
module.nodes = {
init: function( node ) {
// 初始化模型
this._init( node );
// 执行onload 事件
this._onload.execute();
return this;
},
_init: function( node, parentModel ) {
var childNode = node.firstChild,
childParentModel,
model_name,
event_name;
! parentModel && ( parentModel = this.getParentModel( node ) );
switch ( node.nodeName ) {
case "DIV": case "UL":case "DL":
case "FORM":case "LI":case "DD":
model_name = node.getAttribute( "model-node" );
if ( model_name ) {
this._clearModel( node );
node.modelName = model_name;
this.addListener( node, this.models.fns[model_name] );
node.parentModel = parentModel;
( parentModel.childModels[model_name] = parentModel.childModels[model_name] || [] ).push( node );
( this.models[model_name] = this.models[model_name] || [] ).push( node );
childParentModel = node;
}
break;
case "A": case "SPAN": case "LABEL":
case "STRONG": case "INPUT": case "SELECT":
case "BUTTON": case "IMG": case "TEXTAREA":
case "H1": case "H2": case "H3": case "H4":case "I":
event_name = node.getAttribute( "event-node" );
if ( event_name ) {
this._clearEvent(node);
node.eventName = event_name;
this.addListener( node, this.events.fns[event_name] );
node.parentModel = parentModel;
( parentModel.childEvents[event_name] = parentModel.childEvents[event_name] || [] ).push( node );
( this.events[event_name] = this.events[event_name] || [] ).push( node );
}
break;
case "HEAD": case "BODY":
this[node.nodeName.toLowerCase()] = node;
break;
case "#document":
this._clearModel(node);
break;
}
! childParentModel && ( childParentModel = parentModel );
while ( childNode ) {
(1 == childNode.nodeType ) && this._init( childNode, childParentModel );
childNode = childNode.nextSibling;
}
},
_clearModel: function( node ) {
node.modelName = undefined;
node.parentModel = undefined;
node.childModels = {};
node.childEvents = {};
node.args = undefined;
return this;
},
_clearEvent: function( node ) {
node.eventName = undefined;
node.parentModel = undefined;
node.args = undefined;
return this;
},
getParentModel: function( node ) {
var parentNode = node.parentNode,
parentModel;
if ( parentNode && 1 === parentNode.nodeType ) {
parentModel = parentNode.getAttribute('model-node') ? parentNode : this.getParentModel( parentNode );
}
return parentModel || document;
},
getPreviousModel: function( node, siblingName ) {
return this._getSiblingNode( node, { siblingType: "model", siblingName: siblingName }, "previous" );
},
getNextModel: function( node, siblingName ) {
return this._getSiblingNode( node, { siblingType: "model", siblingName: siblingName }, "next" );
},
getPreviousEvent: function( node, siblingName ) {
return this._getSiblingNode( node, { siblingType: "event", siblingName: siblingName }, "previous" );
},
getNextEvent: function( node, siblingName ) {
return this._getSiblingNode( node, { siblingType: "event", siblingName: siblingName }, "next" );
},
_getSiblingNode: function( node, siblingArgs, direction ) {
var sibling;
if ( !node ) return null;
sibling = node[ [ direction, "Sibling" ].join("") ];
return ( sibling && ( siblingArgs.siblingName === sibling[ [ siblingArgs.siblingType, "Name" ].join("") ] ) ) ? sibling : this._getSiblingNode( sibling, siblingArgs, direction );
},
addListener: function( node, events ) {
if ( "object" == typeof events ) {
var event;
for ( event in events ) {
switch ( event ) {
case "load":
node[event] = events[event];
// 添加到队列
this._onload.queue.push( node );
break;
case "callback":
node[event] = events[event];
break;
case "mouseenter": case "mouseleave":
// 兼容非IE
if ( document.addEventListener ) {
var refer = {mouseenter: "mouseover", mouseleave: "mouseout"};
node["on" + refer[event]] = (function( event, fn ){
return function( e ) {
// 上一响应mouseover/mouseout 事件的元素
var parent = e.relatedTarget;
// 假如存在这个元素并且这个元素不等于目标元素
while( parent && parent != this ){
try {
//上一响应的元素开始往上寻找目标元素
parent = parent.parentNode;
} catch( e ) {
break;
}
}
// 假如找不到,表明当前事件触发点不在目标元素内
if ( parent != this ) {
//运行目标方法,否则不运行
node[event] = fn;
node[event]();
}
};
})( event, events[event] );
} else {
node["on" + event] = events[event];
}
break;
default :
node["on" + event] = events[event];
}
}
}
},
removeListener: function( node ) {
node.onclick = node.onfocus = node.onblur = node.onmouseout
= node.onmouseover = node.onmouseenter = node.onmouserleave
= node.onchange = null;
return this;
},
_onload: {
execute: function() {
var l = this.queue.length,
i;
for ( i = 0; i < l; i ++ ) {
this.queue[i]["load"]();
this.queue[i]["load"] = undefined;
}
// 重置队列
this.queue = [];
},
queue: []
},
models: {
fns: {
}
},
events: {
fns: {
}
},
getHead: function() {
this.head || (this.head = document.getElementsByTagName("head")[0]);
return this.head;
},
getBody: function() {
this.body || (this.body = document.getElementsByTagName("body")[0]);
return this.body;
}
};
/**
* 加载CSS 文件
*
* @param string url CSS 文件URL
*/
module.getCSS = (function() {
var temp = [];
//返回内部包函数,供外部调用并可以更改temp的值
return function( url ){
var head = module.nodes.getHead(),
flag = 0,
link,
i = temp.length - 1;
// 第二次调用的时候就不=0了
for ( ; i >= 0; i -- ) {
flag = ( temp[i] == url ) ? 1 : 0;
}
if ( flag == 0 ) {
// 未载入过
link = document.createElement( "link" );
link.setAttribute( "rel", "stylesheet" );
link.setAttribute( "type", "text/css" );
link.setAttribute( "href", url );
head.appendChild( link );
temp.push( url );
}
};
})();
/**
* 加载js 文件
*
* @param string url js 文件URL
* @param function fn 执行函数
*/
module.getJS = (function() {
var temp = [];
//返回内部包函数,供外部调用并可以更改temp的值
return function( url, fn ){
// 第二次调用的时候就不=0了
var head,
script,
onload,
flag = 0,
i = temp.length - 1;
// 第二次调用的时候就不=0了
for ( ; i >= 0; i -- ) {
flag = ( temp[i] == url ) ? 1 : 0;
}
if ( flag == 0 ) {
// 未载入过
// 记录url
temp.push( url );
// 载入
head = module.nodes.getHead();
script = document.createElement( "script" );
script.setAttribute( "src", url );
if ( "function" == typeof fn ) {
script.onload = script.onreadystatechange = function() {
// FF 下没有readyState 值,IE 有readyState 值,需加以判断
if( ! this.readyState || "loaded" == this.readyState || "complete" == this.readyState ) {
this.onload = this.onreadystatechange = null;
fn();
fn = undefined;
script = undefined;
}
};
}
head.appendChild( script );
} else {
if("function" == typeof fn){
fn();
fn = undefined;
}
}
};
})();
/**
* Execute functions when the DOM is ready
*
* @param function fn 格式的数据
*/
module.ready = function( fn ) {
if ( "function" !== typeof fn ) {
return;
}
if ( document.addEventListener ) {
// Use the handy event callback
document.addEventListener( "DOMContentLoaded", fn, false );
// If IE event model is used
} else if ( document.attachEvent ) {
// maybe late but safe also for iframes
document.attachEvent( "onreadystatechange", fn );
}
};
window.M = module;
M.ready(function() {
M(document);
});
})(window);
@zhoumengkang
Copy link
Author

使用演示

M.addModelFns({
    do_weiba_reply:{
        click:function(){
            //...
        }
    }
})

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment