详解用原生JavaScript实现jQuery的某些简单功能


Posted in Javascript onDecember 19, 2016

大致介绍

学习了妙味,用原生的JavaScript实现jQuery中的某些部分功能

定义自己的函数库lQuery

$()选择器的实现

jQuery是面向对象的,所以自己编写的也要是面向对象的,看看基本的结构

// 定义lQuery对象
function lQuery(lArg){
}
function lQ(lArg){
 return new lQuery(lArg);
}
// css()方法
lQuery.prototype.css = function(){};
// html()方法
lQuery.prototype.html = function(){};

先来仿写jQuery中的$(函数)的方法

// 定义lQuery对象
function lQuery(lArg){
 // 用typeof判断参数的类型是 function 、
 switch( typeof lArg){
 case 'function':
  // 如果采用这种写法,给lQ绑定相同的函数,但是只会执行一次
  // window.onload = lArg;
  // break;
 }
}

如果写出这样的函数就会出现问题

lQ(function(){
  alert(1);
 });
 lQ(function(){
  alert(2);
 });

这样就只会弹出'2',但是在jQuery中都会弹出,所以上面的方法不对,我们采用事件绑定的形式来解决这个问题

// 绑定事件函数
function lQbind(obj,eventName,fn){
 // 标准浏览器
 if(obj.addEventListener){
 obj.addEventListener(eventName,fn,false);
 }else{
 // IE浏览器
 obj.attachEvent('on'+eventName,fn);
 }
}

可以使用这样调用

switch( typeof lArg){
 case 'function':
  // 如果采用这种写法,给lQ绑定相同的函数,但是只会执行一次
  // window.onload = lArg;
  // break;
  lQbind(window,'load',lArg);
  break;
 }

仿写jQuery中的$('.div')、$('#div')、$('div')三种方法

这三种方法的区别是第一个字符的不同,所以我们可以根据第一个字符的不同来进行区别对待

先来仿写$('.div')

// '.div'
  case '.':
  this.elements = getClass(document,lArg.substring(1));
   break;

由于getElementsByClassName()是HTML5里的方法,像IE8以下不兼容所以我们自己写了一个简单的getClass方法

// 获取class属性
function getClass(obj,name){
 var arr = [];
 var elems = obj.getElementsByTagName('*');
 for(var i=0;i<elems.length;i++){
 if(elems[i].className == name){
  arr.push(elems[i]);
 }
 }
 return arr;
}

仿写$('#div')

case '#':
   this.elements.push(document.getElementById(lArg.substring(1)));
   break;
   // '.div'
  case '.':

仿写$('div')

default:
 // getElementsByTagName返回的是一个类数组NodeList,为了防止以后出现麻烦,要把他转为一个
 // 数组
 this.elements = toArray(document.getElementsByTagName(lArg));
 break;

由于getElementsByTagName返回的是一个类数组NodeList,为了防止以后出现麻烦,要把他转为一个数组,自定义了一个toArray方法

// 将一个类数组转为真正的数组
function toArray(lickArr){
 var arr = [];
 for(var i=0;i<lickArr.length;i++){
 arr.push(lickArr[i]);
 }
 return arr;
}

仿写$(对象)的方法

      // window  document
      case 'object':
          this.elements.push(lArg);
          break;

html()的实现

html()方法分为有参和无参

// html()方法
lQuery.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;
};

on()方法的实现

利用前面实现的绑定函数可以很容易的实现

 lQuery.prototype.on = function(eventName,fn){
     for(var i=0;i<this.elements.length;i++){
         lQbind(this.elements[i],eventName,fn);
     }
 }

click()和mouseover()方法的实现

利用on()方法可以容易的实现

// click()方法
lQuery.prototype.click = function(fn){
 this.on('click',fn);
 return this;
}
// mouseover()方法
lQuery.prototype.mouseover = function(fn){
 this.on('mouseover',fn);
 return this;
}

hide()和show()方法的实现

// hide()方法
lQuery.prototype.hide = function(){
 for(var i=0;i<this.elements.length;i++){
 this.elements[i].style.display = 'none';
 }
 return this;
}
// show()方法
lQuery.prototype.show = function(){
 for(var i=0;i<this.elements.length;i++){
 this.elements[i].style.display = 'block';
 }
 return this;
}

hover()方法的实现

// hover()方法
 lQuery.prototype.hover = function(fnover,fnout){
 this.on('mouseover',fnover);
 this.on('mouseout',fnout);
 return this;
 }

css()方法的实现

实现$('div').css('width')和$('div').css('width','200px')

lQuery.prototype.css = function(attr,value){
 if(arguments.length == 2){
 for(var i=0;i<this.elements.length;i++){
  this.elements[i].attr = value;
 }
 }
 if(arguments.length == 1){
 return getStyle(this.elements[0],attr);
 }
}

定义了getStyle()方法是为了能找到行内样式以外的样式

// 获取属性
function getStyle(obj,attr){
 if(obj.currentStyle[attr]){
 obj.currentStyle[attr];
 }else{
 obj.getComputedStyle(obj,false)[attr];
 }
}

attr()方法的实现

用了和css()不同的方法

// attr()方法
lquery.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;
};

eq()方法的实现

 实现$('div').eq(1)

 由于eq()方法返回的对象要操作许多lQuery的方法,所以返回的对象必须是lQuery对象

lQuery.prototype.eq = function(num){
  return lQ(this.elements[num]);
 };

index()方法的实现

实现$('div').index() 返回这个元素在同辈元素中的位置

lQuery.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;
  }
 }
 };

阻止默认事件和阻止事件冒泡

在jQuery中 return false 是阻止默认事件和事件冒泡,所以我们要对lQbind函数进行修改,通过判断绑定的函数的返回值是否为false来判断是否要进行阻止默认事件和阻止事件冒泡

