类似jQuery

作者: CeaCrab | 来源:发表于2018-03-19 20:41 被阅读0次

jOuery实际上就是一个构造函数,接收一个参数,这个参数可能是节点,它会返回一个方法对象,可以操控这个节点。typeof JQuery的值是 "function"

闭包:一个函数用到了一个变量,这个变量是它外部声明的,这个变量和这个函数就是闭包,闭包淡村访问不到,但是函数可以操作它。操作一个访问不到的节点。

  • html代码
  <ul>
    <li id="id1">项目1</li>
    <li id="id2">项目2</li>
    <li id="id3">项目3</li>
    <li id="id4">项目4</li>
    <li id="id5">项目5</li>
  </ul>
  • 封装函数
    获取节点所有兄弟元素
// 获的一个节点所有兄弟元素
var allChildren = id3.parentNode.children // 获去id3所有父亲的儿子们
var array = {length:0}; //声明一个伪数组
for(let i=0; i<allChildren.length;i++){
  if(allChildren[i] !==id3){
    array[array.length] = allChildren[i] //伪数组,不能push,只能这样添加
    array.length += 1
  }
}
console.log(array) //打印出id3所有的兄弟元素(所有元素放在了一个伪数组里了)

//封装函数变形
function getSiblings(node){ // node节点。传给我一个节点,比如id3
  var allChildren = node.parentNode.children // 获去id3所有父亲的儿子们
  var array = {length:0}; //声明一个伪数组
  for(let i=0; i<allChildren.length;i++){
    if(allChildren[i] !== node){
      array[array.length] = allChildren[i] //伪数组,不能push,只能这样添加
      array.length += 1
    }
  }
  return array
}
console.log(getSiblings(id3))

给节点添加class

//  给节点添加class
var classes = {'a':true,'b':false,'c':true}  
for( let key in classes){
  var value = classes[key]
  if(value){
    id3.classList.add(key)
  }else{
    id3.classList.remove(key)
  }
}
//封装代码
function addClass(node,classes){
  var classes = {'a':true,'b':false,'c':true}  
  for( let key in classes){
    var value = classes[key]
    if(value){
      id3.classList.add(key)
    }else{
      id3.classList.remove(key)
  }
}
addClass(id3,{'a':true,'b':false,'c':true})
}
//代码优化
function addClass(node,classes){
  var classes = {'a':true,'b':false,'c':true}  
  for( let key in classes){
    var value = classes[key]
    var methodName = value ? 'ad':'remove'
    //如果有不明白把不明白的都打印出来
    console.log(methodName)
    console.log(node.classList)
    console.log(node.classList.add)
    console.log(node.classList[methodName])
    node.classList[methodName](key)
  }
}
addClass(id3,{a:true,b:false,c:true})

命名空间设计模式

function getSiblings(node){ // node节点。传给我一个节点,比如id3
  var allChildren = node.parentNode.children // 获去id3所有父亲的儿子们
  var array = {length:0}; //声明一个伪数组
  for(let i=0; i<allChildren.length;i++){
    if(allChildren[i] !== node){
      array[array.length] = allChildren[i] //伪数组,不能push,只能这样添加
      array.length += 1
    }
  }
  return array
}

function addClass(node,classes){
  var classes = {'a':true,'b':false,'c':true}  
  for( let key in classes){
    var value = classes[key]
    var methodName = value ? 'ad':'remove'
    //如果有不明白把不明白的都打印出来
    console.log(methodName)
    console.log(node.classList)
    console.log(node.classList.add)
    console.log(node.classList[methodName])
    node.classList[methodName](key)
  }
}
//两个函数有关联 可以一起取个名字 就是命名空间设计模式
window.ffDom = {}
ffDom.getSiblings = getSiblings
ffDom.addClass = addClass
//使用
ffDom.getsiblings(id3)
ffDom.addClass(id3,{a:true,b:flase,c:true})

这样做容易不知不觉覆盖全局变量

//首先声明了一个对象,对象有getSibling和addClass两个属性
window.ffDom = {}

ffDom.getSiblings = function(node){
  var allChildren = node.parentNode.children
  var array = {length:0}; 
  for(let i=0; i<allChildren.length;i++){
    if(allChildren[i] !== node){
      array[array.length] = allChildren[i] 
      array.length += 1
    }
  }
  return array
}
ffDom.addClass = function(node,classes){
  for( let key in classes){
    var value = classes[key]
    var methodName = value ? 'add':'remove'
    node.classList[methodName](key)
  }
}

