自己动手构造API理解jQuery
2019-04-10 本文已影响0人
kiterumer
封装两个函数,一个用来获取某个节点的兄弟姐妹,一个用来给元素添加类
现在有一个无序列表。循序渐进,体会jQuery设计思想。
<!-- ul>li[id=item$]{选项$}*5 -->
<ul>
<li id="item1">选项1</li>
<li id="item2">选项2</li>
<li id="item3">选项3</li>
<li id="item4">选项4</li>
<li id="item5">选项5</li>
</ul>
封装两个函数
封装一个获取兄弟姐妹函数getSiblings
function getSiblings(node){ /* API */
var allChildren = node.parentNode.children ;
// 伪数组
var array = {
length: 0
}
// 获取node的兄弟姐妹
for (let i = 0; i < allChildren.length; i++){
if(allChildren[i] !== node){
// array是伪数组,没有push方法
array[array.length] = allChildren[i];
array.length += 1;
}
}
return array
}
封装添加类函数addClass
//添加的类用数组表示
function addClass(node,classes){
classes.forEach(value => {
node.classList.add(value)
});
}
命名空间
两个函数不能就这么随意的放着,赋予一个命名空间
// getSiblings,addClass作为yyydom对象的方法
window.yyydom = {}
yyydom.getSiblings = getSiblings
yyydom.addClass = addClass
yyydom.addClass(item2,['a','b'])
//这种调用方式并不好,我们希望将node节点放在前面
把node放在前面进行调用
有两种方法:
- 扩展 Node 接口,直接在 Node.prototype 上加函数
- 自己创建新的接口
1.篡改Node.prototype,添加函数
Node.prototype.getSiblings = function(){
var allChildren = this.parentNode.children ;
// 伪数组
var array = {
length: 0
}
// 获取node的兄弟姐妹
for (let i = 0; i < allChildren.length; i++){
if(allChildren[i] !== this){
// array是伪数组,没有push方法
array[array.length] = allChildren[i];
array.length += 1;
}
}
return array
}
Node.prototype.addClass2 = function(classes){
classes.forEach(value => {
this.classList.add(value)
});
}
// 用call显示this,call的第一个参数就是this
// item3.getSiblings()
// item3.getSiblings.call(item3) ,等价上
// item3.addClass(['q','w','e'])
// item3.addClass(item3,['q','w','e']) 等价上
但是,在Node原型上增加方法也不好,如果有多个人修改容易造成冲突。既然这样,不如自己创建一个新Node构造函数。自己动手,丰衣足食。
2.自己创建新的接口(无侵入)
window.Node2 = function(node){
return {
getSiblings:function(){
var allChildren = node.parentNode.children ;
// 伪数组
var array = {
length: 0
}
// 获取node的兄弟姐妹
for (let i = 0; i < allChildren.length; i++){
if(allChildren[i] !== node){
// array是伪数组,没有push方法
array[array.length] = allChildren[i];
array.length += 1;
}
}
return array
},
addClass:function(classes){
classes.forEach(value => {
node.classList.add(value)
});
}
}
}
var node2 = Node2(item3)
node2.getSiblings()
node2.addClass(['p','o'])
构造函数Node2返回一个新对象,这个对象有getSiblings和addClass两个方法,里面还是调用的原生API。似乎离目标越来越近了。
Node2是随意取的,改为jQuery,于是
var node2 = jQuery(item3)
node2.getSiblings()
再进一步,window.$ = jQuery,再省略window,于是就变成了
var node2 = $(item3)
node2.getSiblings()
是不是很熟悉呢?
选择器多样化
目前我们所创建的构造函数只能获取节点,如果是其他选择器呢,比如$('ul>li:nth-child(3)'),那么需要加一些判断
window.jQuery = function(nodeOrSelector){
//是否为字符串
if(typeof nodeOrSelector === 'string'){
//利用了原生的document.querySelector
node = document.querySelector(nodeOrSelector)
}else{
node = nodeOrSelector
}
return {
getSiblings:function(){
var allChildren = node.parentNode.children ;
// 伪数组
var array = {
length: 0
}
// 获取node的兄弟姐妹
for (let i = 0; i < allChildren.length; i++){
if(allChildren[i] !== node){
// array是伪数组,没有push方法
array[array.length] = allChildren[i];
array.length += 1;
}
}
return array
},
addClass:function(classes){
classes.forEach(value => {
node.classList.add(value)
});
}
}
}
//获取列表第五个元素
var node2 = jQuery('ul>li:nth-child(5)')
// 给我旧的对象,返回新的对象
node2.addClass(['red'])
那么要获取多个节点呢,这是里面就要用到document.querySelectorAll,而且部分逻辑也有变化
window.jQuery2 = function(nodeOrSelector){
let nodes //最后要返回的对象
if(typeof nodeOrSelector === 'string'){
nodes = document.querySelectorAll(nodeOrSelector) //伪数组
}else if(nodeOrSelector instanceof Node){
// 保证返回结果一致,都为伪数组
nodes = {
0: nodeOrSelector,
length: 1
}
}
//添加类
nodes.addClass = function(classes){
classes.forEach((value) => {
// 给nodes数组里每一项添加类
for (let i = 0;i < nodes.length; i++){
nodes[i].classList.add(value)
}
})
}
// 获取元素文本
nodes.getText = function(){
var texts = []
for(let i = 0;i < nodes.length;i++){
texts.push(nodes[i].textContent)
}
return texts
}
// 设置文本
nodes.setText = function(text){
for(let i=0;i<nodes.length;i++){
nodes[i].textContent = text
}
}
// 两者合并,这种在jQuery中非常常见
nodes.text = function(text){
if(text === undefined){
var texts = []
for(let i = 0;i < nodes.length;i++){
texts.push(nodes[i].textContent)
}
return texts
}else{
for(let i=0;i<nodes.length;i++){
nodes[i].textContent = text
}
}
}
return nodes
}
var node3 = jQuery2('ul>li')
node3.addClass(['red'])
node3.text('yyy')
//这大概就是最终体了