DOM 的基本概念及操作
- DOM(Document Object Model): 文档对象模型
- 其实就是操作 html 中的标签的一些能力
- 我们可以操作哪些内容
-
添加一个div
-
删除一个li
-
修改一个ol
-
获取某一个标签的样式
-
修改某一个而标签的样式
-
给某一个标签添加事件
-
给某一个标签添加属性
-
给元素添加一些 css 样式
-
...
-
- DOM 的核心对象就是
document对象。 - document 对象是浏览器内置的一个对象,内部提供了很多属性和方法,帮我们便捷的操作页面标签。
- DOM: 页面中的标签, 我们通过 JS 获取到以后, 就把这个对象叫做 DOM 对象。
一、获取标签(元素)
- 通过 JS 代码来获取页面中的标签, 获取后我们就可以操作这些标签
1、获取非常规元素
- document.documentElement
- document.head
- document.body
// 1. html
var htmlEle = document.documentElement
console.log(htmlEle)
// 2. head
var headEle = document.head
console.log(headEle)
// 3. body
var bodyEle = document.body
console.log(bodyEle)
2、获取常规元素
- 通过 JS 代码来获取页面中的标签, 获取后我们就可以操作这些标签
1)getElementById
- getElementById 是通过标签的 ID 名称来获取标签的
- 因为页面中的 ID 是唯一的, 所以获取到的就是一个元素
<body>
<div id="box"></div>
<script>
var box = document.getElementById('box')
console.log(box) // 页面中 ID 为 box 的标签
</script>
</body>
2)getElementsByClassName
- getElementsByClassName 是通过标签的 class 名称来获取标签的
- 因为页面中可能会有多个元素的 class 名称一样, 所以获取到的是一组元素
- 哪怕页面中只有一个, 获取到的也是一组元素, 只不过这一组元素只有一个 DOM 元素
<body>
<div calss="box"></div>
<script>
var box = document.getElementsByClassName('box')
console.log(box) // [<div></div>]
console.log(box[0]) // <div></div>
</script>
</body>
- 注意!!! getElementsByClassName 是一组长得很像数组的数据解构, 但它不是数组, 我们叫这种数据结构为:
伪数组 - 这一组数据也是按照索引排列的, 所以我们想要准确的拿到这个 div, 需要用索引来获取
3)getElementsByTagName
- getElementsByTagName 是通过标签的 标签名称 来获取标签饿
- 因为页面中可能有多个元素的标签名称一样, 所以获取到的是一组元素
- 哪怕只有一个这个标签名, 获取到的也是一组数据, 只不过一组数据中只有一个 DOM 元素
<body>
<div></div>
<script>
var box = document.getElementsByTagName('div')
console.log(box) // [<div></div>]
console.log(box[0]) // <div></div>
</script>
</body>
- 和 getElementsByClassName 一样, 获取到的是一个长得很像数组的元素
- 必须要用索引才能准确地到 DOM 元素
4)querySelector('像写CSS选择器一样书写标签')
- querySelector 是按照选择器的方式来获取元素
- 也就是说, 按照我们写 css 的时候的选择器来获取
- 这个方法只能获取到一个元素, 并且是页面中第一个满足条件的元素
- 返回值:符合条件的第一个标签
console.log(document.querySelector('div')) // 获取页面中第一个 div 元素
console.log(document.querySelector('.box')) // 获取页面中第一个 有 box 类名的元素
console.log(document.querySelector('#box2')) // 获取页面中第一个 id 名为 box2 的元素
5)querySelectorAll
- querySelectorAll 是按照选择器的方式来获取元素
- 这个方法能获取到所有满足条件的元素
- 返回值:返回一个符合条件的标签组成的
伪数组- 伪数组:长得很像数组,也有下标,也有length,但是数组的方法,很多都没有.控制台打印出来数组前面有nodelist
- 获取不存在的元素,返回值是
null
console.log(document.querySelectAll('div')) // 获取页面中的所有的 div 元素
console.log(document.querySelectAll('.box')) // 获取页面中的所有的 类名为 box 的元素
- 获取到的是一组数据, 也是需要用索引来获取到准确的每一个 DOM 元素
二、获取样式
1、style
- 专门用来个元素添加 css 样式的
1)行内样式
- 语法:
元素/标签.style - 能够拿到
行内样式,或者给添加一个新的行内样式;
<div style='width:100px;height:200px;background-color:blue;'></div>
var div = document.querySelector('div')
div.style.width = '100px'
div.style.hright = '100px'
div.style['background-color] = 'pink'//能获取,但是有点麻烦
div.style.backgroundColor = 'pink'//推荐写法(驼峰命名)
2)内部样式
- 语法:
getComputedStyle('要查询样式的标签').要查询的样式名 - 非行内样式和行内样式,都能正常获取,但是获取到的值不能修改,只读
<style>
.box {
width: 200px;
height: 200px;
background-color: lightblue;
}
</style>
<div class="box"></div>
<script>
var myDiv = document.querySelector('.box')
//因为元素的样式添加在了类名上,也就是非行内的,所以style获取不到
console.log(myDiv.style.width)//' '
//getComputedStyle('要查询样式的标签').要查询的样式名
console.log(getComputedStyle(myDiv).width)//200px
console.log(getComputedStyle(myDiv).height)//200px
//非行内样式和行内样式,都能正常获取,但是获取到的值不能修改
</script>
2、制作随机背景颜色(why版本)
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
body {
background-color: red;
}
#btn {
display: block;
width: 100px;
height: 100px;
border: 0;
outline: none;
border-radius: 30px;
background-color: lightblue;
margin: 300px auto;
}
</style>
</head>
<body>
<button id="btn">点击一下换颜色</button>
<script>
function getRandom(N, M) {
return Math.floor(Math.random() * (M - N + 1) + N)
}
//十六进制颜色
// function getColor() {
// var str = "#"
// var arr = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f']
// for (var i = 1; i <= 6; i++) {
// var random = getRandom(0, 15)
// str += arr[random]
// }
// return str
// }
//rgb颜色
// function getColor() {
// var r = getRandom(0, 255)
// var g = getRandom(0, 255)
// var b = getRandom(0, 255)
// return `rgb(${r},${g},${b})`
// }
//十六进制+rgb颜色
function getColor(flag = true) {
if (flag) {
var str = "#"
var arr = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f']
for (var i = 1; i <= 6; i++) {
var random = getRandom(0, 15)
str += arr[random]
}
console.log(str)
return str
} else {
var r = getRandom(0, 255)
var g = getRandom(0, 255)
var b = getRandom(0, 255)
console.log(`rgb(${r},${g},${b})`)
return `rgb(${r},${g},${b})`
}
}
var btn = document.querySelector('#btn')
var body = document.querySelector('body')
btn.onclick = function () {
btn.style.backgroundColor = getColor()
body.style.backgroundColor = getColor()
}
// setInterval(function () {
// btn.style.backgroundColor = getColor()
// body.style.backgroundColor = getColor()
// },200)
</script>
</body>
三、操作元素类名
1、className
- 语法:
元素/标签.className=> 能够得到元素目前拥有的类名 - 还可以给这个属性重新赋值,然后修改当前标签的类名
<div class="box1">你好 2310</div>
<script>
var box = document.querySelector('.box1')
console.log(box.className)//box1
//box.className = 'box2' 当前方式,不管之前有多少类名,全部重新覆盖掉
box.className += ' box2'//类名之间一定要加 空格
console.log(box.className)
//删除类名
box.className = ''//相当于清空之前的所有类名
</script>
- 在设置的时候, 不管之前有没有类名, 都会全部被设置的值覆盖
2、classList
- 语法:
元素/标签.classList - 返回值:是一个伪数组,数组内下标对应的是每一个类名,里边的
value属性对应的是我们完整类名的字符串
<div class="box1 abc why">你好 2310</div>
<script>
var box = document.querySelector('.box1')
console.log(box.classList)
//向div这个标签里面追加一个类名box2
//原本的类名不受影响
box.classList.add('box2')
//删除指定类名
// box.classList.remove('why')
console.log(box.classList)
</script>
3、自定义弹框案例
1)课堂版本
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
* {
padding: 0;
margin: 0;
}
html,
body {
width: 100%;
height: 100%;
}
.overlay {
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.3);
position: fixed;
top: 0;
left: 0;
}
.msg_box {
width: 280px;
height: 170px;
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
background-color: aliceblue;
border-radius: 10px;
padding: 20px;
}
.msg_box p {
margin: 24px;
}
.close {
display: none;
}
.show {
display: block;
}
</style>
</head>
<body>
<!-- 点击打开弹出框 -->
<button id="show_msg_box">展示弹出框</button>
<!-- 灰色的遮罩层 -->
<div class="overlay close"></div>
<!-- 弹出层的信息展示 -->
<div class="msg_box close">
<h1>这是一个自定义弹出层</h1>
<p>广告位招租</p>
<!-- 点击关闭弹出层 -->
<button id="close_msg_box">关闭</button>
</div>
<script>
// 0. 获取标签
var showMsgBox = document.querySelector('#show_msg_box')
var closeMsgBox = document.querySelector('#close_msg_box')
var overlay = document.querySelector('.overlay') // 遮罩层
var msgBox = document.querySelector('.msg_box') // 信息框
// 添加事件
// 1. 打开弹窗框 遮罩层和弹出框的信息展示
showMsgBox.onclick = function () {
// 拿遮罩层举例, 删掉 close 添加类名 show
overlay.classList.remove('close')
overlay.classList.add('show')
// 信息框和上边的遮罩层相同
msgBox.classList.remove('close')
msgBox.classList.add('show')
}
// 2. 关闭弹出框 遮罩层和弹出框的信息隐藏
closeMsgBox.onclick = function () {
// 删掉 show, 添加 close
overlay.classList.remove('show')
overlay.classList.add('close')
msgBox.classList.remove('show')
msgBox.classList.add('close')
}
</script>
</body>
2)why版本
<style>
* {
margin: 0;
padding: 0;
}
body,
html {
height: 100%;
}
#btn1 {
width: 100px;
height: 40px;
margin-top: 20px;
border-radius: 30px;
border: 0;
outline: none;
}
#gray {
display: none;
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(127, 127, 127, 0.6);
}
#gray #son {
width: 300px;
height: 150px;
position: absolute;
top: 50%;
left: 50%;
padding-top: 20px;
transform: translate(-50%, -50%);
background-color: #fff;
text-align: center;
border-radius: 30px;
}
#gray #son h3 {
margin-bottom: 20px;
}
#gray #son p {
margin-bottom: 30px;
}
/* #gray #son #btn2 {
position: absolute;
top:130px;
left:10px;
} */
</style>
<button id="btn1">点击出现弹框</button>
<div id="gray">
<div id="son">
<h3>这是一个自定义弹出层</h3>
<p>你可以在这里添加内容</p>
<button id="btn2">关闭</button>
</div>
</div>
<script>
var gray = document.querySelector('#gray')
var son = document.querySelector('#son')
var btn1 = document.querySelector('#btn1')
var btn2 = document.querySelector('#btn2')
btn1.onclick = function () {
console.log('出现')
gray.style.display = 'block'
}
btn2.onclick = function () {
console.log('关闭')
gray.style.display = 'none'
}
</script>
四、操作元素属性
- 我们获取到元素后, 可以直接操作 DOM的属性, 然后直接把效果展示在页面上
<div class="box" why1="一个自定义属性" data_name="张三">一个普通的div</div>
var box = document.querySelector('.box')
console.log(box)
1、获取标签属性
- 语法
元素.getAttribute('属性名')
//1、获取标签属性
console.log(box.getAttribute('class'))//box
var res = box.getAttribute('why')
console.log(res)//一个自定义属性
2、设置标签属性
- 语法
元素.setAttribute('属性名','属性值')
//2、设置标签属性
box.setAttribute('whynew2', '内容bee')
3、修改标签属性
- 语法
元素.setAttribute('属性名','属性值')
//3、修改标签属性
box.setAttribute('class', 'whywhy3')
4、H5新增自定义属性
- H5自定义属性在书写的时候有一个固定的开头就是
data- - 完整语法:
data-属性名 = 属性值 - 获取的语法:
元素/标签.dataset.属性名(属性名不要带data-) - 注意点:在设置的时候,不要采用驼峰,全小写,因为就算大写了,浏览器也会转换为小写.
//4、H5新增自定义属性
//H5自定义属性在书写的时候有一个固定的开头就是data-
//完整语法:data-属性名 = 属性值
//获取的语法:元素/标签.dataset.属性名(属性名不要带data-)
//注意点:在设置的时候,不要采用驼峰,全小写,因为就算大写了,浏览器也会转换为小写
console.log(box.dataset.name)//张三
//新增
box.dataset.newname = '我是新增的属性'
5、getAttribute
- 获取元素的某个属性(包括自定义属性)
<div a="100" class="box"></div>
var div = document.querySelector('div')
console.log(div.getAttribute('a')) // 100
console.log(div.getAttribute('calss')) // box
6、setAttribute
- 给元素设置的一个属性(包括自定义属性)
<div></div>
var div = document.querySelector('div')
console.log(div.setAttribute('a', 100))
console.log(div.setAttribute('calss', box))
7、removeAttribute
- 直接移出元素的某个属性
<div a="100" class="box"></div>
var div = document.querySelector('div')
console.log(div.removeAttribute('calss'))
8、密码框案例
1)课上版本
<input type="password">
<button>点击展示/隐藏密码</button>
<script>
// 0. 获取标签
var inp = document.querySelector('input')
var btn = document.querySelector('button')
// 添加事件
btn.onclick = function () {
// console.log(inp.getAttribute('type'))
// console.dir(inp.type)
// if (inp.type === 'password') {
// inp.type = 'text'
// } else {
// inp.type = 'password'
// }
inp.type = inp.type === 'password' ? 'text' : 'password'
}
// btn.onclick = function () {
// /**
// * 逻辑:
// * 如果当前是密码框, 那么更改为 输入框
// * 如果当前是输入框, 那么更改为 密码框
// */
// // inp.setAttribute('type', 'text')
// // console.log(inp.getAttribute('type'))
// if (inp.getAttribute('type') === 'password') {
// inp.setAttribute('type', 'text')
// } else {
// inp.setAttribute('type', 'password')
// }
// }
</script>
2)why版本
<input type="password" id="input">
<button id="btn">点击展示/隐藏密码</button>
<script>
var input = document.querySelector('#input')
var btn = document.querySelector('#btn')
btn.onclick = function () {
if (input.getAttribute('type') === 'password') {
input.setAttribute('type', 'text')
} else {
input.setAttribute('type', 'password')
}
}
<script>
9、全选案例
1)课上版本
全选: <input type="checkbox" class="all_btn">
<hr>
<input type="checkbox" class="item"> 兴趣1
<input type="checkbox" class="item"> 兴趣2
<input type="checkbox" class="item"> 兴趣3
<script>
// 0. 获取标签
var allBtn = document.querySelector('.all_btn')
var items = document.querySelectorAll('.item')
// 1. 给全选按钮添加点击事件
allBtn.onclick = function () {
for (var i = 0; i < items.length; i++) {
items[i].checked = allBtn.checked
}
}
// 2. 给所有的兴趣爱好添加事件
// 因为 items 是一个伪数组, 所以不能添加点击事件, 只有页面的元素/标签 才能添加
// items.onclick = function () {}
// items[0].onclick = function () { console.log(123) }
// items[1].onclick = function () { console.log(123) }
// items[2].onclick = function () { console.log(123) }
// 因为上述的代码比较复杂, 所以可以使用 一个循环进行优化 (前提是, 这几个函数的事件是一样的, 而我们目前案例中就是相同的事件功能)
// for (var i = 0; i < items.length; i++) {
// items[i].onclick = function () {
// console.log(123)
// }
// }
// console.log(setItemChecked) // 是一个函数体
// console.log(setItemChecked()) // undefined
// 拆分代码, 进行代码的优化(可读性)
for (var i = 0; i < items.length; i++) {
items[i].onclick = setItemChecked
// items[i].onclick = setItemChecked()
}
function setItemChecked() {
// console.log('判断内部的所有兴趣有没有被选中, 如果有那么选中 全选')
// 1. 要知道现在有没有全部选中 所有兴趣
var num = 0
for (var k = 0; k < items.length; k++) {
items[k].checked && num++
}
// console.log(num, items.length, num === items.length)
// 2. 根据上边的结果, 决定是否选中 全选
allBtn.checked = num === items.length
}
// allBtn.onclick = function () {
// // console.log(allBtn.checked)
// if (allBtn.checked === true) {
// // 选中 全选按钮, 勾选所有的兴趣按钮
// // items[0].checked = true
// // items[1].checked = true
// // items[2].checked = true
// // 上边的三行代码非常麻烦, 所以可以借助一个 for 循环优化
// for (var i = 0; i < items.length; i++) {
// items[i].checked = true
// }
// } else {
// // 取消勾选 全选按钮, 那么应该 取消勾选所有的兴趣按钮
// for (var i = 0; i < items.length; i++) {
// items[i].checked = false
// }
// }
// }
</script>
2)why版本
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
* {
margin: 0;
padding: 0;
}
body {
padding-left: 30px;
}
ul li {
list-style: none;
}
</style>
</head>
<body>
<input type="checkbox" id="all">全选/全不选
<hr>
<ul class="like">
<li>
<input type="checkbox">兴趣一
</li>
<li>
<input type="checkbox">兴趣二
</li>
<li>
<input type="checkbox">兴趣三
</li>
<li>
<input type="checkbox">兴趣四
</li>
<li>
<input type="checkbox">兴趣五
</li>
</ul>
<script>
var all = document.querySelector('#all')
var lis = document.querySelectorAll('.like li input')
all.onclick = function () {
for (var i = 0; i < lis.length; i++) {
lis[i].checked = all.checked
}
}
for (var i = 0; i < lis.length; i++) {
lis[i].onclick = function () {
var count = 0
for (var j = 0; j < lis.length; j++) {
if (lis[j].checked === true) {
count++
}
if (count === lis.length) {
all.checked = true
} else {
all.checked = false
}
}
}
}
</script>
</body>
四、操作元素文本
1、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>'
2、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 解析成标签
3、value
- 专门给输入框添加展示文本
var msg = document.querySelector('#msg')
var inp = document.querySelector('#inp')
// msg.innerText = '你好'
// msg.innerHTML = '我不好'
// msg.value = '都不好' //value属性是给input输入框设置展示文本,所以设置无效
//如果想要给input输入框添加展示文本,需要借助value
inp.value = '你好 value'
4、区别
innerHTML/innerText能够给输入框之外的标签添加展示文本value专门给输入框添加展示文本innerHTML认识字符串中的标签,能够将字符串中的标签转换成真正的标签进行渲染;获取文本的时候,能够获取到元素的子集标签以及文本innerText不认识字符串中的标签;获取文本的时候,只能获取到元素的子级文本- 推荐使用
innerText能够防止用户注入恶意代码