# 33. JQuery中的设计模式(上)

代码参考：[这里](https://codesandbox.io/s/domlun-zi-uzjoxs)

* 也叫命名空间风格
  * window\.dom 是我们提供的全局对象
* 增

  * dom.create(\`\<div>hi\</div>\`) 用于创建节点
  * dom.after(node, node2) 用于新增弟弟
  * dom.before(node, node2) 用于新增哥哥
  * dom.append(parent, child) 用于新增儿子
  * dom.wrap(\`\<div>\</div>\`) 用于新增爸爸 ![IMG\_1560](https://raw.githubusercontent.com/clairyitinggu/images/main/img202304111506942.png)

  ```javascript
  window.dom = {
    create(string) {
      const container = document.createElement("template");//可以包含任何tag，连td都可以容纳，如果把td放到div中，会return undefined
      container.innerHTML = string.trim();// .trim()去掉字符串两边的空格
      return container.content.firstChild; //万能公式，可以创建任何元素
    },

    after(node, node2) {
      node.parentNode.insertBefore(node2, node.nextSibling);//有个实验功能node.after()，但是不推荐使用
    },

    before(node, node2) {
      node.parentNode.insertBefore(node2, node);
    },

    append(parent, node) {
      parent.appendChild(node);
    },

    wrap(node, parent) {
      //用parent包裹node 看下面的图示，右边是最后的效果，左边是先将div3插到div1后面，然后再把div2插到div3后面
      //wrap(div2,div3) 把div3包到div2的外面
      //dom.before(div2,div3) 把div3插到div2的前面
      //dom.append(div3,div2) 把div2插到div3的里面
      dom.before(node, parent);
      dom.append(parent, node);
    }
  };
  ```

  ![截屏2023-04-09 上午12.53.55](https://raw.githubusercontent.com/clairyitinggu/images/main/img202304111506893.png)
* 删

  * dom.remove(node) 用于删除节点 //把一个节点从树中删掉
  * dom.empty(parent) 用于删除后代 //把一个父元素的所有儿子全部删除

  ```javascript
  remove(node){
  	node.parentNode.removeChild(node);
  	return node;
  }

  empty(node){
  //node.innerHTML = "";第一种方法，但是这样就获取不到后面节点的引用了
  const {childNodes} = node; //解构赋值 <=> const childNodes = node.childNodes
  const array = [];
  let x = node.firstChild;
  while(x){
  	array.push(dom.remove(node.firstChild));
  	x = node.firstChild
  }
  }

  ```
* 改

  * dom.attr(node, 'title', ?) 用于读写属性
  * dom.text(node, ?) 用于读写文本内容
  * dom.html(node, ?) 用于读写 HTML 内容
  * dom.style(node, {color: 'red'}) 用于修改 style
  * dom.class.add(node, 'blue') 用于添加 class
  * dom.class.remove(node, 'blue') 用于删除 class
  * dom.on(node, 'click', fn) 用于添加事件监听
  * dom.off(node, 'click', fn) 用于删除事件监听

  ```javascript
  attr(node,name, value){//(节点，属性名，属性值) 重载Overload：根据不同参数调用不同函数
  	if(arguments.length === 3){ //如果传入的参数长度为3，就意味着要设置attribute
  		node.setAttribute(name, value);
  	}else if(arguments.length === 2){//
  		return node.getAttribute(name);//如果传入的参数长度为2，说明只是想获取attribute
  	}	
  }

  text(node, string){ //适配
  // node.innerText = string //ie
  // node.textContent = string // firefox/Chrome
  if(arguments.length === 2){
  	if('innerText' in node){
  		node.innerText = string;
  	}else{
  		node.textContent = string;
  	}
  }else if(arguments.length === 1){
  	if('innerText' in node){
  		return node.innerText;
  	}else{
  		return node.textContent;
  	}
  }		
  }

  html(node, string){
   if(arguments.length === 2){
   	node.innerHTML = string;
   }else if(arguments.length === 1){
   	return node.innerHTML;
   }
  }


  style(node, object){
    for(let key in object){
      node.style[key] = object[key]
    } 
  }
  //dom.style(test, {border:'1px solid red', color:'blue'})

  style(node,name,value){
    if(arguments.length === 3){
     // dom.style(div, 'color', 'red')
      node.style[name] = value;
    }else if(arguments.length === 2){
      if(typeof name === 'string'){
        //dom.style(div,'color')
        return node.style[name]
      }else if(name instanceof Object){
        //dom.style(div,{color:'red'})
        const object = name
        for(let key in object){
          node.style[key] = object[key]
        }
      }
    }
  }
  //dom.style(test, 'border', '1px solid black')


  class:{
    add(node, className){
      node.classList.add(className)
    },
     remove(node, className){
       node.classList.remove(className)
    },
     has(node, className){
       return node.classList.contains(className)
     }
  }
  //<style>.red{background:red;}</style>
  //dom.class.add(test, 'red')
  //dom.class.add(test, 'blue')
  //dom.class.remove(test,'blue')

  on(node, eventName, fn){
    node.addEventListener(eventName, fn);
  },
  off(node, eventName, fn){
    node.removeEventListener(eventName, fn);
  }
  //**
  //const fn = ()=>{
  //	console.log("clicked");
  //	}
  //dom.on(test, 'click',fn)
  //dom.off(test, 'click', fn)
  //

  ```
* 查
  * dom.find('选择器') 用于获取标签或标签们
  * dom.parent(node) 用于获取父元素
  * dom.children(node) 用于获取子元素
  * dom.siblings(node) 用于获取兄弟姐妹元素
  * dom.next(node) 用于获取弟弟
  * dom.previous(node) 用于获取哥哥
  * dom.each(nodes, fn) 用于遍历所有节点
  * dom.index(node) 用于获取排行老几

```javascript
find(selector, scope){
  return (scope || document).querySelectorAll(selector)
}
//const testDiv = dom.find('#test')[0] 必须要加[0]，否则获取的就是一个数组

parent(node){
  return node.parentNode;
}

children(node){
  return node.children;
}

siblings(node){//不包括自己
  return Array.from(node.parentNode.children).filter(n => n !== node)
}

next(node){
  let x = node.nextSibling
  while(x && x.nodeType === 3){
    x = x.nextSibling
  }
  return x;
}

previous(node){
  let x = node.previousSibling
  while(x && x.nodeType === 3){
    x = x.previousSibling
  }
  return x;
}

each(nodeList, fn){
  for(let i = 0 ; i < nodeList.length; i++){
    fn.call(null, nodeList[i])
  }
}


index(node){
  const list = dom.children(node.parentNode);
  let i;
  for( i = 0; i < list.length; i++){
    if(list[i] === node){
      break;
    }
  }
  return i;
}

```
