簡易版jQuery——mQuery


前面的話

  雖然jQuery已經日漸式微,但它里面的許多思想,如選擇器、鏈式調用、方法函數化、取賦值合體等,有的已經變成了標准,有的一直影響到現在。所以,jQuery是一個偉大的前端框架。前端世界日新月異,由於實在是沒有時間去精讀源碼,於是自己封裝一個簡易版本的jQuery,來梳理jQuery的核心思路

 

基本構架

  由於火柴的英文是match,應該將這個簡單框架稱為mQuery。使用面向對象的寫法來寫mQuery,構造函數是Mquery(),調用$()方法,將根據Mquery()構造函數,創建一個實例對象

//構造函數
function Mquery(arg){}
function $(arg){
  return new Mquery(arg);
} 

  jquery幾大特征:

  1、通過$()選擇的元素都是一個集合,即使僅僅是一個元素

  因此,創建一個elements屬性為一個數組,去接收獲取的元素

//構造函數
function Mquery(arg){
  //保存所選擇的元素
  this.elements = [];
}

  2、鏈式調用

  所以,原型函數要返回this,以實現鏈式調用的效果

 

$函數

  $函數根據參數類型的不同,用途也不同

  1、參數為函數時,則直接運行

$(function(){
    console.log(1)
})

  2、參數為對象時,則把DOM對象轉換為$對象

$(document.body)

  3、參數為字符串時,則根據字符串選擇出元素,並轉換為$對象

$('#box')

  下面根據以上三個分類,來編寫Mquery構建函數

//事件綁定兼容寫法
function _addEvent(target,type,handler){
    if(target.addEventListener){
        target.addEventListener(type,function(e){
          //如果事件函數中出現 return false;則阻止默認事件和阻止冒泡
          if(typeof handler == 'function' && handler() === false){
            e.preventDefault();
            e.cancelBubble = true;
          }
        },false);
    }else{
        target.attachEvent('on'+type,function(event){
          if(typeof handler == 'function' && handler() === false){
            event.cancelBubble = true;
            event.returnValue = false;
          }
            return handler.call(target,event);
        });
    }
}

//將類數組轉換成數組
function _toArray(arrayLike){
  return Array.prototype.slice.call(arrayLike);
}
//構造函數
function Mquery(arg){
  //保存所選擇的元素
  this.elements = [];
  switch(typeof arg){
    //當參數是函數時,如$(function(){})(),直接運行里面的代碼
    case 'function':
      _addEvent(window,'load',arg);
      break;
    //當參數是字符串時,選擇元素
    case 'string':
      this.elements = _toArray(document.querySelectorAll(arg));              
      break;
    //當參數是DOM對象時,將DOM對象轉換為$對象  
    case 'object':
      if(arg.constructor == Array){
        this.elements = arg;
      }else{
        this.elements.push(arg);
      }      
      break;
  }
}

 

HTML、CSS及特性設置

  下面來介紹常用的HTML、CSS及特性設置

【HTML】

  對於文本內容來說,一般地,有三種方法:html()、text()和val()。本文只實現最常用的html()方法

  當html()方法沒有參數時,表示獲取內容;有一個參數時,表示設置內容

//HTML獲取與設置
Mquery.prototype.html = function(str){
  //設置
  if(str){
    for(var i = 0; i < this.elements.length; i++){
      this.elements[i].innerHTML = str;
    }
  //獲取
  }else{
    return this.elements[0].innerHTML;
  }  
  return this;
}

【CSS】

  對於CSS來說,有兩種參數格式:一種是json格式,一種是字符串格式

  當第一個參數為對象時,則判斷為json格式,否則為字符串格式

  對於字符串格式來說,只有一個參數時,為獲取樣式,兩個參數時,為設置樣式

  獲取樣式時,僅獲取當前集合中第0個元素的樣式;設置樣式時,則設置當前集合中所有元素的樣式

//獲取計算樣式兼容寫法
function _getCSS(obj,style){
    if(window.getComputedStyle){
        return getComputedStyle(obj)[style];
    }
    return obj.currentStyle[style];
}
//CSS獲取與設置
Mquery.prototype.css = function(attr,value){
  //如果是對象的形式,以對象的形式設置
  if(typeof attr == 'object'){
    for(var att in attr){
      for(var j = 0; j < this.elements.length; j++){
        this.elements[j].style[att] = attr[att];
      }
    }
  //如果不是對象的形式
  }else{
    //設置
    if(arguments.length == 2){
      for(var i = 0; i < this.elements.length; i++){
        this.elements[i].style[attr] = value;
      }
    //獲取
    }else if(arguments.length == 1){
      return _getCSS(this.elements[0],attr)
    }
  }
  return this;
}

【attr】

  特性設置與獲取的思路與CSS類似,只是方法變成了setAttribute()和getAttribute()

