前言:在前端三大框架没有出现的时候,我们开发时候可能一般会使用到jQuery,它是一个高效、精简并且功能丰富的 JavaScript 工具库。它提供的 API 易于使用且兼容众多浏览器,这让诸如 HTML 文档遍历和操作、事件处理、动画和 Ajax 操作更加简单,例如常见的$('div').html()
、$('#div1').html('bbbbbb').css('background','green')
等等的操作是如何工作的呢,自己做了个简单的Vquery,分享下自己的见解及书写步骤
1、jquery中的顶级对象是$
,为了保持一致或更简单的书写,我也采用了$
作为函数名(当然也可以取任意自己定义的名称,如MyQuery等)
2、如上图所示,函数$
中返回一个new的对象,所以需要创建一个名为Vquery的构造函数,我们会给这个构造函数传递一个参数,并会对此参数做对应的处理,涉及到js中的关于原型的一些东西,Vquery.prototype.xxx=function(){},给构造函数的原型对象添加属性,也就是添加一个个的方法,如click,hide,show,html
等方法
3、当然也少不了一些基础的方法或者工具函数,例如获取元素class
,绑定事件的on
,获取最终样式等
上面的就是基本的过程以及部分示例代码,在Vquery构造函数中需要判断传递参数的类型,如我们常用的$(function(){})
或者$('div')
或者$('#div')
等都是有不同的处理方式
4、关于使用时候一些东西的补充,我们可能会这样使用jquery,$('#div').css('background')
也可能这样使用$('#div').css('background':'red')
,前者是获取元素样式,后者是设置元素样式,它背后的实现原理如下,通过判断参数个数确定是设置还是获取
5、说说链式操作实现的原理,jQuery中的每个挂载在原型对象下面的方法最后有return this,这样在执行$('xxx')
(最上面一张截图)的时候就执行了里面的new Vquery返回了本身。
6、创建html文件并测试结果如下
结语:这个只是基本的雏形,实际的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);
}
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。