在网上下了一个类似于jQuery的小框架,分析源码,看看怎么写框架。
选择器Select
//用沙箱闭包其整个代码,只有itcast和I暴漏在全局作用域 (function( window , undefined){ //Itcast函数,参数:selector。返回值一个Itcast对象,功能:new Itcast。prototype。init() function Itcast(selector){ return new Itcast.prototype.init(); } // Itcast的原型属性用替换重新定义 Itcast.prototype = { constructor: Itcast, type: "Itcast", length: 0, //constructor指向构造函数Itcast,type记录对象类型“Itcast”,length:变成伪数组 // init函数 功能:Itcast对象的真正的构造函数,根据参数类型,进行不同的处理: 参数:selector。 // 返回值:只要在适当的位置返回即可,构造函数不需要返回值,但是为了提醒这里是为了创建对象,所以写成return this //因为init是构造函数,this就是指创建出来的这个对象,现在要把获取到的dom对象全部追加到this中来,再通过Itcast返回 // 。因为Itcast和init是用的同一个原型,所以认为此处创建出来的就是Itcast对象 init:function(selector){ var push = [].push; if( typeof selector == "string"){ // 如果selector是html字符串,用parseHtml将其转成DOM伪数组,再转成this(Itcast伪数组) if( selector.charAt(0) == "<"){ push.apply(this , parseHTML(selector)); }else{ // 如果selector是选择器。用Select函数, push.apply(this , Select(selector)); } } // 如果是function ,近似于onload if( typeof selector == "function"){ } // 如果是dom,追加到this(Itcast伪数组)中 if( selector.nodeType ){ } // 如果是Itcast对象,追加到新的Itcast对象中返回 if( selector.type = "Itcast" ){ } } } //让init的原型属性指向Itcast。prototype。即有init创建出来的对象也就是Itcast对象了 Itcast.prototype.init.prototype = Itcast.fn = Itcast.prototype; //设定Itcast的扩展方式,Itcast。extend(静态成员扩展) 。 Itcast.prototype.extend(动态成员扩展) // .函数参数: 对象option。 返回值: 无, 功能:将option中的属性或方法依次添加给Itcast或Itcast.fn Itcast.fn.extend = Itcast.extend = function(option){ for( var k in option){ this[ k ] = option[ k ]; } } //模块化,功能化。(构造函数的补充) //扩充静态成员 //选择器Select(闭包,仅将Select暴漏在外面)参数:无,返回值Select函数。 // 功能:再沙箱中将Select函数定义好, var Select = (function(){ //数据初始化: //将某些浏览器是否支持a方法用对象support储存起来以免每一次动用函数的时候都要进行查找 // 是否提供可以看函数体是否包含 [native code]即可;,正则表达式的变量以r开头 var rnative = /[native code]/, push = [].push , i, div = document.createElement("div"); var support = { qsa: rnative.test(document.querySelectorAll), getByClass : rnative.test( document.getElementsByClassName), getByClass2: rnative.test(div.getElementsByClassName), trim: rnative.test(String.prototype.trim), indexOf: rnative.test(Array.prototype.indexOf), } // 要用的函数提前准备好 // push,push没有兼容性问题但是push.apply再IE低版本,不能展开伪数组,会报错 // ,因此用try{}catch的方法兼容 try{ push.apply([],document.getElementsByTagName("*")); }catch(e){ //z自定义push.apply的函数,参数数组a,伪数组b, 返回值 数组a, // 功能:将b中的内容添加到 a当中; var push = { apply : function( a , b){ for( var i =0 ; i< b.length ; i++ ){ a[ a.length++ ] = b[ i ]; } return a; } } } //trim 参数:字符串 ,返回值:首位去除空白的I字符串。功能:将字符串的两端的空白去出,并返回 function trim( str ){ if( support.trim ){ return str.trim(); }else{ var rtrim = /^s+|s+$/; return str.replace( rtrim , ""); } } // indexOf,参数数组arr,a要查找项,返回值:a的索引值,如果没有返回-1 //indexOf 还需要一个参数, 就是 查找的开始位置 function indexOf( arr , a,startIndex){ startIndex = startIndex || 0; if(support.indexOf){ return arr.indexOf(a , startIndex); } for(var i = startIndex; i< arr.length ;i++){ if( arr[ i ] === a){ return i; } } return -1; } //unique函数,参数:数组 ,返回值:去重之后的数组,功能: 将穿进来的数组中的重复项去除 function unique( arr ){ var array = []; for( var i=0 ; i< arr.length ;i++){ if(indexOf( array ,arr[ i ]) == -1){ array.push( arr[i]); } } return array; } //核心函数Select:参数:selector选择器, 要被添加元素的数组或伪数组results, 返回值results //功能: 将selector对应的DOM对象,追加到results中输出 function Select(selector ,results){ results = results || []; if( typeof selector !== "string"){ return ; } //如果浏览器支持querySelectorAll就用,如果不支持,就自己定义一个select2 if( support.qsa ){ return document.querySelectorAll( selector ); }else { return select2( selector); } } // select2,参数:selector选择器,返回值dom对象, function select2( selector ,results){ // 功能:看选择器是不是并集选择器,将selector用trim函数去掉首尾的空白() results = results || []; // ,再用split函数切割成数组, var arr = selector.split(","); for( i = 0 ; i < arr.length ; i++){ // 再用select3函数进行处理,将切割好的字符串用trim方法取出前后空白 select3( trim(arr[ i ]) , results); } return unique(results); } function select3 ( selector , results){ results = results || []; //select3函数:参数select ,返回值dom对象。功能:判断选择器是“*”还是id,还是类,还是标签 var first = selector.charAt(0); //注意如果是类选择器,document.getElementsByClassName有浏览器兼容性问题。 //区分好后,调用相应的函数进行处理 //此处屏蔽掉后代选择器的影响,此时如果selector经过了首尾去空格后还有空格,说明是后代选择器 if( selector.slice(" ").length == 1){ if(selector == "*"){ /* results = document.getElementsByTagName("*"); return results; ,如果results原来就有内容,此处把results中的内容全部覆盖了所以不行, 要将选择器对应的dom元素挨个追加到results中 */ }else if( first == "#"){ return id(selector.slice(1) , results); }else if( first == "."){ //类 return c(selector.slice(1),results); }else { //标签 return t(selector , results) } }else{ //如果是后代选择器,此处咱不处理,抛出一个bug,提示升级浏览器 throw new Error("您的浏览器版本过低,请升级浏览器") } } //参数:选择器selector 被追加元素的数组。 返回值: results //功能: 将selector对应的元素挨个追加到results中并输出, function id( selector ,results ){ results = results || []; push.apply(results , document.getElementById(selector)); return results; } // 标签 function t( selector , results){ results = results || []; push.apply( results , document.getElementsByTagName( selector)); return results; } //类,getElementsByClassName有浏览器兼容行问题, function c( selector , results ){ results = results || []; push.apply( results , getByClass( selector , document)); return results; } //兼容类选择器,参数:类名className ,查找返回node,返回值:返回查找到的dom元素数组 //功能: 用className属性查找node中的符合条件的dom对象,并返回对象数组 function getByClass(className , node){ node = node || document; //如果浏览器支持 if( node == document && support.getByClass || node.nodeType && support.getByClass2){ return node.getElementsByClassName(className); }else{ //如果浏览器不支持 //获取所有的标签,遍历 var list = node.getElementsByTagName("*"), arr = [], tempClassName; for( var i = 0 ; i< list.length ;i++){ tempClassName = list[ i ]; if( !tempClassName ){ continue; } //再class属性存在的情况下 //用slice(“ ”)分割 //判断是否与className相同 //如果相同追加到results中 if(indexOf(tempClassName.slice(" "),className) !== -1){ arr.push(tempClassName); } } return arr; } } return Select; })(); // 解析html字符串parseHTML //在解析过程中,需要在内存中创建一个node,为了不暴漏在外面使用沙箱(自调自用的函数,返回该数组) //参数:selector,(html字符串),返回值存储dom的数组,功能: 将html字符串转化成dom对象储存在数组中 Itcast.parseHTML =(function (){ var node = document.createElement("div"); var arr = []; function parseHTML(selector){ node.innerHTML = selector; arr.push.apply(arr , node.childNodes); return arr; } return parseHTML; })(); //扩充实例成员 Itcast.fn.extend({ appendTo: function ( parent , child ){ parent.appendChild( child ); } }) //将Itcast挂在window上 window.Itcast = window.I = Itcast; })(window);