详解用原生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 相关文章推荐
javascript学习笔记(二十) 获得和设置元素的特性(属性)
Jun 20 Javascript
『jQuery』.html(),.text()和.val()的概述及使用
Apr 22 Javascript
基于Jquery实现焦点图淡出淡入效果
Nov 30 Javascript
BootStrap Table前台和后台分页对JSON格式的要求
Jun 28 Javascript
jquery.validate.js 多个相同name的处理方式
Jul 10 jQuery
在nginx上部署vue项目(history模式)的方法
Dec 28 Javascript
简单理解Vue中的nextTick方法
Jan 30 Javascript
用vue-cli开发vue时的代理设置方法
Sep 20 Javascript
移动端底部导航固定配合vue-router实现组件切换功能
Jun 13 Javascript
微信小程序开发之map地图组件定位并手动修改位置偏差
Aug 17 Javascript
javascript实现多边形碰撞检测
Oct 24 Javascript
JS前端使用Canvas快速实现手势解锁特效
Sep 23 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
php5中类的学习
2008/03/28 PHP
accesskey 提交
2006/06/26 Javascript
基于jquery的内容循环滚动小模块(仿新浪微博未登录首页滚动微博显示)
2011/03/28 Javascript
基于jQuery的合并表格中相同文本的相邻单元格的代码
2011/04/06 Javascript
jQuery UI Autocomplete 1.8.16 中文输入修正代码
2012/04/16 Javascript
自己动手实现jQuery Callbacks完整功能代码详解
2013/11/25 Javascript
jquery实现鼠标拖动图片效果示例代码
2014/01/09 Javascript
判断某个字符在一个字符串中是否存在的js代码
2014/02/28 Javascript
jQuery操作元素css样式的三种方法
2014/06/04 Javascript
JS实现倒计时和文字滚动的效果实例
2014/10/29 Javascript
jquery实现的用户注册表单提示操作效果代码分享
2015/08/28 Javascript
js实现随机点名系统(实例讲解)
2017/10/18 Javascript
浅析vue深复制
2018/01/29 Javascript
Vue 中mixin 的用法详解
2018/04/23 Javascript
在小程序中使用腾讯视频插件播放教程视频的方法
2018/07/10 Javascript
Vue.js 通过jQuery ajax获取数据实现更新后重新渲染页面的方法
2018/08/09 jQuery
[04:29]【TI9采访】OG.N0tail在胜者组决赛后接受采访
2019/08/25 DOTA
Django应用程序中如何发送电子邮件详解
2017/02/04 Python
Python实现选择排序
2017/06/04 Python
Python 比较两个数组的元素的异同方法
2017/08/17 Python
对Python3 goto 语句的使用方法详解
2019/02/16 Python
Python hexstring-list-str之间的转换方法
2019/06/12 Python
Python获取当前脚本文件夹(Script)的绝对路径方法代码
2019/08/27 Python
pytorch 使用加载训练好的模型做inference
2020/02/20 Python
matlab中imadjust函数的作用及应用举例
2020/02/27 Python
Python 实现敏感目录扫描的示例代码
2020/05/21 Python
使用opencv识别图像红色区域,并输出红色区域中心点坐标
2020/06/02 Python
利用CSS3实现文字折纸效果实例代码
2018/07/10 HTML / CSS
小饰品店的创业计划书范文
2013/12/28 职场文书
反腐倡廉演讲稿
2014/05/22 职场文书
2015年学校财务工作总结
2015/05/19 职场文书
公司管理制度范本
2015/08/03 职场文书
体育教师研修感悟
2015/11/18 职场文书
2019年教师节祝福语精选,给老师送上真诚的祝福
2019/09/09 职场文书
mybatis源码解读之executor包语句处理功能
2022/02/15 Java/Android
解析探秘fescar分布式事务实现原理
2022/02/28 Java/Android