//使用直接用这个对象就可以了,只要取的名字不一样就不会覆盖别人的全局变量了
ffDom.getSiblings(id3)
ffDom.addClass(id3,{a:true,b:false,c:true})

我们直觉一般这样使用:就需要修改node(id3)的原型链
id3.getSibling
id3.addClass

//修改node的原型链,我们添加一个getSibling
Node.prototype.getSibling = function(){
  //怎么获取node呢? 可以用this,this是call的第一个参数
  this  //把所有node改成this,node会自动找到id3
}   
//修改node的原型链,我们添加一个addClass
Node.prototype.addClass = function(classes){
  for( let key in classes){
    var value = classes[key]
    var methodName = value ? 'add':'remove'
    this.classList[methodName](key)
  }
}
*********************************************************************
//完整代码
Node.prototype.getSiblings = function(){
  var allChildren = this.parentNode.children
  var array = {length:0}; 
  for(let i=0; i<allChildren.length;i++){
    if(allChildren[i] !== this){
      array[array.length] = allChildren[i] 
      array.length += 1
    }
  }
  return array
}
Node.prototype.addClass = function(classes){ //这里就不需要this了
  for( let key in classes){
    var value = classes[key]
    var methodName = value ? 'add':'remove'
    this.classList[methodName](key)
  }
}

//使用
id3.getsiblings()
id3.addClass([a:true,b:false,c:true])
//用call看着更明显
id3.getsiblings.call(id3)
id3.addClass(id3,[a:true,b:false,c:true])
  • jQuery初探
    这样写的话还有弊端,我们不能确定别人有没有给原型添加跟我们一样的方法,同样的话就会覆盖。解决办法,重新再写一个Node2原型,然后调用Node。首先声明一个Node2等于一个函数,给我一个node,把node升级node2,返回一个新的对象,新的对象(函数)有两个属性(函数)getSbiling和addClass,现在id3重新构造下,var node2 = Node2(id3),新的属性怎么获取节点呢,因为我们构造新的对象时,已经传了一个node了,可以直接操作node。
    现在把Node2修改成jQuery,jQuery其实就是Dom的升级,接收一个久的node,返回一个新的对象,这个对象就是jQuery对象,也可以认为是node2对象,使用的时候只需要调用旧node的getSibling和addClass两个属性。
//Node2改成jquery
window.Node2 = function(node){
  return{
    getSiblings: function(){
      var allChildren = node.parentNode.children
      var array = {length:0}; 
      for(let i=0; i<allChildren.length;i++){
        if(allChildren[i] !== node){
        array[array.length] = allChildren[i] 
        array.length += 1
        }
      }
      return array
    },
    addClass: function(classes){ //需要传入一个参数 参数名
      for( let key in classes){
      var value = classes[key]
      var methodName = value ? 'add' : 'remove'
      node.classList[methodName](key)
      }
    }
  }
}
var node2 = Node2(id3) 
//Node2修改成jQuery
var node2 = jQuery(id3)

node2.getSiblings()
node2.addClass({a:true,b:false,c:true})

假如传参是一个字符串呢,传参名为nodeOrSelector(节点或选择器),然后声明一个变量node,不赋值,传参类型做下判断,if传参类型为字符串,document.querySelsector(nodeOrSelector)会通过字符串 获取这个节点元素,赋值给node。这样就可以操作这个节点了。

window.Node2 = function(nodeOrSelector){
  let node
  if(typeof nodeOrSelector === 'string'){
    node = document.querySelector(nodeOrSelector)
  }else{
    node = nodeOrSelsector
  }
  
  return{
    getSiblings: function(){
      var allChildren = node.parentNode.children
      var array = {length:0}; 
      for(let i=0; i<allChildren.length;i++){
        if(allChildren[i] !== node){
        array[array.length] = allChildren[i] 
        array.length += 1
        }
      }
      return array
    },
    addClass: function(classes){
      for( let key in classes){
      var value = classes[key]
      var methodName = value ? 'add' : 'remove'
      node.classList[methodName](key)
      }
    }
  }
}
var node2 = Node2('#id3')
node2.getSiblings()
node2.addClass({red:true,b:false,c:true})

此处用到了闭包,像addClass这个函数用到了一个变量node,这个变量node是外部声明的,这个node和这个addClass匿名的函数我们就叫闭包。


深度截图_选择区域_20180317203136.png