//attr獲取與設置
Mquery.prototype.attr = function(attr,value){
  //如果是對象的形式
  if(typeof attr == 'object'){
    for(var att in attr){
      for(var j = 0; j < this.elements.length; j++){
        this.elements[j].setAttribute(att,attr[att]);
      }
    }
  //如果不是對象的形式
  }else{
    //設置
    if(arguments.length == 2){
      for(var i = 0; i < this.elements.length; i++){
        this.elements[i].setAttribute(attr,value);
      }
    //獲取
    }else if(arguments.length == 1){
      return this.elements[0].getAttribute(attr);
    }
  }
  return this;
}

 

事件綁定

【on】

  在jQuery中,最常用的事件綁定方法就是on方法。在on方法中要特別注意的是this的綁定,由於函數fn中的this實際上是window,所以應該將fn的this綁定到當前元素

//事件綁定
Mquery.prototype.on = function(eventType,fn){
  for(var i = 0; i < this.elements.length; i++){
    _addEvent(this.elements[i],eventType,fn.bind(this.elements[i));
  }
  return this;
}

【click和hover】

  click方法是一個簡寫方法

Mquery.prototype.click = function(fn){
  this.on('click',fn);
  return this;
}

  hover方法是mouseover和mouseout的合成方法

Mquery.prototype.hover = function(fnOver,fnOut){
  this.on('mouseover',fnOver);
  this.on('mouseout',fnOut);
  return this;
}

【return false】

  在jQuery中,使用return false可以同時阻止默認行為和阻止冒泡

//事件綁定兼容寫法
function _addEvent(target,type,handler){
    if(target.addEventListener){
        target.addEventListener(type,function(e){
          //如果事件函數中出現 return false;則阻止默認事件和阻止冒泡
          if(typeof handler == 'function' && handler() === false){
            e.preventDefault();
            e.cancelBubble = true;
          }
        },false);
    }else{
        target.attachEvent('on'+type,function(event){
          if(typeof handler == 'function' && handler() === false){
            event.cancelBubble = true;
            event.returnValue = false;
          }
            return handler.call(target,event);
        });
    }
}

 

其他設置

  jQuery的功能非常強大。下面選擇一些常用功能進行實現

【顯示隱藏】

//隱藏
Mquery.prototype.hide = function(){
  for(var i = 0; i < this.elements.length; i++){
    //保存當前元素的display值
    this.elements[i].displayValue = this.elements[i].style.display;
    this.elements[i].style.display = 'none';
  }
  return this;
}
//顯示
Mquery.prototype.show = function(){
  for(var i = 0; i < this.elements.length; i++){
   this.elements[i].style.display = this.elements[i].displayValue;
   //刪除保存的元素的display值
   delete this.elements[i].displayValue;
  }
  return this;
}

【插件設置】

$.extend = function(json){ 
  for(var attr in json){
    $[attr] = json[attr];
  }
};
$.fn = {};
$.fn.extend = function(json){
  for(var attr in json){
    Mquery.prototype[attr] = json[attr];
  } 
};

【索引設置】

//根據索引選擇元素
Mquery.prototype.eq = function(number){
  return $(this.elements[number]);
}

//根據元素獲取索引
Mquery.prototype.index = function(){
  var elements = this.elements[0].parentNode.children;
  for(var i = 0; i < elements.length; i++){
    if(elements[i] === this.elements[0]){
      return i;
    }
  }
}

【子級篩選】

//篩選出當前匹配的元素集合中每個元素的后代
Mquery.prototype.find = function(str){
  var arr = [];
  for(var i = 0; i < this.elements.length; i++){
    Array.prototype.push.apply(arr,this.elements[i].querySelectorAll(str));
  }
  return $(arr);
}

 

完整源碼

  下面是mQuery的完整源碼

//事件綁定兼容寫法
function _addEvent(target,type,handler){
    if(target.addEventListener){
        target.addEventListener(type,function(e){
          //如果事件函數中出現 return false;則阻止默認事件和阻止冒泡
          if(typeof handler == 'function' && handler() === false){
            e.preventDefault();
            e.cancelBubble = true;
          }
        },false);
    }else{
        target.attachEvent('on'+type,function(event){
          if(typeof handler == 'function' && handler() === false){
            event.cancelBubble = true;
            event.returnValue = false;
          }
            return handler.call(target,event);
        });
    }
}
//獲取計算樣式兼容寫法
function _getCSS(obj,style){
    if(window.getComputedStyle){
        return getComputedStyle(obj)[style];
    }
    return obj.currentStyle[style];
}

//將類數組轉換成數組
function _toArray(arrayLike){
  return Array.prototype.slice.call(arrayLike);
}
//構造函數
function Mquery(arg){
  //保存所選擇的元素
  this.elements = [];
  switch(typeof arg){
    //當參數是函數時,如$(function(){})(),直接運行里面的代碼
    case 'function':
      _addEvent(window,'load',arg);
      break;
    //當參數是字符串時,選擇元素
    case 'string':
      this.elements = _toArray(document.querySelectorAll(arg));              
      break;
    //當參數是DOM對象時,將DOM對象轉換為$對象  
    case 'object':
      if(arg.constructor == Array){
        this.elements = arg;
      }else{
        this.elements.push(arg);
      }      
      break;
  }
}
//根據索引選擇元素
Mquery.prototype.eq = function(number){
  return $(this.elements[number]);
}
//根據元素獲取索引
Mquery.prototype.index = function(){
  var elements = this.elements[0].parentNode.children;
  for(var i = 0; i < elements.length; i++){
    if(elements[i] === this.elements[0]){
      return i;
    }
  }
}
//篩選出當前匹配的元素集合中每個元素的后代
Mquery.prototype.find = function(str){
  var arr = [];
  for(var i = 0; i < this.elements.length; i++){
    Array.prototype.push.apply(arr,this.elements[i].querySelectorAll(str));
  }
  return $(arr);
}
//CSS獲取與設置
Mquery.prototype.css = function(attr,value){
  //如果是對象的形式,以對象的形式設置
  if(typeof attr == 'object'){
    for(var att in attr){
      for(var j = 0; j < this.elements.length; j++){
        this.elements[j].style[att] = attr[att];
      }
    }
  //如果不是對象的形式
  }else{
    //設置
    if(arguments.length == 2){
      for(var i = 0; i < this.elements.length; i++){
        this.elements[i].style[attr] = value;
      }
    //獲取
    }else if(arguments.length == 1){
      return _getCSS(this.elements[0],attr)
    }
  }
  return this;
}
//attr獲取與設置
Mquery.prototype.attr = function(attr,value){
  //如果是對象的形式
  if(typeof attr == 'object'){
    for(var att in attr){
      for(var j = 0; j < this.elements.length; j++){
        this.elements[j].setAttribute(att,attr[att]);
      }
    }
  //如果不是對象的形式
  }else{
    //設置
    if(arguments.length == 2){
      for(var i = 0; i < this.elements.length; i++){
        this.elements[i].setAttribute(attr,value);
      }
    //獲取
    }else if(arguments.length == 1){
      return this.elements[0].getAttribute(attr);
    }
  }
  return this;
}
//HTML獲取與設置
Mquery.prototype.html = function(str){
  //設置
  if(str){
    for(var i = 0; i < this.elements.length; i++){
      this.elements[i].innerHTML = str;
    }
  //獲取
  }else{
    return this.elements[0].innerHTML;
  }  
  return this;
}
//隱藏
Mquery.prototype.hide = function(){
  for(var i = 0; i < this.elements.length; i++){
    //保存當前元素的display值
    this.elements[i].displayValue = this.elements[i].style.display;
    this.elements[i].style.display = 'none';
  }
  return this;
}
//顯示
Mquery.prototype.show = function(){
  for(var i = 0; i < this.elements.length; i++){
   this.elements[i].style.display = this.elements[i].displayValue;
   //刪除保存的元素的display值
   delete this.elements[i].displayValue;
  }
  return this;
}
//事件綁定
Mquery.prototype.on = function(eventType,fn){
  for(var i = 0; i < this.elements.length; i++){
    _addEvent(this.elements[i],eventType,fn.bind(this.elements[i]));
  }
  return this;
}
//click簡寫
Mquery.prototype.click = function(fn){
  this.on('click',fn);
  return this;
}
//鼠標移入移出
Mquery.prototype.hover = function(fnOver,fnOut){
  this.on('mouseover',fnOver);
  this.on('mouseout',fnOut);
  return this;
}
$.extend = function(json){ 
  for(var attr in json){
    $[attr] = json[attr];
  }
};
$.fn = {};
$.fn.extend = function(json){
  for(var attr in json){
    Mquery.prototype[attr] = json[attr];
  } 
};
function $(arg){
  return new Mquery(arg);
} 

 

實際應用

  下面使用mQuery來實現一個簡單的效果

<style>
div { width:60px; height:60px; margin:5px; float:left; }
</style>
<span id="result"></span>
<div style="background-color:blue;"></div>
<div style="background-color:rgb(15,99,30);"></div>
<div style="background-color:#123456;"></div>
<div style="background-color:#f11;"></div>
<script src="mQuery.js"></script>
<script>
$("div").click(function(){
 $("#result").html("背景顏色是 " + $(this).css("background-color"));
})
</script> 

  點擊不同顏色的元素塊,將在右側顯示具體的顏色值

  


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM