DOM

204 阅读6分钟

网页也是一棵树,根节点是<html>标签,每个标签都是一个子节点。 JS不能直接操作这棵树,浏览器就在window上加了一个document,使JS可以操作网页---Document Object Model

接下来就是正文

一、获取元素

获取元素,也叫标签

(一)获取任意元素

  • window.idxxxidxxx

可以直接获取idkw的元素

  • document.getElementById('idxxx')

如果id关键字,那么第一种方法就不适用了,需要使用这种精确的方法

  • document.getElementsByTagName('div')[0]

找到所有标签名为div的元素,后面的下标表示找第几个,不带下标的话找到的是一个伪数组,并不能对它进行操作

  • document.getElementsByClassName('red')[0]

找到ClassNamered的元素

  • document.querySelector('#idxxx')

  • document.querySelectorAll('.red')[0]

最后两个方法借用了CSS选择器的使用方法,找id用‘#’,找class用‘.’,而且可以写的很复杂

找一个div里的span,并且是它的第二个儿子

找所有符合条件的选项,符合条件的第几个

一般用最后两种方法,demo时可以用第一种

(二)获取特定元素

  • 获取html元素document.documentElement

enenen~~~~~小写的标签名打出来是大写!!

  • 获取head元素document.head

  • 获取body元素document.body

  • 获取所有元素document.all
    这个是个奇葩,是第六个falsy值,只支持ie,所以可以用这个代码判断是否是ie浏览器

(三)获取窗口

  • 获取窗口(窗口不是元素)window

窗口虽然不是元素,但是我们也可以获取,比如监听一个click事件

我么在这个窗口监听onclick事件,当在这个窗口点击时就会打印hi

(四)原型

我们获取到的元素到是啥,来看看它的原型链来了解一下

很显然是个对象,有六层原型

二、节点、元素、标签。。。。

  • 1表示元素Element也叫标签Tag
  • 3表示文本Text
  • 8表示注释Comment
  • 9表示文档Document
  • 11表示文档片段DocumentFragment

nodeType可以查看这个节点的节点类型 这个div是一个的节点类型是‘1’,也就是元素;然后childNodes查看这个div的子节点,第一个节点是text文本,textContent查看文本内容,这个文本内容是一个回车,然后它的节点类型是‘3’,也就是文本,。。en。。。这是一个证明题

三、节点的增删改查

(一)增

(1)创建一个标签节点

  • let div1 = document.createElement('div') 创建一个div节点
  • document.creatElement('style') 创建一个CSS节点
  • document.creatElement('script')创建一个script节点
  • document.creatElement('li') 创建一个li节点

(2)创建一个文本节点

text1 = document.createTextNode('你好')

(3)标签里面插入文本

  • div1.appendChild(text1)
  • div1.innerText = '你好'
  • div1.textContent = '你好'

div节点只接受节点,'你好'是个字符串,要把它作为一个节点放进div

(4)插入页面中

  • 刚刚创建的标签默认处于JS线程中,需要把它插到head或者body里才会生效
    • document.body.appendChiled(div)
    • 已在页面中的元素.appendChild(div)

一个元素不能同时出现在两个地方,但是可以复制cloneNode()

(二)删

(1)旧方法(Element提供,兼容ie)

  • chiledNode.parentNode.removeChild(childNode)让这个节点的爸爸删掉它

(2)新方法(node提供,不兼容ie,简单)

  • childNode.remove()直接自己删掉就好了

(3)如果一个node被移出页面(DOM树),它还可以回来吗

  • 可以!只是被移出页面,但是它还在内存中
    • 就是第一种方法是你爸爸不要你了,但你还在这个人世间,哪一天你爸爸想你了,还能再把你认回来
    • 第二种方法就是自己任性,离家出走了,但是呢,还有对家的眷恋,没有走远,你爸爸一叫你就回来了

  • 让这个div1彻底消失
    • 首先从DOM树移出
    • 然后 div1 = null,让这个div1断开连接,就会被垃圾回收掉

(三)改(写)

(1)改属性

# 写标准属性

  • 改id:div.id = 'div1'

  • 改class
    • 重写整个class内容div.className = 'red blue'
    • 增加class:div.classList.add('red')

早期的JS的对象是不能使用一个保留字作为它的key的,所以,div.class不能用。 className会把之前的全覆盖,如果想加一个red,就要写div1.className += ' red'(red前有个空格) 新的API有一个classList

  • 改style:
    • 重写style div.style = 'width:100px;color:blue;'
    • 改style的一部分:div.style.width = '20px'
    • 注意大小写

style也会全覆盖,正确做法是该什么写什么
JS不支持中划线的key,就算支持也只能用字符串的形式来表示div1.style['background-color']
那如果你就要用‘.’(div1.style.background-color)来表示呢,中划线就会被理解成减号
所以JS就规定中划线大写div1.style.backgroundColor(-c写成C)

  • data属性(自定义属性)
    • 写data-*属性:div.setAttribute('data-x','test')'
    • 改data-*属性:div1.dataset.x = 'hello'

# 读标准属性

名字一一对应读取就好,class可以用className或者classList

  • div.classList/a.href
  • div.getAttribute('class')/a.getAttribute('href')
  • div1.dataset.x

  • a标签例外,浏览器会默认给相对路径补充当前站点的域名

(2)改事件处理函数

  • div.onclick默认为null,也就是点击div不会有任何事情发生
  • 但是如果把div.onclick改为一个函数fn,那么点击div的时候,浏览器就会调用这个函数
  • 通过fn.call(div,event)上传参数并调用fn
  • div就是this
  • event则包含了点击事件的所有信息,包括坐标等等

浏览器自动使用test.onclick.call(test,event)来调用fn x就是一个参数,叫什么无所谓,反正是按照顺序来的,不是按照名字

(3)改内容

# 改文本内容

改的仅仅是开关标签之间的文本内容

  • div.innerText = 'xxx'
  • div.textContent = 'xxx'

# 改HTML内容

可以在div里加各种标签,但是长度有所限制,大概在好几千行

  • div.innerHTML = '<strong>重要内容</strong>'

# 改标签

  • div.innerHTML = ''先清空
  • div.appendChild(div2)再加内容

(4)改爸爸

  • newparent.appendChild(div)

之前说了一个div不能同时出现在两个地方,那就找到新爸爸,把这个div加过去就好了

(四)查

  • 查爸爸
    • node.parentNode
    • node.parentElement
  • 查爷爷
    • node.parentNode.parentNode
  • 查孩子
    • node.childNodesnode提供的,空格回车也算
    • node.childrenelement提供的,比较符合正常人的思维

  • 查兄弟姐妹
    • node.parentNode.childNodes
    • node.parentNode.children

两种方法都是先获取爸爸,然后看爸爸的所有孩子,兄弟姐妹的话还要排除自己,如果是childNodes还要排除文本节点

let siblings= []
let c = div.parentElement.children
for(let i = 0; i<c.length; i++){
    if(c[i] !== div){
        siblings.push(c[i])
    }
}
  • 查老大
    • node.firstChild
  • 查老幺
    • node.lastChild
  • 查上一个兄弟
    • node.previousSibling
  • 查下一个兄弟
    • node.nextSibling

最后两个可能查到文本节点,要避开文本节点可以声明是查看元素的兄弟 node.previousElementSibling node.nextElementSibling

查看所有元素(遍历)

travel = (node, fn) =>{   
//给我一棵树,和一个函数
    fn(node)  
    //首先用函数调一下这棵树,把节点打印出来(node是在最后定义的,传参数的时候)
    if(node.children){  
    //如果这个节点有儿子,就遍历这些儿子
        for(let i=0; i<node.children.length; i++){
            travel(node.children[i],fn)  
            //每个节点再travel一下,看看它有没有儿子,这是一个递归的travel
        }
    }
}
travel(div1,(node) => console.log(node))