怎么操作多有节点呢?首先声明一个变量nodes(所有节点),需要初始化一下,要不就是undefined。判断类型,如果传参是字符串,就是一个或多个节点,因为doucument.querySelsectorAll返回的就是一个hash,一个伪数组,变量nodes就是一个伪数组,return nodes之后我们发现不是一个纯净的伪数组,首先给他一个临时变量,然后遍历他,它的proto直接指向object了,是一个纯净的伪数组。如果传参是一个node节点,本来会返回一个元素,因为返回要一致,if返回一个伪数组,else也要返回一个数组。也就是说不管返回的是什么我们都放到nodes里。因为nodes只有 0,1,2,3,4 和length这几个key,没有getSibling和addClass方法,因为nodes是一个对象,我们可以给它添加这些方法。比如addClass(),我们操作谁呢,肯定是nodes,现在nodes是一个hash,不是一个元素,所以我们要操作nodes[0]/nodes[1]/…nodes[5],我们肯定不能写死,所以要遍历它,然后nodes[i]就可以了。


window.jQuery = function(nodeOrSelector){ // ②. 然后判断类型
  let nodes = {} //⑤. 放到伪数组里
  if(typeof nodeOrSelector === 'string'){ //③. 如果是字符串
    let temp = document.querySelectorAll(nodeOrSelector) //④. 就获取所有元素
    for(let i = 0; i < temp.length; i++){ 
      nodes[i] = temp[i]
    }
    nodes.length = temp.length
  }else if(nodeOrSelsctor instanceof Node){ // ⑥.如果是节点
    nodes = {        //⑦. 不管是字符串还是节点都放在这个伪数组里边
      0: nodeOrSelector,     //这里本来是一个节点,因为要返回一致,所以必须是个维数组
      length : 1
    }
  }
  nodes.addClass = function(classes){  // ⑨. 这个函数就遍历这个classes
    classes.forEach((value) => {
      for(let i = 0; i < nodes.length; i++){
        nodes[i].classList.add(value)  // ⑩. 然后会把遍历结果逐个放到伪数组的每一项里
      }
    })
  }
  return nodes
}

var node2 = jQuery('ul > li') // ①. jQuery接收了一个字符串
node2.addClass(['red'])  //⑧. 现在如果调用addClass

添加jQyery一些API:获取所有文本和设置文本


window.jQuery = function(nodeOrSelector){
  let nodes = {}
  if(typeof nodeOrSelector === 'string'){
    let temp = document.querySelectorAll(nodeOrSelector)
    for(let i = 0; i < temp.length; i++){
      nodes[i] = temp[i]
    }
    nodes.length = temp.length
  }else if(nodeOrSelsctor instanceof Node){
    nodes = {
      0: nodeOrSelector,
      length : 1
    }
  }
  nodes.addClass = function(classes){
    classes.forEach((value) => {
      for(let i = 0; i < nodes.length; i++){
        nodes[i].classList.add(value)
      }
    })
 }
  
  
  //添加jQuery一些有用的API:获取所有文本
  nodes.getText = function(){
    var texts = []
    for(let i = 0; i < nodes.length; i++){
      texts.push(nodes[i].textContent)
    }
    return texts
  }

  //设置text
//   nodes.setText = function(text){
//     for(i = 0; i < nodes.length; i++){
//       nodes[i].textContent = text
//       }       
 
//       return nodes
//     }
  return nodes
}  


var node2 = jQuery('ul > li')
node2.addClass(['red'])
console.log(node2.getText())
// node2.setText('hi')

jQuery一般不这么用,它把两个功能合并了,如果不给参数(undefined),表明是想获取文本,如果传了参数就表明想设置文本。代码如下



window.jQuery = function(nodeOrSelector){
  let nodes = {}
  if(typeof nodeOrSelector === 'string'){
    let temp = document.querySelectorAll(nodeOrSelector)
    for(let i = 0; i < temp.length; i++){
      nodes[i] = temp[i]
    }
    nodes.length = temp.length
  }else if(nodeOrSelsctor instanceof Node){
    nodes = {
      0: nodeOrSelector,
      length : 1
    }
  }
  nodes.addClass = function(classes){
    classes.forEach((value) => {
      for(let i = 0; i < nodes.length; i++){
        nodes[i].classList.add(value)
      }
    })
 }
  
  //合并功能代码
  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(i = 0; i < nodes.length; i++){
      nodes[i].textContent = text
      }       
    }
  }
  return nodes
}  


var node2 = jQuery('ul > li')
node2.addClass(['red'])

//不传参数
var text = node2.text() 
console.log(text)

// node2.text('hi') //传参就不用赋值变量了,直接写入需要传的参数

相关文章

网友评论

    本文标题:类似jQuery

    本文链接:https://www.haomeiwen.com/subject/hvbrqftx.html