在一些很小的项目里,连用jquery都还觉的大的时候,你就可以用我的这个库了。
一个库或者框架,是应需求而生的,当你的项目实际上只需要简单的一个好用的选择器 一个ajax 封装 一个兼容的事件封装的时候,你当然就会觉的jquery都太臃肿了,好吧,我那jquery剥离了这几个功能出来,本来我是只剥离jquery的domready 的, 但是发现这个东西牵扯到了jquery的事件模型的封装,那我就把jquery的事件也一并的剥离了下来,然后自己写了一个ajax封装。ok,一个最简单的js开发库成型了。代码在下面:
/*
* 简易的开发js库 暂命名为 --- 呃没有命名
* $选择器,ajax,event模块,dom.ready()方法
* 该js library 暂时不能和同样用$符号注册window标志符的js framework or library比如jquery等协作,会有命名空间冲突
*/
(function(scope){
var _my_library=scope.my_library,_$=scope.$;
var my_library=scope.my_library=scope.$=function(selector,context){
return my_library.fn.init(selector,context);
}
var quickExpr = /^[^<]*(<(.|\s)+>)[^>]*$|^#(\w+)$/;
// 简单的判断是一个html片段or是一个dom的id
//undefined;//定义一个局部的undefined
my_library.fn = {
init : function(selector,context){
selector = selector || document;
if(selector.nodeType){
return selector;
}
if ( typeof selector == "string" ) {
var match = quickExpr.exec( selector );
if ( match && (match[1] || !context) ) {
if ( match[1] ){
//return new String(selector);
var temp = document.createElement('div'),
frag = document.createDocumentFragment();
temp.innerHTML = selector;
(function(){
if(temp.firstChild) {
frag.appendChild(temp.firstChild);
arguments.callee();
}
})();
//传入的为html串,则返回包含该html串的documentfragmet文档碎片
return frag;
} else {
var elem = document.getElementById( match[3] );
if ( elem )
return elem;
return undefined;
}
} else
var $ret=PetQuery(selector,context);
return $ret.length==0 ? undefined : $ret;
} else if (my_library.isFunction(selector)){
my_library.ready( selector,document);
//如果传入的是方法,那么就自动启动ready加栽执行
}
}
};
var PetQuery = (function(){
//pet query javascript选择器 begin
var snack = /(?:[\w\-\\.#]+)+(?:\[\w+?=([\'"])?(?:\\\1|.)+?\1\])?|\*|>/ig,
exprClassName = /^(?:[\w\-_]+)?\.([\w\-_]+)/,
exprId = /^(?:[\w\-_]+)?#([\w\-_]+)/,
exprNodeName = /^([\w\*\-_]+)/,
na = [null,null];
function _find(selector, context) {
context = context || document;
var simple = /^[\w\-_#]+$/.test(selector);
if (!simple && context.querySelectorAll) {
return realArray(context.querySelectorAll(selector));
}
if (selector.indexOf(',') > -1) {
var split = selector.split(/,/g), ret = [], sIndex = 0, len = split.length;
for(; sIndex < len; ++sIndex) {
ret = ret.concat( _find(split[sIndex], context) );
}
return unique(ret);
}
var parts = selector.match(snack),
part = parts.pop(),
id = (part.match(exprId) || na)[1],
className = !id && (part.match(exprClassName) || na)[1],
nodeName = !id && (part.match(exprNodeName) || na)[1],
collection;
if (className && !nodeName && context.getElementsByClassName) {
collection = realArray(context.getElementsByClassName(className));
} else {
collection = !id && realArray(context.getElementsByTagName(nodeName || '*'));
if (className) {
collection = filterByAttr(collection, 'className', RegExp('(^|\\s)' + className + '(\\s|$)'));
}
if (id) {
var byId = context.getElementById(id);
return byId?[byId]:[];
}
}
return parts[0] && collection[0] ? filterParents(parts, collection) : collection;
}
function realArray(c) {
try {
return Array.prototype.slice.call(c);
} catch(e) {
var ret = [], i = 0, len = c.length;
for (; i < len; ++i) {
ret[i] = c[i];
}
return ret;
}
}
function filterParents(selectorParts, collection, direct) {
var parentSelector = selectorParts.pop();
if (parentSelector === '>') {
return filterParents(selectorParts, collection, true);
}
var ret = [],
r = -1,
id = (parentSelector.match(exprId) || na)[1],
className = !id && (parentSelector.match(exprClassName) || na)[1],
nodeName = !id && (parentSelector.match(exprNodeName) || na)[1],
cIndex = -1,
node, parent,
matches;
nodeName = nodeName && nodeName.toLowerCase();
while ( (node = collection[++cIndex]) ) {
parent = node.parentNode;
do {
matches = !nodeName || nodeName === '*' || nodeName === parent.nodeName.toLowerCase();
matches = matches && (!id || parent.id === id);
matches = matches && (!className || RegExp('(^|\\s)' + className + '(\\s|$)').test(parent.className));
if (direct || matches) { break; }
} while ( (parent = parent.parentNode) );
if (matches) {
ret[++r] = node;
}
}
return selectorParts[0] && ret[0] ? filterParents(selectorParts, ret) : ret;
}
var unique = (function(){
var uid = +new Date();
var data = (function(){
var n = 1;
return function(elem) {
var cacheIndex = elem[uid],
nextCacheIndex = n++;
if(!cacheIndex) {
elem[uid] = nextCacheIndex;
return true;
}
return false;
};
})();
return function(arr) {
var length = arr.length,
ret = [],
r = -1,
i = 0,
item;
for (; i < length; ++i) {
item = arr[i];
if (data(item)) {
ret[++r] = item;
}
}
uid += 1;
return ret;
};
})();
function filterByAttr(collection, attr, regex) {
var i = -1, node, r = -1, ret = [];
while ( (node = collection[++i]) ) {
if (regex.test(node[attr])) {
ret[++r] = node;
}
}
return ret;
}
return _find;
})();
//query is end
my_library.isFunction = (function() {
//修复jquery中isFunction的 BUG
// Performance optimization: Lazy Function Definition
return "object" === typeof document.getElementById ?
isFunction = function(fn){
try {
return /^\s*\bfunction\b/.test("" + fn);
} catch (x) {
return false
}
}:
isFunction = function(fn){
return "[object Function]" === Object.prototype.toString.call(fn);
};
})();
my_library.Each = function( object, callback, args ) {
var name, i = 0, length = object.length;
if ( args ) {
if ( length === undefined ) {
for ( name in object )
if ( callback.apply( object[ name ], args ) === false )
break;
} else
for ( ; i < length; )
if ( callback.apply( object[ i++ ], args ) === false )
break;
// A special, fast, case for the most common use of each
} else {
if ( length === undefined ) {
for ( name in object )
if ( callback.call( object[ name ], name, object[ name ] ) === false )
break;
} else
for ( var value = object[0];
i < length && callback.call( value, i, value ) !== false; value = object[++i] ){}
}
return object;
};
////开始为dom ready做准备 begin
Function.prototype.hookend = function(hook){
//这里侵入了Function的原形,一个挂钩函数,让函数可以继承自己执行新的函数,唉,取舍啊
var fn = this;
return function(){
var ret = fn.apply(this, arguments);
hook.apply(this, arguments);
return ret;
}
};
my_library.domReady=function(){
//domready 页面load 回调的 顶层函数,后面通过$(function(){})添加的 函数 都 在由这个函数为顶层函数的闭包作用域链上
if(scope.location.href.toString().indexOf("file:")!=0)
document.domain="qq.com";
};
my_library.isReady = false;
// Handle when the DOM is ready
my_library.ready_run = function() {
// Make sure that the DOM is not already loaded
if ( !my_library.isReady ) {
// Remember that the DOM is ready
my_library.isReady = true;
// If there are functions bound, to execute
my_library.domReady();
//这里执行所有的domready函数
my_library.domReady=null;
//把扩展的hookend原型去掉,还原原型污染
Function.prototype.hookend=null;
delete Function.prototype.hookend;
//这个方法的使命完成了
}
};
my_library.ready = function(fn) {
bindReady();
if (my_library.isReady)
fn.call(scope.document);
else
my_library.domReady=my_library.domReady.hookend(fn);
//用挂钩闭包来缓存要domready执行的function
return this;
};
var readyBound=false;
function bindReady(){
if ( readyBound ) return;
readyBound = true;
if ( document.addEventListener ) {
document.addEventListener( "DOMContentLoaded", function(){
document.removeEventListener( "DOMContentLoaded", arguments.callee, false );
my_library.ready_run();
}, false );
// If IE event model is used
} else if ( document.attachEvent ) {
document.attachEvent("onreadystatechange", function(){
if ( document.readyState === "complete" ) {
document.detachEvent( "onreadystatechange", arguments.callee );
my_library.ready_run();
}
});
if ( document.documentElement.doScroll && window == window.top ) (function(){
if ( my_library.isReady ) return;
try {
document.documentElement.doScroll("left");
} catch( error ) {
setTimeout( arguments.callee, 0 );
return;
}
my_library.ready_run();
})();
}
my_library.event.add( window, "load", my_library.ready_run );
};
var expando = "my_library" + now(), uuid = 0, windowData = {};
function now(){
return +new Date;
}
my_library.cache = {};
my_library.data = function( elem, name, data ) {
elem = elem == window ?
windowData :
elem;
var id = elem[ expando ];
if ( !id )
id = elem[ expando ] = ++uuid;
if ( name && !my_library.cache[ id ] )
my_library.cache[ id ] = {};
if ( data !== undefined )
my_library.cache[ id ][ name ] = data;
return name ?
my_library.cache[ id ][ name ] :
id;
};
my_library.removeData = function( elem, name ) {
elem = elem == window ?
windowData :
elem;
var id = elem[ expando ];
if ( name ) {
if ( my_library.cache[ id ] ) {
delete my_library.cache[ id ][ name ];
name = "";
for ( name in my_library.cache[ id ] )
break;
if ( !name )
my_library.removeData( elem );
}
} else {
try {
delete elem[ expando ];
} catch(e){
if ( elem.removeAttribute )
elem.removeAttribute( expando );
}
delete my_library.cache[ id ];
}
};
my_library.event = {
//该模块来自己jquery,所以相关注释请查看jquery的develope版本
add: function(elem, types, handler, data) {
if ( elem.nodeType == 3 || elem.nodeType == 8 )
return;
if ( elem.setInterval && elem != window )
elem = window;
if ( !handler.guid )
handler.guid = this.guid++;
if ( data !== undefined ) {
var fn = handler;
handler = this.proxy( fn );
handler.data = data;
}
var events = my_library.data(elem, "events") || my_library.data(elem, "events", {}),
handle = my_library.data(elem, "handle") || my_library.data(elem, "handle", function(){
return typeof my_library !== "undefined" && !my_library.event.triggered ?
my_library.event.handle.apply(arguments.callee.elem, arguments) :
undefined;
});
// event in IE.
handle.elem = elem;
my_library.Each(types.split(/\s+/), function(index, type) {
var namespaces = type.split(".");
type = namespaces.shift();
handler.type = namespaces.slice().sort().join(".");
var handlers = events[type];
if ( my_library.event.specialAll[type] )
my_library.event.specialAll[type].setup.call(elem, data, namespaces);
if (!handlers) {
handlers = events[type] = {};
if ( !my_library.event.special[type] || my_library.event.special[type].setup.call(elem, data, namespaces) === false ) {
if (elem.addEventListener)
elem.addEventListener(type, handle, false);
else if (elem.attachEvent)
elem.attachEvent("on" + type, handle);
}
}
handlers[handler.guid] = handler;
my_library.event.global[type] = true;
});
// Nullify elem to prevent memory leaks in IE
elem = null;
},
guid: 1,
global: {},
proxy: function( fn, proxy ){
proxy = proxy || function(){ return fn.apply(this, arguments); };
proxy.guid = fn.guid = fn.guid || proxy.guid || this.guid++;
return proxy;
},
remove: function(elem, types, handler) {
if ( elem.nodeType == 3 || elem.nodeType == 8 )
return;
var events = my_library.data(elem, "events"), ret, index;
if ( events ) {
if ( types === undefined || (typeof types === "string" && types.charAt(0) == ".") )
for ( var type in events )
this.remove( elem, type + (types || "") );
else {
if ( types.type ) {
handler = types.handler;
types = types.type;
}
my_library.Each(types.split(/\s+/), function(index, type){
var namespaces = type.split(".");
type = namespaces.shift();
var namespace = RegExp("(^|\\.)" + namespaces.slice().sort().join(".*\\.") + "(\\.|$)");
if ( events[type] ) {
if ( handler )
delete events[type][handler.guid];
else
for ( var handle in events[type] )
if ( namespace.test(events[type][handle].type) )
delete events[type][handle];
if ( my_library.event.specialAll[type] )
my_library.event.specialAll[type].teardown.call(elem, namespaces);
for ( ret in events[type] ) break;
if ( !ret ) {
if ( !my_library.event.special[type] || my_library.event.special[type].teardown.call(elem, namespaces) === false ) {
if (elem.removeEventListener)
elem.removeEventListener(type, my_library.data(elem, "handle"), false);
else if (elem.detachEvent)
elem.detachEvent("on" + type, my_library.data(elem, "handle"));
}
ret = null;
delete events[type];
}
}
});
}
// Remove the expando if it's no longer used
for ( ret in events ) break;
if ( !ret ) {
var handle = my_library.data( elem, "handle" );
if ( handle ) handle.elem = null;
my_library.removeData( elem, "events" );
my_library.removeData( elem, "handle" );
}
}
},
handle: function(event) {
var all, handlers;
event = arguments[0] = my_library.event.fix( event || window.event );
event.currentTarget = this;
var namespaces = event.type.split(".");
event.type = namespaces.shift();
all = !namespaces.length && !event.exclusive;
var namespace = RegExp("(^|\\.)" + namespaces.slice().sort().join(".*\\.") + "(\\.|$)");
handlers = ( my_library.data(this, "events") || {} )[event.type];
for ( var j in handlers ) {
var handler = handlers[j];
if ( all || namespace.test(handler.type) ) {
event.handler = handler;
event.data = handler.data;
var ret = handler.apply(this, arguments);
if( ret !== undefined ){
event.result = ret;
if ( ret === false ) {
event.preventDefault();
event.stopPropagation();
}
}
if( event.isImmediatePropagationStopped() )
break;
}
}
},
props: "altKey attrChange attrName bubbles button cancelable charCode clientX clientY ctrlKey currentTarget data detail eventPhase fromElement handler keyCode metaKey newValue originalTarget pageX pageY prevValue relatedNode relatedTarget screenX screenY shiftKey srcElement target toElement view wheelDelta which".split(" "),
fix: function(event) {
if ( event[expando] )
return event;
var originalEvent = event;
event = my_library.Event( originalEvent );
for ( var i = this.props.length, prop; i; ){
prop = this.props[ --i ];
event[ prop ] = originalEvent[ prop ];
}
if ( !event.target )
event.target = event.srcElement || document;
if ( event.target.nodeType == 3 )
event.target = event.target.parentNode;
if ( !event.relatedTarget && event.fromElement )
event.relatedTarget = event.fromElement == event.target ? event.toElement : event.fromElement;
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);
}
if ( !event.which && ((event.charCode || event.charCode === 0) ? event.charCode : event.keyCode) )
event.which = event.charCode || event.keyCode;
if ( !event.metaKey && event.ctrlKey )
event.metaKey = event.ctrlKey;
if ( !event.which && event.button )
event.which = (event.button & 1 ? 1 : ( event.button & 2 ? 3 : ( event.button & 4 ? 2 : 0 ) ));
return event;
},
proxy: function( fn, proxy ){
proxy = proxy || function(){ return fn.apply(this, arguments); };
proxy.guid = fn.guid = fn.guid || proxy.guid || this.guid++;
return proxy;
},
special: {
ready: {
setup: bindReady,
teardown: function() {}
}
},
specialAll: {
live: {
setup: function( selector, namespaces ){
my_library.event.add( this, namespaces[0], liveHandler );
},
teardown: function( namespaces ){
if ( namespaces.length ) {
var remove = 0, name = RegExp("(^|\\.)" + namespaces[0] + "(\\.|$)");
my_library.each( (my_library.data(this, "events").live || {}), function(){
if ( name.test(this.type) )
remove++;
});
if ( remove < 1 )
my_library.event.remove( this, namespaces[0], liveHandler );
}
}
}
}
};
my_library.Event = function( src ){
if( !this.preventDefault )
return new my_library.Event(src);
if( src && src.type ){
this.originalEvent = src;
this.type = src.type;
}else
this.type = src;
this.timeStamp = now();
this[expando] = true;
};
function returnFalse(){
return false;
}
function returnTrue(){
return true;
}
my_library.Event.prototype = {
preventDefault: function() {
this.isDefaultPrevented = returnTrue;
var e = this.originalEvent;
if( !e )
return;
if (e.preventDefault)
e.preventDefault();
e.returnValue = false;
},
stopPropagation: function() {
this.isPropagationStopped = returnTrue;
var e = this.originalEvent;
if( !e )
return;
if (e.stopPropagation)
e.stopPropagation();
e.cancelBubble = true;
},
stopImmediatePropagation:function(){
this.isImmediatePropagationStopped = returnTrue;
this.stopPropagation();
},
isDefaultPrevented: returnFalse,
isPropagationStopped: returnFalse,
isImmediatePropagationStopped: returnFalse
};
my_library.ajax=function(options){
var hastype= ("type" in options) ? true : false;
options={
//默认设置
method : options.method || "GET",
type : options.type || "xml",
url : options.url || "",
//超时连接,默认5秒
timeout: options.timeout || 50000,
delaytime:options.delaytime || 300,
onComplete: options.onComplete || function(){},
onError: options.onError || function(){},
onSuccess: options.onSuccess || function(){},
data : options.data || ""
//服务器将会返回的数据类型
};
var xml=getXMLHttpRequest(options.type);
//创建请求对象
xml.open(options.method , options.url);
//初始化异步请求
//超时计算 begin//
var timeoutLength=options.timeout;
var delaylength = options.delaytime;
//我们在请求5秒超时后放弃请求
var requestDone=false;
//请求超过300毫秒(目前默认为300毫秒)则延时
var isdelay=false;
setTimeout(function(){
//如果这个时候onreadystatechange回调函数已经执行请求已经返回,isdelay被该回调函数修改为null,否则设置isdelay=true说明系统已经开始延时
if (isdelay==null)
return;
isdelay=true; //系统已经延时
//记录请求是否完成,这个时候就要注意设置请求可能超时的定时监听了
setTimeout(function(){
requestDone=true;
},timeoutLength);
},delaylength)
//超时计算 end//
xml.onreadystatechange = function(){
if(xml.readyState == 4 && !requestDone){
if(httpSuccess(xml)){
var r_data=httpData( xml , options.type);
if(r_data != null)
options.onSuccess(r_data);
else
options.onError(null);
} else {
//否则就发生了错误
$.ui.showErr("服务器响应失败!http状态为"+xml.status);
options.onError();
}
options.onComplete();
//调用完成回调函数
xml = null;
//为避免内存泄漏,清理文档
}
};
xml.send();
//发送请求,建立连接
function httpSuccess(r){
try
{
//得不到服务器状态,而且我们正在请求本地文件,认为成功,200到300间的状态码表示成功 304未修改状态也酸成功 safari在文档为修改时返回空状态,,,
return !r.status && location.protocol == "file:" ||(r.status >= 200 && r.status<300) || r.status ==304 || navigator.userAgent.indexOf("Safari") > 0 && typeof r.status == "undefined" ;
}
catch (e){}
return false;
//若请求失败
};
function httpData(r,type){
//如果该方法返回null的话,则onsuccess回调函数不执行
//组装返回的对象数据
//抓去响应的http头部信息
var ct = r.getResponseHeader("content-type");
//检索返回是否为xml对象
var data = ct && ct.indexOf("xml") >= 0;
//alert(data)
//如果用户设置要输出xml,只有在type参数为xml 并且是手动配置的xml才解析response
data = (type == "xml" && hastype ) || data ? r.responseXML : r.responseText;
//因为ie不能解析responsexml
if(((type == "xml" && hastype ) || (ct && ct.indexOf("xml") >= 0) ) && window.ActiveXObject){
//ie下面需要转换一下
//data=r.responseText;
var doc = new ActiveXObject("MSxml2.DOMDocument")
doc.loadXML(r.responseText);
data=doc;
//避免内存泄漏,清理该文档
doc=null;
}
//返回json对象
if(type == "json") {
try{
/*return (new Function("return"+data))();*/
var c_obj=(new Function("return"+data))();
if(c_obj.result && c_obj.result == -1){
$.ui.showErr(c_obj.msg);
return null;
} else
return c_obj;
}
catch (e){
alert(e.message)
alert(data);
return null;
//如果alert出了这里,说明组织的json对象的数据结构错误,无法解析成对象
}
}
//请求一个script脚本
if(type == "script") {
//eval.call(window,data);//这个不行,被john骗了
var script_o=document.createElement("script");
script_o.nodeValue=data;
script_o.setAttribute("charset","utf-8");
$("head")[0].appendChild(script_o);
}
return data;
};
function getXMLHttpRequest (type){
var xmlHR=false;
if(scope.ActiveXObject){
try {xmlHR=new ActiveXObject("Msxml2.XMLHTTP");}
catch(e){try{xmlHR=new ActiveXObject("Microsoft.XMLHTTP");}
catch(e){try{xmlHR=new ActiveXObject("Msxml2.XmlHttp.4.0");}catch(e){}}}
}else if(scope.XMLHttpRequest){
xmlHR=new XMLHttpRequest();
if(xmlHR.overrideMimeType){
if (!hastype){//如果没有传入type参数那么头定义为html的
xmlHR.overrideMimeType('text/xml');
} else {
switch (type){
case "xml": xmlHR.overrideMimeType('text/xml');
break
case "json":xmlHR.overrideMimeType('text/json');
break
default : xmlHR.overrideMimeType('text/html');
}
}
}
}else{alert("Create XMLHttpRequest object false!");return false;}
return xmlHR;
}
};
})(window);
关键的 我来说下我的这个 选择器啊,这个选择器和jq最大的不同 ,就是 返回的不是一个jq对象,而是直接返回你所以找到的dom对象 or domlist。其他的,很,很简单,自己看看吧。 至于domready 就是$(function(){//这个就是push进ready准备执行的 处理函数了,})
简单吧,真的很简单。