写在前面
写这篇博客目的在于认识DOM以便进行封装
DOM原生语句
- 创建元素
document.createElement('标签名')
document.createTextNode()
document.createAttribute()
document.createComment()
document.createDocumentFragment() DocumentFragment 不是真实 DOM 树的一部分,它的变化不会触发DOM树的重新渲染,且不会导致性能等问题最常用的方法是使用文档片段作为参数一次性插入了当前文档。
请把<body><p>第1行</p><p>第2行</p>...</body>(body之间有100个p元素)插入body里面,这种情况用DocumentFragment明显比用for循环一个一个插入好用
以上几种办法只管创建不管插入在js线程中完成,插入需要其他语句
- 插入元素的第二种语法
Element.innerHTML = '字符串'能改写所有元素节点的内容,如果字符串是HTML标签就相当于插入标签了
- 插入元素
Node.insertBefore() insertBefore方法接受两个参数,第一个参数是所要插入的节点newNode,第二个参数是父节点内部的一个子节点
Node.appendChild()方法接受一个节点对象作为参数,将其作为最后一个子节点,插入当前节点。
封装
- 插入元素语句
window.dom.creat = function(tagName){
return document.createElement(tagName)
}
不够方便继续改造
window.dom.creat = function(string){
const container = document.createElement("div")
container.innerHTML = string
return container.children[0]
}
但是有的元素是不能在div元素里的不如td
window.dom.creat = function(string){
const container = document.createElement("template")
container.innerHTML = string.trim()
return container.content.firstChild
}
改成template就可以HTML5新的标签专门作为容器的标签什么都能放,注意这个标签不能用children[]
trim的作用在于去掉字符串两边的空格,防止空格成为第一个孩子
这样creat函数就可以接受<div><span>1</span></div>这样的代码,这里creat后仍然存在于线程中,而且container并不会被返回
- 在某个元素前后创建一个元素
window.dom.after = function(node,node2){
node.parentNode.insertBefore(node2,node.nextSilbling)
}
在插入后一个元素的前面,即使已经是最后一个元素仍然可以插入
window.dom.bofore = function(node,node2){
node.parentNode.insertBefore(node2,node)
}
- 插入一个节点
dom.append = function(parent,node){
parent.appendChild(node)
}
- 给一个元素加一个父元素
window.dom.wrap = function(node,parent){
dom.before(node,parent)
dom.append(parent,node)
}
先把parent放到node前面,然后把node放到parent里面
- 删除节点
window.dom.remove = function(node){
node.parentNode.removeChild(node)
return node
}
window.dom.empty = function(node){
const array = []
let x = node.firstChild
while(x){
array.push(dom.remove(node.firstChild))
x = node.firstChild
}
return array
}
删除所有子节点,注意直接遍历删除的话伪数组长度是会实时反馈的
const {childNodes} = node 等价于 const childNodes = node.childNodes
- 设置属性
属性本身是一个对象(Attr对象),但是实际上,这个对象极少使用。一般都是通过元素节点对象(HTMlElement对象)来操作属性。
元素对象有一个attributes属性,返回一个类似数组的动态对象,成员是该元素标签的所有属性节点对象,属性的实时变化都会反映在这个节点对象上。其他类型的节点对象,虽然也有attributes属性,但返回的都是null,因此可以把这个属性视为元素对象独有的。
window.dom.attr = function(node,name,value){
if(arguments.length === 3){
node.setAttritube(name,value)
}else if(arguments === 2){
return node.getAttribute(name)
}
}
- 修改文本
window.dom.text = function(node,string){
if(arguments.length === 2){
if('innerText' in node){
node.innerText = string
}else{
node.textContent = string
}
}else if(arguments.length === 1){
return node.innerText
}
}
分别满足ie和其他浏览器
textContent属性返回当前节点和它的所有后代节点的文本内容。自动忽略当前节点内部的 HTML 标签,返回所有文本内容。
- 修改样式
独特操作:元素节点的style属性(Element.style),style的属性
window.dom.style = function(node,name,value){
if(arguments.length === 3){
// dom.style(div,'color','red')
node.style.name = value
}else if(arguments.length === 2){
// dom.style(div,'color')
if(typeof name === 'string'){
return node.style[name]
}else if(naem instanceof Object){
// dom.style(div,{color:'red'})
for(let key in name){
node.stlyle[key] = name[key]
}
}
}
}
- 给元素加类
window.dom.class = {
add(node,className){
node.classList.add(className)
}
remove(node,className){
node.classList.remove(className)
}
has(node,className){
return node.classList.contains(className)
}
}
- 事件
window.dom.on = function(node,eventName,fn){
node.addEventListener(eventName,fn)
}
window.dom.off = function(node,eventName,fn){
node.removeEventListener(eventName,fn)
}
- 查找元素
window.dom.find = function(selector,scope){
return (scope || document).querySelectorAll(selector)
}
在scope里面找selector
- 找父子兄弟
window.dom.parent = function(node){
return node.parentNode
}
window.dom.sibling = function(node){
return Array.from(node.parentNode.children).filter(n => n!== node)
}
childNodes是节点提供的包含空格,children是元素提供的
window.dom.next = function(node){
let x = node.nextSbling
while(x.nodeType === 3){
x = x.nextSbling
}
return x
}
window.dom.previous = function(node){
let x = node.previousSbling
while(x.nodeType === 3){
x = x.previousSbling
}
return x
}
节点分为很多种nodeType返回不同值,nextSibling所有节点都返回
- 遍历
window.dom.each = function(nodeList,fn){
for(let i= 0;i <= nodeList.length;i++){
fn.call(null,nodeList[i])
}
}
- 下标
window.dom.index = function(node){
const list = window.dom.children(node.parentNode)
for(let i = 0;i<list.length;i++){
if(list[i] === node){
break
}
}
return i
}
- 查找孩子
window.dom.children = function(node){
return node.children
}
注意dom.children是不会实时变化的,而children会实时变化