仿照jquery封装一个自己的js库
所谓造轮子的好处就是复习知识点,加深对原版jquery的理解。
本文系笔者学习jquery的笔记,记述一个名为"dQuery"的初级版和缩水版jquery库的实现。主要涉及知识点包括面向对象,jquery,绑定,脚本化css等。
一. jquery的美元符意味什么?
先思考alert(typeof $)的结果中的$,它是一个对象,也是一个函数。
所以美元符字面上是jQuery
,其实就是一个jq对象,里面可以接受函数,字符串(#xxx,.xxx,xxx...),还有一种是对象(比如this)。
dQuery是基于面向对象实现的,所以需要先写构造函数。为了方便遍历和其它方法操作,所有内容返回到一个数组中。这个数组依附于dQuery对象存在,之后将为这个dquery对象属性添加方法。
function dQuery(vArg){//参数是变体变量
this.elements=[];//选择器选择的元素扔到这个数组中
}
因为新的对象可以接受三种类型的参数(字符串,对象,函数)。作为一个变体变量,根据匈牙利命名法可以用vXxx
命名,同时需要分类讨论变量的情况:
1.当参数为函数时,执行函数——window.onload.——不好。
jquery写作时,经常允许多个$(function()),但是写window.onload会导致最终只执行最后一个。这时需要给函数绑定window.onload事件。
绑定事件的函数如下:
function myAddEvent(obj,sEv,fn){
if(obj.attachEvent){
obj.attachEvent('on'+sEv,fn);
}else{
obj.addEventListener(sEv,fn,false);
}
}
所以,当为id选择器时,查找:document.getElementById(vArg.substring(1));并把它加到this.elements中去。
2.当参数为字符串时,执行选择器操作.
这里需要对id选择器,类选择器,元素选择器进行判断。
注意:把选择器结果丢到一个数组(dQuery.elements)中去。方便遍历事件。
用charAt进行判断参数首位:(#,.或是其它)
(1)首位为#
时:
执行document.getElementById,同时把这个字符串稍作处理,用substring(1)方法把首个字符给去掉。
(2)首位为.
时
选取class类。可以设计一个getByClass函数
function getByClass(oParent,sClass){
var aEle=oParent.getElementsByTagName('*');//选择父元素的所有元素
var aResult=[];
var re=new RegExp('\\b'+sClass+'\\b','i');//正则边界
var i=0;
for(i=0;i<aEle.length;i++){
if(re.test(aEle[i].className)){
aResult.push(aEle[i]);
}
}
return aResult;
}
在本实例中,oParent父级对象实际上就是document,另一方面,因为getByClass返回的对象实际是一个数组,所以:
this.elements=getByClass(document,vArg.substring(1));
(3)参数为对象时,返回一个对象本身
把这个对象push到
(4)绑定基本的事件——比如点击事件
在接下来就是绑定事件。比如click(function(){}),它是一个回调函数。需要用到原型(prototype)方法。
//对选择器函数绑定click事件
dQuery.prototype.click=function(fn){
var i=0;
//对于返回器数组的内容
for(i=0;i<this.elements.length;i++){
myAddEvent(this.elements[i],'click',fn);
}
}
(5)简写设置
到目前为止,在调用这个dQuery时,每次都需要这样写:
new dQuery(function(){
new dQuery('input').click(function(){
alert('a');
})
});
每次都要使用new
,不用就会出问题。
如果我想使用类似jquery的简写方式,使用$d
作为简写,可以通过一个函数来定义:
function $d(vArg){
return new dQuery(vArg);
}
所以当前的最终代码为:
//可重复调用的加载函数
function myAddEvent(obj,sEv,fn){
if(obj.attachEvent){
obj.attachEvent('on'+sEv,fn);
}else{
obj.addEventListener(sEv,fn,false);
}
}
//class选择器调用函数
function getByClass(oParent,sClass){
var aEle=oParent.getElementsByTagName('*');//选择父元素的所有元素
var aResult=[];
var re=new RegExp('\\b'+sClass+'\\b','i');//正则边界
var i=0;
for(i=0;i<aEle.length;i++){
if(re.test(aEle[i].className)){
aResult.push(aEle[i]);
}
}
return aResult;
}
//定义dQuery对象
function dQuery(vArg){//参数是变体变量
this.elements=[];//选择器选择的元素扔到这个数组中
switch(typeof vArg){
//如果参数是函数
case 'function':
myAddEvent(window,'load',vArg);
break;
//如果参数是字符串
case 'string':
switch(vArg.charAt(0)){
case '#'://id选择器参数应该为#号之后的字符段
var obj=document.getElementById(vArg.substring(1));
this.elements.push(obj);
break;
case '.'://class
this.elements=getByClass(document,vArg.substring(1));
break;
default://标签
this.elements=document.