前言:在前端三大框架没有出现的时候,我们开发时候可能一般会使用到jQuery,它是一个高效、精简并且功能丰富的 JavaScript 工具库。它提供的 API 易于使用且兼容众多浏览器,这让诸如 HTML 文档遍历和操作、事件处理、动画和 Ajax 操作更加简单,例如常见的$('div').html()
$('#div1').html('bbbbbb').css('background','green')等等的操作是如何工作的呢,自己做了个简单的Vquery,分享下自己的见解及书写步骤
1、jquery中的顶级对象是$,为了保持一致或更简单的书写,我也采用了$作为函数名(当然也可以取任意自己定义的名称,如MyQuery等)
image.png
2、如上图所示,函数$中返回一个new的对象,所以需要创建一个名为Vquery的构造函数,我们会给这个构造函数传递一个参数,并会对此参数做对应的处理,涉及到js中的关于原型的一些东西,Vquery.prototype.xxx=function(){},给构造函数的原型对象添加属性,也就是添加一个个的方法,如click,hide,show,html等方法
image.png


image.png
3、当然也少不了一些基础的方法或者工具函数,例如获取元素class,绑定事件的on,获取最终样式等
image.png
上面的就是基本的过程以及部分示例代码,在Vquery构造函数中需要判断传递参数的类型,如我们常用的$(function(){})或者$('div')或者$('#div')等都是有不同的处理方式
4、关于使用时候一些东西的补充,我们可能会这样使用jquery,$('#div').css('background')也可能这样使用$('#div').css('background':'red'),前者是获取元素样式,后者是设置元素样式,它背后的实现原理如下,通过判断参数个数确定是设置还是获取
image.png
5、说说链式操作实现的原理,jQuery中的每个挂载在原型对象下面的方法最后有return this,这样在执行$('xxx')(最上面一张截图)的时候就执行了里面的new Vquery返回了本身。
6、创建html文件并测试结果如下
image.png


image.png
结语:这个只是基本的雏形,实际的jQuery要复杂的很多,例如获取复杂元素($('#div .className1')),事件委托,兼容性等的未考虑,参考代码如下,如有问题,欢迎指正


//绑定事件的函数
function addEvent(obj,type,fn){
    if(obj.addEventListener){
        obj.addEventListener(type,fn,false);
    }else{
        obj.attachEvent('on'+type,fn);
    }
}

//JS原生获取class的函数
function getByClass(oParent,sClass){
    var arr=[];
    var elems=oParent.getElementsByTagName('*');
    for(var i=0;i<elems.length;i++){
        if(elems[i].className==sClass){
            arr.push(elems[i]);
        }
    }
    return arr;
}

//JS原生转化为数组的一种方法  由于后面的获取标签元素得到的是一个类数组
function toArray(elem){
    var arr=[];
    for(var i=0;i<elem.length;i++){
        arr.push(elem[i]);
    }
    return arr;
}

//JS获取最终样式
function getStyle(obj,attr){
    if(obj.currentStyle){
        return obj.currentStyle[attr];
    }else{
        return getComputedStyle(obj,false)[attr];
    }
}

function Vquery(vArg){
    this.elements=[];   //创建一个数组用来存放获取到的元素     ----    选择到元素的一个集合
    switch(typeof vArg){
        case 'function':
            //window.onload=vArg;
            addEvent(window,'load',vArg);
        break;
        case 'string':
            switch(vArg.charAt(0)){
                case '#':
                    this.elements.push(document.getElementById(vArg.substring(1)));
                break;
                case '.':
                    this.elements=getByClass(document,vArg.substring(1));
                break;
                default:
                    this.elements=toArray(document.getElementsByTagName(vArg));
                break;
            }
        break;
        case 'object':
            if(vArg.constructor==Array){
                this.elements=vArg;
            }else{
                this.elements.push(vArg);
            }
        break;
    }
}

Vquery.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;
}
Vquery.prototype.click=function(fn){
    //    for(var i=0;i<this.elements.length;i++){
    //        addEvent(this.elements[i],'click',fn);
    //    }
    this.on('click',fn);   //后面的on函数在这里也可以直接调用  简化了代码
    return this;
}
Vquery.prototype.mouseover=function(fn){
    //    for(var i=0;i<this.elements.length;i++){
    //        addEvent(this.elements[i],'mouseover',fn);
    //    }
    this.on('mouseover',fn);
    return this;
}
Vquery.prototype.on=function(events,fn){
    for(var i=0;i<this.elements.length;i++){
        addEvent(this.elements[i],events,fn);
    }
    return this;
}
Vquery.prototype.hide=function(){
    for(var i=0;i<this.elements.length;i++){
        this.elements[i].style.display='none';
    }
    return this;
}
Vquery.prototype.show=function(){
    for(var i=0;i<this.elements.length;i++){
        this.elements[i].style.display='block';
    }
    return this;
}
Vquery.prototype.hover=function(fnOver,fnOut){
    this.on('mouseover',fnOver);
    this.on('mouseout',fnOut);
    return this;
}
Vquery.prototype.css=function(attr,value){
     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 getStyle(this.elements[0],attr);
     }
     return this;
}
Vquery.prototype.attr=function(attr,value){
    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;
}
Vquery.prototype.eq=function(num){
    //return this.elements[num];   注意这样返回的是这个元素的集合   而要想调用css方法的话  前面是需要一个对象的
    return $(this.elements[num]);
}
Vquery.prototype.index=function(){
    var elems=this.elements[0].parentNode.children
    for(var i=0;i<elems.length;i++){
        if(elems[i]==this.elements[0]){
            return i;
        }
    }
}
//获取所有的兄弟节点 siblings
Vquery.prototype.find=function(sel){
    var arr=[];
    if(sel.charAt(0)=='.'){
        for(var i=0;i<this.elements.length;i++){
            arr=arr.concat(getByClass(this.elements[i],sel.substring(1)));
        }
    }else{
        for(var i=0;i<this.elements.length;i++){
            arr=arr.concat(toArray((this.elements[i].getElementsByTagName('li'))));
        }
    }
    return $(arr);
}

function $(vArg){
    return new Vquery(vArg);
}

凡尘丶
112 声望0 粉丝

这个人很懒