详解用原生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 源码分析笔记(5) jQuery.support
Jun 19 Javascript
Javascript变量函数浅析
Sep 02 Javascript
JS操作HTML自定义属性的方法
Feb 10 Javascript
jquery实现用户信息修改验证输入方法汇总
Jul 18 Javascript
javascript实现类似于新浪微博搜索框弹出效果的方法
Jul 27 Javascript
jQuery移动端日期(datedropper)和时间(timedropper)选择器附源码下载
Apr 19 Javascript
jquery注册文本框获取焦点清空,失去焦点赋值的简单实例
Sep 08 Javascript
jQuery ui autocomplete选择列表被Bootstrap模态窗遮挡的完美解决方法
Sep 23 Javascript
Angular 2.x学习教程之结构指令详解
May 25 Javascript
Vue混入mixins滚动触底的方法
Nov 22 Javascript
Vue实现 点击显示再点击隐藏效果(点击页面空白区域也隐藏效果)
Jan 16 Javascript
vue 二维码长按保存和复制内容操作
Sep 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初学者(入门学习经验谈)
2010/10/12 PHP
PHP数组实例总结与说明
2011/08/23 PHP
php把session写入数据库示例
2014/02/26 PHP
php判断GIF图片是否为动画的方法
2020/09/04 PHP
PHP中调用SVN命令更新网站方法
2015/01/07 PHP
Nginx+php配置文件及原理解析
2020/12/09 PHP
js checkbox(复选框) 使用集锦
2009/04/28 Javascript
jQuery动态添加 input type=file的实现代码
2012/06/14 Javascript
css结合js制作下拉菜单示例代码
2014/02/27 Javascript
node.js中的path.delimiter方法使用说明
2014/12/09 Javascript
使用npm发布Node.JS程序包教程
2015/03/02 Javascript
简述AngularJS相关的一些编程思想
2015/06/23 Javascript
XML、HTML、CSS与JS的区别整理
2016/02/18 Javascript
浅谈js中的延迟执行和定时执行
2016/05/31 Javascript
JS+CSS3实现超炫的散列画廊特效
2016/07/16 Javascript
详解webpack 多入口配置
2017/06/16 Javascript
基于JavaScript实现弹幕特效
2020/08/27 Javascript
基于Vue实现支持按周切换的日历
2020/09/24 Javascript
搭建element-ui的Vue前端工程操作实例
2018/02/23 Javascript
解决qrcode.js生成二维码时必须定义一个空div的问题
2020/07/09 Javascript
[00:32]2018DOTA2亚洲邀请赛出场——LGD
2018/04/04 DOTA
详解python3百度指数抓取实例
2016/12/12 Python
对numpy中array和asarray的区别详解
2018/04/17 Python
使用python画个小猪佩奇的示例代码
2018/06/06 Python
Python代码块批量添加Tab缩进的方法
2018/06/25 Python
Python判断以什么结尾以什么开头的实例
2018/10/27 Python
PyQT实现菜单中的复制,全选和清空的功能的方法
2019/06/17 Python
Manjaro、pip、conda更换国内源的方法
2020/11/17 Python
Mavi牛仔裤美国官网:土耳其著名牛仔品牌
2016/09/24 全球购物
西班牙香水和化妆品连锁店:Druni
2019/05/05 全球购物
美国家居装饰店:Z Gallerie
2020/12/28 全球购物
印度电子产品购物网站:Vijay Sales
2021/02/16 全球购物
计算机本科生自荐信
2013/10/15 职场文书
2014优秀党员事迹材料
2014/08/14 职场文书
事业单位财务人员岗位职责
2015/04/14 职场文书
全陪导游词开场白
2015/05/29 职场文书