详解用原生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 相关文章推荐
jquery下checked取值问题的解决方法
Aug 09 Javascript
jQuery 遍历- 关于closest() 的方法介绍以及与parents()的方法区别分析
Apr 26 Javascript
jQuery实现菜单感应鼠标滑动动画效果的方法
Feb 28 Javascript
Jquery on绑定的事件 触发多次实例代码
Dec 08 Javascript
用angular实现多选按钮的全选与反选实例代码
May 23 Javascript
Node.js中多进程模块Cluster的介绍与使用
May 27 Javascript
详解RequireJs官方使用教程
Oct 31 Javascript
详解jQuery中的isPlainObject()使用方法
Feb 27 jQuery
Koa项目搭建过程详细记录
Apr 12 Javascript
bootstrap 日期控件 datepicker被弹出框dialog覆盖的解决办法
Jul 09 Javascript
初学vue出现空格警告的原因及其解决方案
Oct 31 Javascript
JS模拟实现京东快递单号查询
Nov 30 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编程网上资源导航
2006/10/09 PHP
用PHP查询搜索引擎排名位置的代码
2010/01/05 PHP
Android App中DrawerLayout抽屉效果的菜单编写实例
2016/03/21 PHP
PHP实现的随机IP函数【国内IP段】
2016/07/20 PHP
PHP基于双向链表与排序操作实现的会员排名功能示例
2017/12/26 PHP
laravel 错误处理,接口错误返回json代码
2019/10/25 PHP
window.print打印指定div实例代码
2013/12/13 Javascript
使用postMesssage()实现跨域iframe页面间的信息传递方法
2016/03/29 Javascript
jQuery图片轮播插件——前端开发必看
2016/05/31 Javascript
从0开始学Vue
2016/10/27 Javascript
JavaScript中匿名函数的递归调用
2017/01/22 Javascript
微信小程序 使用腾讯地图SDK详解及实现步骤
2017/02/28 Javascript
WebSocket实现简单客服聊天系统
2017/05/12 Javascript
JavaScript监听手机物理返回键的两种解决方法
2017/08/14 Javascript
vue 中的keep-alive实例代码
2018/07/20 Javascript
详解Angular6学习笔记之主从组件
2018/09/05 Javascript
vue实现可视化可拖放的自定义表单的示例代码
2019/03/20 Javascript
js微信分享接口调用详解
2019/07/23 Javascript
vuex存储复杂参数(如对象数组等)刷新数据丢失的解决方法
2019/11/05 Javascript
Python使用xlwt模块操作Excel的方法详解
2018/03/27 Python
详解Django模版中加载静态文件配置方法
2019/07/21 Python
正则给header的冒号两边参数添加单引号(Python请求用)
2019/08/09 Python
python学习笔记之多进程
2020/08/06 Python
Python join()函数原理及使用方法
2020/11/14 Python
python Matplotlib基础--如何添加文本和标注
2021/01/26 Python
HTML5 WebSocket实现点对点聊天的示例代码
2018/01/31 HTML / CSS
BIFFI美国站:意大利BIFFI BOUTIQUES豪华多品牌时装零售公司
2020/02/11 全球购物
英国奢侈品牌时尚购物平台:Farfetch(支持中文)
2020/02/18 全球购物
C,C++的几个面试题小集
2013/07/13 面试题
村班子对照检查材料
2014/08/18 职场文书
2014年高中教师工作总结
2014/12/19 职场文书
2015年小学重阳节活动总结
2015/07/29 职场文书
大队委员竞选演讲稿
2015/11/20 职场文书
导游词之台湾安平古堡
2019/12/25 职场文书
读《工匠精神》有感:热爱工作,精益求精
2019/12/28 职场文书
聊聊Lombok中的@Builder注解使用教程
2021/11/17 Java/Android