网页也是一棵树,根节点是<html>标签,每个标签都是一个子节点。
JS不能直接操作这棵树,浏览器就在window上加了一个document,使JS可以操作网页---Document Object Model
接下来就是正文
一、获取元素
获取元素,也叫标签
(一)获取任意元素
window.idxxx或idxxx
id为kw的元素
document.getElementById('idxxx')
id为关键字,那么第一种方法就不适用了,需要使用这种精确的方法
document.getElementsByTagName('div')[0]
找到所有标签名为div的元素,后面的下标表示找第几个,不带下标的话找到的是一个伪数组,并不能对它进行操作
document.getElementsByClassName('red')[0]
找到ClassName为red的元素
-
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')
- 重写整个class内容
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
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'
- 写data-*属性:
# 读标准属性
名字一一对应读取就好,class可以用className或者classList
div.classList/a.hrefdiv.getAttribute('class')/a.getAttribute('href')div1.dataset.x
- a标签例外,浏览器会默认给相对路径补充当前站点的域名
(2)改事件处理函数
div.onclick默认为null,也就是点击div不会有任何事情发生- 但是如果把
div.onclick改为一个函数fn,那么点击div的时候,浏览器就会调用这个函数 - 通过
fn.call(div,event)上传参数并调用fn div就是thisevent则包含了点击事件的所有信息,包括坐标等等
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.parentNodenode.parentElement
- 查爷爷
node.parentNode.parentNode
- 查孩子
node.childNodesnode提供的,空格回车也算node.childrenelement提供的,比较符合正常人的思维
- 查兄弟姐妹
node.parentNode.childNodesnode.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))