DOM 的基本概念
- DOM(Document Object Model): 文档对象模型
- 其实就是操作 html 中的标签的一些能力
- 我们可以操作哪些内容
- 获取一个元素
- 移除一个元素
- 创建一个元素
- 向页面中添加一个元素
- 给元素绑定一些事件
- 获取元素的属性
- 给元素添加一些 css 样式
- ...
- DOM 的核心对象就是 document 对象
- document 对象是浏览器内置的一个对象, 里面存储这专门用来操作元素的各种方法
- DOM: 页面中的标签, 我们通过 JS 获取到以后, 就把这个对象叫做 DOM 对象
获取非常规元素
- document.documentElement -> html标签
- document.head -> head标签
- document.body -> body标签
//1.html标签
console.log(document.documentElement)
//2.head
console.log(document.head)
//3.body
console.log(document.body)
获取常规元素
- 通过ID名获取标签
- 语法: document.getElementById('ID名')
- 因为页面中的 ID 是唯一的, 所以获取到的就是一个元素
<body>
<div id="box"></div>
<script>
var box = document.getElementById('box')
console.log(box) // 页面中 ID 为 box 的标签
</script>
</body>
- 通过class名获取标签
- 语法: document.getElementsByClassName('class名')
- 注意:因为页面中可能会有多个元素的 class 相同,所以获取到的是一组元素
- 哪怕页面中只有一个, 获取到的也是一组元素, 只不过这一组元素只有一个 DOM 元素
- 获取到后,会把元素放在一个长得很像数组一样的数据结构内,但他并不是数组,我们管这种数据结构叫做 伪数组
- 伪数组: 长得很像数组,也是通过索引排列的,但是没有数组的方法
<body>
<div class="box"></div>
<script>
var box = document.getElementsByClassName('box')
console.log(box) // [<div></div>]
console.log(box[0]) // <div></div>
</script>
</body>
- 通过标签名获取
- 语法: document.getElementsByTagName('标签名')
- 注意:获取到的也是一个长得很像数组的数据结构,其实就是获取到了一个伪数组
- 想要准确的获取到标签元素,我们需要通过索引来帮助我们拿到
<body>
<div></div>
<script>
var box = document.getElementsByTagName('div')
console.log(box) // [<div></div>]
console.log(box[0]) // <div></div>
</script>
</body>
- 按照选择器的形式来获取元素
-
querySelector
- 这个方法允许我们像写css的时候的选择器一样获取标签
- 注意:这个方法只能获取到一个元素,就是满足条件的第一个元素
- 语法: document.querySelector('选择器')
-
querySelectorAll
- 这个方法与querySelector 选择器类似,只不过会将所有满足条件的元素都获取到,也放在一个伪数组中
- 注意:这个方法能获取到所有满足条件的元素
- 语法: document.querySelectorAll('选择器')
-
console.log(document.querySelector('div')) // 获取页面中第一个 div 元素
console.log(document.querySelector('.box')) // 获取页面中第一个 有 box 类名的元素
console.log(document.querySelector('#box')) // 获取页面中第一个 id 名为 box 的元素
console.log(document.querySelectAll('div')) // 获取页面中的所有的 div 元素
console.log(document.querySelectAll('.div')) // 获取页面中的所有的 类名为 box 的元素
操作属性
innerHTML
- 获取元素内部的 HTML 解构
<div>
<p>
<span>hello</span>
</p>
</div>
var div = document.querySelector('div')
console.log(div.innerHTML) // <p><span>hello</span></p>
- 设置元素内部的 HTML 解构
<div></div>
var div = document.querySelector('div')
div.innerHTML = '<p><span>hello</span></p>'
innerText
- 获取元素内部的文本(只能获取到文本, 获取不到 html 标签)
<div>
<p>
<span>hello</span>
</p>
</div>
var div = document.querySelector('div')
console.log(div.innerHTML) // hello
- 设置元素内部的 HTML 解构
<div></div>
var div = document.querySelector('div')
div.innerHTML = '<p><span>hello</span></p>'
//会把 '<p><span>hello</span></p>' 当作一段文本出现在 div 元素内, 而不会吧 p 解析成标签
getAttribute
- 获取元素的某个属性(包括自定义属性)
- 语法: 元素.getAttribute('要查询的属性名')
- 返回值:查询到属性时返回对应的属性值,没有查询到时直接返回 null
<div a="100" class="box"></div>
var div = document.querySelector('div')
console.log(div.getAttribute('a')) // 100
console.log(div.getAttribute('class')) // box
console.log(div.getAttribute('b'))//null
setAttribute
- 给元素设置的一个属性(包括自定义属性)
- 语法: 元素.setAttribute('对应的属性名','对应的属性值')
- 注意: 如果元素没有对应的属性名,那么相当于是新增一个属性
<div></div>
var div = document.querySelector('div')
console.log(div.setAttribute('a', 100))
console.log(div.setAttribute('class', box))
removeAttribute
- 直接移除元素的某个属性
- 语法: 元素.removeAttribute('要删除的属性名')
<div a="100" class="box"></div>
var div = document.querySelector('div')
console.log(div.removeAttribute('class'))
H5 自定义属性
- 在 H5 自定义属性中
data-表示该属性是一个自定义属性 data-以后的内容才是属性名=后面的内容才叫做属性值- 每一个元素身上天生自带一个属性, 叫做 dataset, 是一个类似对象的数据结构
- 内部记录的是该元素身上所有
data-开头的自定义属性 - 对于该元素 H5 自定义属性的操作, 就是对这个数据结构的操作(对象操作语法)
<div data-a="100" class="box"></div>
var oDiv = document.querySelector('div')
// 增
oDiv.dataset.age = 18
// 删
delete oDiv.dataset.a
// 查
console.log(oDiv.dataset.age)
元素行内样式 style
- 专门用来个元素添加 css 样式的
- 添加的都是行内样式
- 语法:元素.style.某个属性
- 我们也可以给这个语法重新赋值,达到修改元素样式的效果(修改的是行内样式)
<div></div>
var div = document.querySelector('div')
div.style.width = '100px'
div.style.height = '100px'
div.style.backgroundColor = 'pink'
console.log(oDiv.style['backgroundColor']) // 中括号语法
获取非行内样式
getComputedStyle (非IE使用)
- 语法: window.getComputedStyle(元素).要查询的css属性
- 注意: 这种方式获取到的属性 是只读的
currentStyle (IE使用)
- 语法:
元素.currentStyle.要获取的属性
操作元素的 类名
- className
- 语法:元素.className
- 我们也可以给她重新赋值,达到修改元素的类名
<div class='box'></div>
var div = document.querySelector('div')
console.log(div.className) // box
div.className = 'ceshi'
console.log(div.className) // ceshi
//在设置的时候, 不管之前有没有类名, 都会全部被设置的值覆盖
- classList
//0. 获取元素
var oDiv = document.querySelector('.box')
console.log(oDiv.className)
oDiv.className = 'qwer'
//2.1 获取
// console.log(oDiv.classList)
// //2.2 新增
// oDiv.classList.add('qwer')
// //2.3 删除
// oDiv.classList.remove('new_box')
DOM 节点
- 一般来说我们分为三个大类: 元素节点(标签) / 文本节点(标签内的文字) / 属性节点(标签上的属性)
- 元素节点
- 通过 getElementBy... 获取到的都是元素节点
- 属性节点
- 通过 getAttribute 获取到的就是元素的属性节点
- 文本节点
- 通过 innerText 获取到的就是元素的文本节点
获取节点
childNodes: 获取某一节点下 所有的子一级 节点
- 语法: 元素.childNodes
<div>
<p>hello</p>
</div>;
var pDiv = document.querySelector("div");
console.log(pDiv.childNodes);
/**
* NodeList(3) [text, p, text]
*
* 0 : text
* 1 : p
* 2 : text
* length : 3
*/
- 拿到的是一个伪数组, 里面有三个节点
- 一个 text: 从
<div> 一直到 <p>中间有一个换行和一堆空格, 这是第一个节点, 是一个文本节点 - 一个 p: 这个就是 p 标签, 他是第二个节点, 这是一个元素节点
- 又一个 text: 从
</div> 一直到 </p>中间有一个换行和一堆空格, 是一个文本节点
children
- 获取某一节点下所有的子一级 元素节点
- 语法: 元素.children
- 获取到的是一个伪数组
<div>
<p>hello</p>
</div>;
var pDiv = document.querySelector("div");
console.log(pDiv.children);
/**
* HTMLCollection(1) [p]
*
* 0 : p
* length : 1
*/
- 因为 children 只要元素节点 所以就只拿到了 div 下边的唯一一个 元素节点, 也就是 p
- 虽然获取到的只有一个, 但也是一个 伪数组
firstChild
- 获取某一节点下子一级的 第一个节点
- 语法: 元素.firstChild
<div>
<p>hello</p>
</div>;
var pDiv = document.querySelector("div");
console.log(pDiv.firstChild);
// #text
- 这个是只获取第一个节点, 所以不再是伪数组了
- 根据标签结构我们可以得知, 第一个节点是从
<div> 一直到 <p>的那个换行和空格, 是个文本节点
lastChild
- 获取某一节点下子一级的 最后一个节点
- 语法: 元素.lastChild
<div>
<p>hello</p>
</div>;
var pDiv = document.querySelector("div");
console.log(pDiv.lastChild);
// #text
- 这个是只获取最后一个节点, 所以不再是伪数组了
- 根据标签结构我们可以得知, 最后一个节点是从
</div> 一直到 </p>的那个换行和空格, 是个文本节点
firstElementChild
- 获取某一节点下子一级的 第一个元素节点
- 语法: 元素.firstElementChild
<div>
<p>hello</p>
</div>;
var pDiv = document.querySelector("div");
console.log(pDiv.firstElementChild);
- 这个是只获取第一个节点, 所以不再是伪数组了
- 获取的是第一个元素节点, 所以是 p 标签
lastElementChild
- 获取某一节点下子一级的 最后一个元素节点
- 语法: 元素.lastElementChild
<div>
<p>hello</p>
</div>;
var pDiv = document.querySelector("div");
console.log(pDiv.lastElementChild);
- 这个是只获取最后一个节点, 所以不再是伪数组了
- 获取的是最后一个元素节点, 所以是 p 标签
获取兄弟节点
nextSibling
- 获取某一个节点的 下一个兄弟节点
- 语法:元素.nextSibling
<ul>
<li id="a">hello</li>
<li id="b">world</li>
<li id="c">!!!</li>
</ul>;
var oLi = document.querySelector("#b");
console.log(oLi.nextSibling); // #text
- 只获取一个节点,不再是伪数组
- 获取的是
id="b"这个li的下一个兄弟节点 - 因为
id="b"的下一个节点,是两个li标签之间的换行和空格,所以是一个文本节点
previousSibling
- 获取某一个节点的 上一个兄弟节点
- 语法:元素.previousSibling
<ul>
<li id="a">hello</li>
<li id="b">world</li>
<li id="c">!!!</li>
</ul>;
var oLi = document.querySelector("#b");
console.log(oLi.previousSibling); // #text
- 只获取一个节点,不在是伪数组
- 获取的是
id="b"这个li的上一个兄弟节点 - 因为
id="b"的上一个节点,是两个li标签之间的换行和空格,所以是一个文本节点
nextElementSibling
- 获取对应的 下一个兄弟元素节点
- 语法:元素.nextElementSibling
<ul>
<li id="a">hello</li>
<li id="b">world</li>
<li id="c">!!!</li>
</ul>;
var oLi = document.querySelector("#b");
console.log(oLi.nextElementSibling); // <li id="c">!!!</li>
- 只获取一个节点,不在是伪数组
- 获取的是
id="b"这个li的下一个兄弟元素节点 - 因为
id="b"的下一个节点,是id="c" 的 li, 所以应该打印 li
previousElementSibling
- 获取某一个节点的 上一个兄弟元素节点
- 语法:元素.previousElementSibling
<ul>
<li id="a">hello</li>
<li id="b">world</li>
<li id="c">!!!</li>
</ul>;
var oLi = document.querySelector("#b");
console.log(oLi.previousElementSibling); // <li id="a">hello</li>
- 只获取一个节点,不在是伪数组
- 获取的是
id="b"这个li的上一个兄弟元素节点 - 因为
id="b"的上一个节点,是id="a" 的 li, 所以应该打印 li
获取父节点与属性节点
获取某一个节点的 父节点 parentNode
- 语法: 元素.parentNode
<ul>
<li id="a">hello</li>
<li id="b">world</li>
<li id="c">!!!</li>
</ul>;
var oLi = document.querySelector("#b");
console.log(oLi.parentNode); // <ul>...</ul>
- 只获取一个节点,不在是伪数组
- 获取的是当前这个
li的父元素节点 - 因为这个
li的父亲就是ul,所以获取到的就是ul,是一个元素节点
获取某一个 元素节点 的所有 属性节点
- 语法: 元素.attributes
<ul>
<li id="a" a="100" test="test">
hello
</li>
</ul>;
var oLi = document.querySelector("#a");
console.log(oLi.attributes); // NamedNodeMap {0: id, 1: a, 2: test, id: id, a: a, test: test, length: 3}
- 获取该元素的所有属性, 也是一个伪数组
- 这个 li 有三个属性
id; a; test, 所以就获取到了这三个
节点属性
1. nodeType 节点类型
- 节点中的一个属性 nodeType 能够区分当前节点是什么类型
nodeType === 1就表示该节点是一个 元素节点nodeType === 2就表示该节点是一个 属性节点nodeType === 3就表示该节点是一个 文本节点
2. nodeName 节点名称
- 元素节点的 nodeName 就是 大写标签名
- 属性节点的 nodeName 就是 属性名
- 文本节点的 nodeName 就是 #text
3. nodeValue 节点的值
- 元素节点 没有 nodeValue
- 属性节点的 nodeValue 就是 属性值
- 文本节点的 nodeValue 就是 文本内容 | - | nodeType | nodeName | nodeValue | | -------- | -------- | ---------- | --------- | | 元素节点 | 1 | 大写标签名 | null | | 属性节点 | 2 | 属性名 | 属性值 | | 文本节点 | 3 | #text | 文本内容 |
操纵 DOM 节点
- 常规意义上 '增删改查'
- 在增加节点前, 我们应该先有一个节点, 所以应该是
1. 创建
2. 向页面中增加一个节点
3. 删除页面中的某一个节点
4. 修改页面中的某一个节点
5. 获取页面中的某一个节点
创建节点
- 语法:document.createElement('要创建的标签名称')
var oDiv = document.createElement('div')
console.log(oDiv) // <div></div>
- createTextNode 创建一个文本节点
var oDiv = document.createTextNode('我是一个文本节点')
console.log(oDiv) // 我是一个文本节点
向页面增加一个节点
- 语法1:元素.appendChild(要添加的节点)
- 作用:向元素的末尾追加一个节点
- 语法2:元素.insertBefore(要插入的节点, 插入到哪个节点的前面)
- 注意:两个参数都是必填项
- 第二个参数传递正常节点时,代表插入到这个节点的前面
- 第二个参数传递的是 null 时,代表插入到 "元素"的末尾
<div>
<p>我是一个 p 标签</p>
</div>
var oDiv = document.querySelector('div')
var oP = oDiv.querySelector('p')
// 创建一个元素节点
var oSpan = document.createElement('span')
// 将这个元素节点添加到 div 下的 p 的前面
oDiv.insertBefore(oSpan, oP)
console.log(oDiv)
/**
* <div>
* <span></span>
* <p>我是一个 p 标签</p>
* </div>
*/
删除页面某一个节点
- 语法1: 父节点.removeChild(要删除的子节点)
- 语法2: 节点.remove()
<div>
<p>我是一个 p 标签</p>
</div>
var oDiv = document.querySelector('div')
var oP = oDiv.querySelector('p')
oDiv.removeChild(oP)
console.log(oDiv) // <div></div>
修改页面某一个节点
- 语法: 父节点.replaceChild(新节点,旧节点/要被修改的节点)
- 作用:将页面中的某一个节点 做一个替换
<div>
<p>我是一个 p 标签</p>
</div>
var oDiv = document.querySelector('div')
var oP = oDiv.querySelector('p')
// 创建一个 span 节点
var oSpan = document.createElement('span')
// 向 span 元素中加点文字
oSpan.innerHTML = '我是新创建的 span 标签'
// 用创建的 span 标签替换原先 div 下的 p 标签
oDiv.replaceChild(oSpan, oP)
console.log(oDiv)
/*
<div>
<span>我是新创建的 span 标签</span>
</div>
*/
克隆页面某一个节点
- 语法: 节点.cloneNode(参数)
- 参数:
- 默认是 false,表示不可隆后代节点
- 选填是 true,表示克隆后代节点
获取元素偏移量
offsetParent
- 获取元素的相对父级
- 其实就是假设你要给一个元素 绝对定位 的时候
- 它是根据谁来进行定位的, 那么这个元素的偏移量参考父级就是谁
offsetLeft / offsetTop
- 获取的是元素左边的偏移量和上边的偏移量
- offsetLeft 该元素相对于参考父级的左侧偏移量
- offsetTop 该元素相对于参考父级的上侧偏移量
获取元素尺寸(元素的占地面积)
offsetWidth 和 offsetHeight
- offsetWidth: 获取元素内容 + padding + border 的宽度
- offsetHeight: 获取元素内容 + padding + border 的高度
clientWidth 和 clientHeight
- clientWidth 获取元素内容 + padding 的宽度
- clientHeight 获取元素内容 + padding 的高度
- 注意:
- 获取到的尺寸是没有单位的数字
- 当元素在页面中不占位置的时候, 获取到的是 0
display: none元素在页面不占位visibility: hidden元素在页面占位
获取浏览器窗口尺寸
- 1.window.innerxxx -> 计算的时候 会包含浏览器的滚动条
-
- document.documentElement.clientxxx -> 计算的时候,不会计算滚动条(只计算浏览器的可视区域)
- document.documentElement.clientWidth: 浏览器可视窗口的宽度
- document.documentElement.clientHeight: 浏览器可视窗口的高度