function lQbind(obj,events,fn){
  if(obj.addEventListener){
  obj.addEventListener(events,function(ev){ 
   if( fn() == false ){
   ev.preventDefault();
   ev.cancelBubble = true;
   }
  },false);
  }
  else{
  obj.attachEvent('on'+events,function(){
   if( fn() == false ){
   window.event.cancelBubble = true;
   return false;
   }
  });
  }
 }

find()方法的实现

仿写$('div').find('.box')和$('div').find('#box')方法

这里涉及到通过判断find()参数第一个字符的方法来进行不同的操作和$()方法差不多,在循环时要使用concat()方法来连接数组,最后返回一个lQuery对象

lQuery.prototype.find = function(sel){
  var arr = [];
  if( sel.charAt(0) == '.' ){ 
  for(var i=0;i<this.elements.length;i++){ 
   arr = arr.concat(getClass( this.elements[i] , sel.substring(1) ));
  }
  }
  else{ 
  for(var i=0;i<this.elements.length;i++){ 
   arr = arr.concat(toArray(this.elements[i].getElementsByTagName(sel)));
  }
  }
  return lQ(arr); 
 };

以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,同时也希望多多支持三水点靠木!

Javascript 相关文章推荐
菜单效果
Oct 14 Javascript
wordpress之js库集合研究介绍
Aug 17 Javascript
Jquery实现图片预加载与延时加载的方法
Dec 22 Javascript
javascript中createElement的两种创建方式
May 14 Javascript
原生js实现移动端瀑布流式代码示例
Dec 18 Javascript
jQuery实现的跨容器无缝拖动效果代码
Jun 21 Javascript
etmvc+jQuery EasyUI+combobox多值操作实现角色授权实例
Nov 09 Javascript
Vue2路由动画效果的实现代码
Jul 10 Javascript
babel的使用及安装配置教程
Feb 22 Javascript
详解vue中的父子传值双向绑定及数据更新问题
Jun 13 Javascript
基于vue-cli3+typescript的tsx开发模板搭建过程分享
Feb 28 Javascript
解决新建一个vue项目过程中遇到的问题
Oct 22 Javascript
Jquery Easyui对话框组件Dialog使用详解(14)
Dec 19 #Javascript
jQueryUI 拖放排序遇到滚动条时有可能无法执行排序的小bug及解决方案
Dec 19 #Javascript
jQuery Easyui datagrid editor为combobox时指定数据源实例
Dec 19 #Javascript
vue项目中做编辑功能传递数据时遇到问题的解决方法
Dec 19 #Javascript
jQuery Easyui datagrid行内实现【添加】、【编辑】、【上移】、【下移】
Dec 19 #Javascript
Jquery Easyui表单组件Form使用详解(30)
Dec 19 #Javascript
基于JavaScript实现自动更新倒计时效果
Dec 19 #Javascript
You might like
PHP调用Linux命令权限不足问题解决方法
2015/02/07 PHP
php语言的7种基本的排序方法
2020/12/28 PHP
基于Laravel实现的用户动态模块开发
2017/09/21 PHP
jquery选择器(常用选择器说明)
2010/09/28 Javascript
jQuery代码优化 事件委托篇
2011/11/01 Javascript
关于jQuery参考实例2.0 用jQuery选择元素
2013/04/07 Javascript
js控制的遮罩层实例介绍
2013/05/29 Javascript
js传参数受特殊字符影响错误的解决方法
2013/10/21 Javascript
javascript面向对象之定义成员方法实例分析
2015/01/13 Javascript
node.js入门实例helloworld详解
2015/12/23 Javascript
jQuery选择器及jquery案例详解(必看)
2016/05/20 Javascript
JavaScript递归算法生成树形菜单
2017/08/15 Javascript
View.post() 不靠谱的地方你知道多少
2017/08/29 Javascript
vue2.0 better-scroll 实现移动端滑动的示例代码
2018/01/25 Javascript
JS获取子节点、父节点和兄弟节点的方法实例总结
2018/07/06 Javascript
vue-router的使用方法及含参数的配置方法
2018/11/13 Javascript
JS字典Dictionary类定义与用法示例
2019/02/01 Javascript
微信小程序如何刷新当前界面的实现方法
2019/06/07 Javascript
Vue实现简单的拖拽效果
2020/08/25 Javascript
vue 实现基础组件的自动化全局注册
2020/12/25 Vue.js
[40:12]Liquid vs Chaos 2019国际邀请赛小组赛 BO2 第二场 8.15
2019/08/16 DOTA
[01:46]2020完美世界全国高校联赛秋季赛报名开启
2020/10/15 DOTA
Python解析json文件相关知识学习
2016/03/01 Python
Python中的相关分析correlation analysis的实现
2019/08/29 Python
Pandas-Cookbook 时间戳处理方式
2019/12/07 Python
用纯css3实现的图片放大镜特效效果非常不错
2014/09/02 HTML / CSS
10种CSS3实现的loading动画,挑一个走吧?
2020/11/16 HTML / CSS
Toppik顶丰增发纤维官网:解决头发稀疏
2017/12/30 全球购物
英语专业毕业个人求职自荐信
2013/09/21 职场文书
信息技术专业个人自我评价
2013/12/11 职场文书
《秋姑娘的信》教学反思
2014/02/28 职场文书
村主任群众路线教育实践活动个人对照检查材料思想汇报
2014/10/01 职场文书
乡镇三严三实学习心得体会
2014/10/13 职场文书
基层干部个人对照检查及整改措施
2014/10/28 职场文书
党的群众路线教育实践活动心得体会(医院)
2014/11/03 职场文书
创业计划书之水果店
2019/07/18 职场文书