从封装函数到实现简易版自用jQuery (一)
温馨提示
本文阅读对象: 对 JavaScript 有一定的了解,如果你没有学过或者忘记 JavaScript 某些操作,请看 阮一峰 JavaScript 教程 。
导语
DOM 有许多 API ,但是有些 API 太难用了。
比如,想获取某 element 的所有兄弟该怎么办?
再比如,我想给某 element 加多个 class ,你说有 node.classList.add( )啊。那我想加 100 个怎么办?总不能写 100 遍吧,so 自己封装个 API 。
向大佬学习
自己写一个毫无头绪啊,那jQuery是怎么做的,我们模仿一下嘛。 在jQuery这个库里,有许多函数,比如addClass( ),.css( ),.data( )等等。也就是说,jQuery是一个大仓库,仓库里有很多工具,我们需要什么的时候就用什么工具。 现在我们要做的就是,自己生产很多工具,然后建立自己的仓库,我们想用什么就从仓库里拿出来什么。
1. 生产工具
假设我们现在需要两个工具,分别是获取兄弟 element 和 添加多个 class 。
实现功能
1. 获取兄弟 element
操作步骤:
- 在 html 中有一个 ul 标签,在 ul 中有 5 个 li 。
<ul><li id="item1">item1</li><li id="item2">item2</li><li id="item3">item3</li><li id="item4">item4</li><li id="item5">item5</li>
</ul>
复制代码
获取 id 为 item3 的兄弟元素。
首先定义一个 allChildren 变量来存储 item3 的父节点所有的子元素。 获取子元素 DOM 有两个 API ,node.parent.children 和 node.parent.childNodes 。应该选择哪个呢?parent.childNodes:获取节点,不同浏览器表现不同;
IE:只获取元素节点;
非IE:获取元素节点与文本节点;
parent.children:获取元素节点,浏览器表现相同。
因此建议使用children。
var allChildren = item3.parentNode.children;
复制代码
上图是在某博客页面做的测试,可以看到使用 parent.childNodes 获取到了 text 节点。
- 定义一个空数组来存兄弟元素,此时数组长度为0。
var arr = {length:0};
复制代码
- 遍历所有的孩子节点,如果不是 item3 ,那么就存到 arr 数组中。
for(var i = 0;i < allChildren.length;i++){if(allChildren[i] !== item3){arr[arr.length] = allChildren[i];arr.length++;}
}
复制代码
小技巧:使用 arr[arr.length] = allChildren[i];
使得数组下标依次存储 item 元素。
完整代码:
<ul><li id="item1">item1</li><li id="item2">item2</li><li id="item3">item3</li><li id="item4">item4</li><li id="item5">item5</li>
</ul>var allChildren = item3.parentNode.children;
var arr = {length:0};for(var i = 0;i < allChildren.length;i++){if(allChildren[i] !== item3){arr[arr.length] = allChildren[i];arr.length++;}
}console.log(arr);
复制代码
运行结果:
注意: 这个 arr 数组是一个伪数组,它的原型链直接指向了 Object 并没有指向 Array.prototype ,只有原型链中指向 Array.prototype 的数组才是真正的数组。如果原型链中不包含 Array.prototype 是没有数组.push( )等方法的。
封装成函数
- 包装一下,加个 function ,同时起个名字,方便调用。
function getSiblings(){var allChildren = item3.parentNode.children;var arr = {length:0};for(var i = 0;i < allChildren.length;i++){if(allChildren[i] !== item3){arr[arr.length] = allChildren[i];arr.length++;}}console.log(arr);
}
复制代码
- 我们给这个函数一个返回值,返回值呢就是这个数组,把
console.log(arr)
改成return arr
。 - 此时我们发现,item3 这个 id 是函数外面的值,是在调用函数的时候传参才能获取到,所以给我们的函数加一个参数,同时把 item3 改成参数 node 。
function getSiblings(node){var allChildren = node.parentNode.children;var arr = {length:0};for(var i = 0;i < allChildren.length;i++){if(allChildren[i] !== node){arr[arr.length] = allChildren[i];arr.length++;}}return arr;
}
console.log(getSiblings(item3));
复制代码
2. 添加多个 class
操作流程同上,这里只给出代码和必要的解释。
实现功能:
<ul><li id="item1">item1</li><li id="item2">item2</li><li id="item3">item3</li><li id="item4">item4</li><li id="item5">item5</li>
</ul>var classes = {'a':true,'b':false,'c':true}
for(var key in classes){var value = classes[key];if(value){item3.classList.add(key);}else{item3.classList.remove(key);}
}
复制代码
利用 hash 存储是否添加的 class ,如果为 true ,添加给 item3 ,如果为 false 移除该 class 。
封装成函数:
function addClasses(node,classes){for(var key in classes){var value = classes[key];if(value){node.classList.add(key);}else{node.classList.remove(key);}}
}
addClasses(item3,{'a':true,'b':false,'c':true});
// 传入参数包括节点和要添加的 class
复制代码
优化整理:
function addClasses(node,classes){for(var key in classes){var value = classes[key];var methodName = value ? 'add':'remove';node.classList[methodName](key);}
}
addClasses(item3,{'a':true,'b':false,'c':true});
复制代码
这里要说明一下,我们根据传来的 key 值为 true 或者 false 来决定是否添加这个 class。node.classList.add(key);
和 node.classList.remove(key);
是属于一类代码,区别就是调用的是 add 方法还是 remove 方法,那么存在优化的可能性。
定义一个 methodName 变量存储 value 值,也就是遍历过程中每次的 true 或者 false。让 node.classList[methodName](key)
每次直接调用 methodName 即可完成操作。
备注:如果你只了解对象 obj.add( )
这种调用,不理解关于obj[]( )
调用方法,情回顾 JavaScript 基础。
运行结果:
2. 建造仓库放工具
现在我们的工具都造好了,就要给工具造房子了。
jQuery 工具的房子叫 jQuery ,那我们也取一个属于自己的名字,比如我的叫 simpleTools 。
window.simpleTools = function(){ return{getSiblings:function(){},addClass:function(){}};
};
复制代码
window.simpleTools 是我们的大房子,这是一个函数大房子,房子里面现在住着 getSiblings 对象和 addClass 对象,这就好比是放工具的架子。接下来,我们把上面封装好的函数放在对应的架子上。
window.simpleTools = function(node){return{getSiblings:function(){var allChildren = node.parentNode.children;var arr = {length:0};for(var i = 0;i < allChildren.length;i++){if(allChildren[i] !== node){arr[arr.length] = allChildren[i];arr.length++;}}return arr;},addClass:function(classes){for(var key in classes){var value = classes[key];var methodName = value ? 'add':'remove';node.classList[methodName](key);}}};
};
复制代码
传给 function 的 node 就好像是我们的仓库小管家,一旦他被通知要工作了(有参数传过来),那他就去告诉每一个工具,做好准备随时准备开工。
现在加几句测试语句,看看运行结果。
var nodeTest = simpleTools(item3);
console.log(nodeTest.getSiblings());
nodeTest.addClass({'a':true,'b':false,'c':true});
复制代码
运行结果:
很好,和之前的运行结果相同,说明我们并没有因为放到仓库里而产生bug。
小结
到这为止,你已经学会了写一个自己的仓库。我们再来回顾一下流程吧。
生产工具:
- 实现功能
- 封装成函数
- 适当优化
建造仓库放工具:
- 建一个仓库
- 放入工具
快动手实现一个属于自己的仓库吧, 代码的后续优化请看 从封装函数到实现简易版自用jQuery (二)。
从封装函数到实现简易版自用jQuery (一)相关推荐
- 字符串拼接函数的实现(简易版)
字符串操作函数的实现----字符串拼接 1 #include <stdio.h> 2 3 // 求字符串长度 4 int getLength(char *str) { 5 6 int le ...
- 5 拦截器拦截请求路由_手写简易版axios拦截器,实现微信小程序wx.request的封装与拦截...
前言: axios是一个功能强大的网络请求库,其中拦截器又是axios的精髓.在小程序的开发或者需要手动实现ajax的时候,没有实现对请求的拦截,开发的时候非常不方便,因此手写一个简易版的axios拦 ...
- 从零手写实现简易版MMKV(一)
概述 MMKV是支持多平台的高性能键值对持久化存储组件,其核心原理是利用mmap内存映射文件,关于它的详细介绍和更多原理参看MMKV开源git地址. 从零开始手写(其实是抄写-.-!)简易版MMKV( ...
- C与C++游戏项目练习9:接金币游戏简易版
## C与C++游戏项目练习9:接金币游戏简易版 还是只能在devC++里面运行,不要用VS!!! 还是只能在devC++里面运行,不要用VS!!! 还是只能在devC++里面运行,不要用VS!!!* ...
- 利用python实现简易版的贪吃蛇游戏(面向python小白)
前言 这篇文章主要给大家介绍了关于如何利用python实现简易版的贪吃蛇游戏的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学 ...
- python实现简易版成绩管理系统_Python 实现简易版成绩管理系统!
上一次,公众号介绍了如何使用 Python 实现单链表,下面让我们一探单链表的简单应用:在命令行,实现简易版成绩管理系统. 这次的简易版成绩管理系统,主要有六大功能:增加学生信息.删除学生信息.修改学 ...
- 肝一波 ~ 手写一个简易版的Mybatis,带你深入领略它的魅力!
零.准备工作 <dependencies><dependency><groupId>mysql</groupId><artifactId>m ...
- python简易版成绩管理系统_Python 实现简易版成绩管理系统
上一次,公众号介绍了如何使用 Python 实现单链表,下面让我们一探单链表的简单应用:在命令行,实现简易版成绩管理系统. 这次的简易版成绩管理系统,主要有六大功能:增加学生信息.删除学生信息.修改学 ...
- js计算器代码加减乘除_如何用jQuery做一个简易版计算器
经过几个小时地敲敲打打,终于把这一部分的代码完成了. 这类问题的难点不在于布局,而是如何恰当地使用jQuery达成计算.交互的目的,比如储存.显示数值,数据类型的转换等. 在听老师讲课之前的我,思路是 ...
最新文章
- HTML的相关路径与绝对路径的问题---通过网络搜索整理
- 前端学习(2924):watch的用法
- docker web程序本地化_Docker-01-Docker介绍
- 动态生成类_springboot动态生成类属性
- 【clickhouse】clickhouse 表引擎之 Merge
- shell 构建脚本基础
- 苹果手机上网很慢_手机信号满格,但上网速度却很慢?来听听通信专家怎么说的...
- python 安装whl文件
- 【算法随记二】线卷积积分及其在图像增强和特效方面的应用(一)
- GO分析和KEGG分析都是啥?
- 电脑通过 adb 控制安卓手机(1台或多台)自动加微信
- 比较Cint() , int() , fix() ,round()的区别
- 使用BeanEditForm来创建用户表单
- Java实现发电子邮件,快去给你好基友发一封邮件~
- 十八、商城 - 规格管理-模板管理(6)
- MIPS指令集和汇编
- SQL Server Management Studio(SSMS)无法连接到服务器,及解决方案
- Verilog通过锁相环实现倍频,分频,相位偏移
- 全连接层介绍以及简单实现
- 单片机与STM32问题及解决
热门文章
- sudo执行脚本找不到环境变量解决方法
- [.net 面向对象程序设计进阶] (18) 多线程(Multithreading)(三) 利用多线程提高程序性能(下)...
- ExtJs自学教程(1):一切从API開始
- 领悟Web设计模式(转)
- iOS开发笔记(十七):持久化方案之 NSUserDefaults
- 哪种云存储服务最适合你?
- 极客Web前端开发资源大荟萃
- [Share]10 Free EBooks for Web Designers
- 计算路由汇总的方法(CIDR)
- 【译】需要学习的是编程,而不是编程语言