详解用原生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 相关文章推荐
juqery 学习之五 文档处理 包裹、替换、删除、复制
Feb 11 Javascript
jquery插件制作 提示框插件实现代码
Aug 17 Javascript
JS弹出窗口代码大全(详细整理)
Dec 21 Javascript
Javascript玩转继承(一)
May 08 Javascript
jQuery中get()方法用法实例
Dec 27 Javascript
如何用js 实现依赖注入的思想,后端框架思想搬到前端来
Aug 03 Javascript
深入解析Javascript闭包的功能及实现方法
Jul 10 Javascript
详解Js模板引擎(TrimPath)
Nov 22 Javascript
微信禁止下拉查看URL的处理方法
Sep 28 Javascript
Typescript的三种运行方式(小结)
Sep 18 Javascript
javascript实现视频弹幕效果(两个版本)
Nov 28 Javascript
vue3.0+vue-router+element-plus初实践
Dec 02 Vue.js
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
Yii2增加验证码步骤详解
2016/04/25 PHP
浅谈PHP中静态方法和非静态方法的相互调用
2016/10/04 PHP
PHP编程快速实现数组去重的方法详解
2017/07/22 PHP
jquery ready函数源代码研究
2009/12/06 Javascript
jquery 操作表格实现代码(多种操作打包)
2011/03/20 Javascript
jquery多选项卡效果实例代码(附效果图)
2013/03/23 Javascript
js返回上一页并刷新的多种实现方法
2014/02/26 Javascript
jquery关于事件冒泡和事件委托的技巧及阻止与允许事件冒泡的三种实现方法
2015/11/27 Javascript
jQuery绑定事件的几种实现方式
2016/05/09 Javascript
JavaScript实现url参数转成json形式
2016/09/25 Javascript
jQuery实现的checkbox级联选择下拉菜单效果示例
2016/12/26 Javascript
jquery实现弹窗功能(窗口居中显示)
2017/02/27 Javascript
js实现鼠标跟随运动效果
2020/08/02 Javascript
layui复选框的全选与取消实现方法
2019/09/02 Javascript
vue实现页面切换滑动效果
2020/06/29 Javascript
Vue项目前后端联调(使用proxyTable实现跨域方式)
2020/07/18 Javascript
python抓取某汽车网数据解析html存入excel示例
2013/12/04 Python
从零学Python之入门(五)缩进和选择
2014/05/27 Python
零基础写python爬虫之打包生成exe文件
2014/11/06 Python
python实现下载指定网址所有图片的方法
2015/08/08 Python
Python处理文本文件中控制字符的方法
2017/02/07 Python
详谈python read readline readlines的区别
2017/09/22 Python
Python数据结构与算法之图的基本实现及迭代器实例详解
2017/12/12 Python
python处理excel绘制雷达图
2019/10/18 Python
python实现opencv+scoket网络实时图传
2020/03/20 Python
如何开发一款堪比APP的微信小程序(腾讯内部团队分享)
2016/12/22 HTML / CSS
Stella McCartney官网:成衣、包袋、香水、内衣、童装及Adidas系列
2018/12/20 全球购物
意大利火车票和铁路通行证专家:ItaliaRail
2019/01/22 全球购物
党员承诺书范文
2014/05/19 职场文书
2015年党员岗位承诺书
2015/04/27 职场文书
2015年学生资助工作总结
2015/05/25 职场文书
医德医风学习心得体会
2016/01/25 职场文书
创业开店,这样方式更合理
2019/08/26 职场文书
分布式锁为什么要选择Zookeeper而不是Redis?看完这篇你就明白了
2021/05/21 Redis
深入解析Apache Hudi内核文件标记机制
2022/03/31 Servers
Windows Server 2012 R2服务器安装与配置的完整步骤
2022/07/15 Servers