繼續昨天的封裝,今天的部分繼昨天選擇器以後實現了css樣式的獲取和添加,attr的獲取和添加和一部分事件的封裝;只是我本身的理解,不妥之處歡迎你們在評論中提出,相互學習,共同提升css
/** * Created by Jason on 2016/12/31. */ //jquery 的構造函數 function Jquery(arg){ //用來存選出來的元素 this.elemenets=[]; switch(typeof arg){ case 'function' : domReady(arg); break; case 'string' : this.elements = getEle(arg); break; case 'object' : this.elements.push(arg); break; } } //DOM ready onload 若是參數是函數,則進行domReady操做 function domReady(fn){ // FF chrome if(document.addEventListener){ //jquery中已經省略false,false解決低版本火狐兼容性問題 document.addEventListener('DOMContentLoaded',fn,false); }else{ document.attachEvent('onreadystatechange',function(){ if(document.readyState=='complete'){ fn(); } }); } } function getByClass(oParent,sClass){ //高級瀏覽器支持getElementsByClassName直接使用 if(oParent.getElementsByClassName){ return oParent.getElementsByClassName(sClass); }else{ //不支持須要選中全部標籤的類名來選取 var res=[]; var aAll=oParent.getElementsByTagName('*'); for(var i=0;i<aAll.length;i++){ //選中標籤的所有類名是個str='btn on red'=aAll[i].className 使用正則 reg=/\b sClass \b/g var reg= new RegExp('\\b'+sClass+'\\b','g'); if(reg.test(aAll[i].className)){ res.push(aAll[i]); } } return res; } } //若是參數是str 進行選擇器的操做 function getByStr(aParent,str){ //用來存放選中的元素的數組 這個數組在getEle存在,爲了每次執行的時候都須要清空,因此使用局部函數的變量 var aChild=[]; //aParent開始是[document],再執行完getByStr的時候getEle將aParent指向了getByStr函數的返回值aChild數組以確保循環父級下面的全部匹配元素 for(var i=0;i<aParent.length;i++){ switch(str.charAt(0)){ //id選擇器 eg: #box 使用document.getElementById選取 case '#': var obj=document.getElementById(str.substring(1)); aChild.push(obj); break; //類選擇器 eg: .box 使用上面封裝的getByClass選取 case '.': //因爲一個標籤能夠有多個類選擇器 因此須要進行循環選取 var aRes=getByClass(aParent[i],str.substring(1)); for(var j=0;j<aRes.length;j++){ aChild.push(aRes[j]); } break; //今天先簡單的編寫選擇器 這裏咱們假設除了id和類選擇器,就是標籤選擇器 default: // 若是是li.red 那麼用正則來判斷 if(/\w+\.\w+/g.test(str)){ //先選擇標籤,在選擇類選擇器 使用類選擇器的時候重複選擇器函數便可 var aStr=str.split('.'); var aRes=aParent[i].getElementsByTagName(aStr[0]); var reg=new RegExp('\\b'+aStr[1]+'\\b','g'); //循環選取標籤,注意外層已經有i的循環 for(var j=0;j<aRes.length;j++){ if(reg.test(aRes[j].className)){ aChild.push(aRes[j]); } } //若是是li:eq(2) 或者 li:first這樣的選擇器 書寫正則是的時候注意()可有能夠無爲? 有或者沒有爲* 至少有一個也就是若干個爲+ {2,5}這種則爲2-5個 }else if(/\w+\:\w+(\(\d+\))?/g.test(str)){ //講str進行整理 [li,eq,2] 或者 [li,first] var aStr=str.split(/\:|\(|\)/); //aStr[2]是eq、lt、gt傳入的參數,這裏使用n來保存 var n=aStr[2]; //在父級下獲取全部匹配aStr[0]項的標籤 var aRes=aParent[i].getElementsByTagName(aStr[0]); //這時候會循環判斷aStr[1]項是的內容,jquery中常常使用的爲eq、lt、gt、even、odd、first、last switch(aStr[1]){ //若是是eq則把第n項傳入aChild數組便可 case 'eq': aChild.push(aRes[n]); break; //若是是lt須要將aRes數組中獲取到的小於n的標籤循環推入aChild中 case 'lt': for(var j=0;j<n;j++){ aChild.push(aRes[j]); } break; //若是是gt則和lt相反 case 'gt': for(var j=n;j<aRes.legth;j++){ aChild.push(aRes[j]); } break; //若是是event的話須要隔數添加,注意jquery中的event是從第0開始循環的 case 'event': for(var j=0;j<aRes.length;j+=2){ aChild.push(aRes[j]); } break; //若是是odd的和event不一樣的只是從第1項開始循環 case 'odd': for(var j=1;j<aRes.length;j+=2){ aChild.push(aRes[j]); } break; //若是是first,則將aRes[0]推入aChild case 'first': aChild.push(aRes[0]); break; case 'last': aChild.push(aRes[aRes.length-1]); break; } //屬性選擇器 eg:input[type=button] 一樣適用正則來判斷 }else if(/\w+\[\w+\=\w+\]/g.test(str)){ //將屬性選擇器切成數組 [input,type,button] var aStr=str.split(/\[|\=|\]/g); var aRes=aParent[i].getElementsByTagName(aStr[0]); //在選中標籤中選出有aRes[1]的屬性 for(var j=0;j<aRes.length;j++){ //把屬性值爲aRes[2]的標籤推入aChild中 if(aRes[j].getAttribute(aStr[1])==aStr[2]){ aChild.push(aRes[j]); } } //標籤選擇器 div、span }else{ var aRes=aParent[i].getElementsByTagName(str); for(var j=0;j<aRes.length;j++){ aChild.push(aRes[j]); } } break; } } return aChild; } function getEle(str){ //若是是字符串的話先要去除收尾空格 eg:" on replace index play auto " var arr = str.replace(/^\s+|\s+$/g,'').split(/\s+/g); var aChild = []; var aParent = [document]; for(var i = 0;i<arr.length;i++){ aChild = getByStr(aParent,arr[i]); aParent = aChild } return aChild; } //實現jquery $符號的寫法 function $(arg){ return new Jquery(arg); } //css方法 Jquery.prototype.css=function(name,value){ //設置單個樣式的時候使用 oEle.css(name,value); 注意多是一個元素,也多是一組元素,須要循環添加 if(arguments.length==2){ for(var i=0;i<this.elements.length;i++){ this.elements[i].style[name]=value; } }else{ //當參數爲字符串是獲取樣式 oEle.css(name); 當參數爲object的時候是批量添加樣式{name1:value1,name2:value2} 這裏判斷的是參數類型 switch(typeof name){ //獲取元素的樣式只要返回獲取的樣式的值便可,jqeury中當選中一組元素獲取樣式的時候是默認返回第一個元素的樣式 case 'string': return this.elements[0].style[name]; break; //當爲參數爲json的時候循環json添加樣式 case 'object': for(var i=0;i<this.elelemts.length;i++){ for(var item in name){ this.elements[i].style[item]=name[item]; } } break; } } }; //attr 獲取屬性 和css的思路是同樣的,這裏就不過多的註釋了 Jquery.prototype.attr=function(name,value){ if(arguments.length==2){ for(var i=0;i<this.elements.length;i++){ this.elements[i].setAttribute[name]=value; } }else{ switch(typeof name){ case 'string': return this.elements[0].getAttribute[name]; break; case 'object': for(var i=0;i<this.elements.length;i++){ for(var item in name){ this.elements.setAttribute[item]=item; } } break; } } }; //事件,使用了下面的事件綁定函數封裝 jquery中事件全是綁定的 'mouseover mouseout click keydown keyup resize scroll load change'.replace(/\w+/g,function(sEv){ Jquery.prototype[sEv]=function(fn){ for(var i=0;i<this.elements.length;i++){ addEvent(this.elements[i],sEv,fn); } } }); //事件綁定函數的封裝 function addEvent(obj,sEv,fn){ //高級瀏覽器支持addEventListener if(obj.addEventListener){ obj.addEventListener(sEv,function(ev){ var ev=ev || event; fn.apply(obj,arguments); },false); }else{ obj.attachEvent('on'+sEv,function(ev){ var ev=ev || event; fn.apply(obj,arguments); }); } } //onmouseenter事件的添加,onouseenter是進入範圍後只觸發一次,這裏使用onmouseover實現 Jquery.prototype.mouseenter=function(fn){ for(var i=0;i<this.elements.length;i++){ addEvent(this.elements[i],'mouseenter',function(ev){ //獲取鼠標上一次的位置 var ev=ev || event; var oFrom=ev.fromElement || ev.relatedTarget; //在構造函數中,若是有return就直接返回return後面的東西,若是沒有return會返回構造函數的屬性值;這裏判斷上一次鼠標的位置是否是在this的範圍以內,若是是就直接返回空結束onmouseenter事件,若果沒有就修改this的指向 if(this.contains(oFrom)){ return; } fn&&fn.apply(this,arguments); }); } };