DOM02
复习
HTML代码 会先转换成 DOM对象, 然后显示在浏览器上
- 浏览器实际显示的是 DOM对象的内容
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2d83Dvw5-1645336739306)(C:\Users\jiyx\AppData\Roaming\Typora\typora-user-images\image-20220106090217948.png)]
DOM: document object model
文档对象模型
本质是 window.document
属性, 利用此属性可以操作浏览器中的内容显示
DOM树
: 对DOM对象结构的一种称呼, 结构像树形结构
- 父元素
- 兄弟元素
DOM操作核心就两种:
- 查找要操作的元素:
- 固定元素: head, body, documentElement - html
- 按照与已知元素的关系查找
- 第一个孩子:
firstElementChild
- 最后一个孩子:
lastElementChild
- 所有孩子:
children
- 上一个兄弟:
prevElementSibling
- 下一个兄弟:
nextElementSibling
- 父:
parentElement
- 第一个孩子:
- 按照特征查找
- id:
getElementById
- id是唯一标识, 此方法的返回值 是元素本身
- class:
getElementsByClassName
- class可以同名多个, 结果是 伪数组, 用for…of遍历
- 标签:
getElementsByTagName
- name:
getElementsByName
- id:
- 利用css选择器查找
- 查单个:
querySelector
- 返回值 是元素本身
- 查多个:
querySelectorAll
- 返回值是伪数组类型, 但是原型中有借用的 forEach方法可以遍历
- 查单个:
- 对元素属性进行操作
- style: 内联样式
- class
- className: 简单的修改 class的值, 是字符串
- classList: 优雅
- add: 添加
- remove: 删除
- toggle: 切换
- 事件: 都是
on
开头- onclick: 点击
- onmouseover: 鼠标悬浮
作业1
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
<style>
.menu {
background-color: #f2f5f6;
padding: 10px;
user-select: none;
}
.menu > span {
width: 100px;
height: 40px;
color: #777;
text-align: center;
line-height: 40px;
display: inline-block;
background-color: white;
border-radius: 20px;
margin-right: 5px;
border: 1px solid #eee;
}
.menu > .cur {
background-color: #ff5d23;
color: white;
border-color: #ff5d23;
}
/* not:排除 */
.menu > span:not(.cur):hover {
border-color: #ff5d23;
color: #ff5d23;
}
</style>
</head>
<body>
<div class="menu">
<span class="cur">推荐分类</span>
<span>网游竞技</span>
<span>单机热游</span>
<span>手游休闲</span>
<span>娱乐天地</span>
<span>颜值</span>
</div>
<script>
// 如果不写bind, qsa调用时, this指向window
// 简化
const qsa = document.querySelectorAll.bind(document)
// doc 回车 .qus 回车 .b 回车 (doc 回车
const qs = document.querySelector.bind(document)
// 查找 class='menu' 下的所有span标签
qsa('.menu span').forEach(value => {
value.onclick = function () {
qs('.menu .cur').classList.remove('cur')
this.classList.add('cur')
}
})
</script>
</body>
</html>
作业2
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
<style>
.tab {
user-select: none;
}
.tab > span {
padding: 8px;
background-color: #eee;
float: left;
border: 1px solid #aaa;
}
.tab > .cur {
background-color: white;
border-bottom-color: white;
}
</style>
</head>
<body>
<div class="tab">
<span class="cur">今日点数</span>
<span>本周点数</span>
<span>贵宾(746)</span>
<span>钻粉(0)</span>
</div>
<script>
let tabs = document.querySelectorAll('.tab>span')
tabs.forEach(tab => {
tab.onclick = function () {
document.querySelector('.tab>.cur').classList.remove('cur')
this.classList.add('cur')
}
})
</script>
</body>
</html>
change事件
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
<style>
.btn {
width: 300px;
display: inline-block;
padding: 6px 0;
text-align: center;
color: white;
background-color: #72b134;
border-radius: 4px;
user-select: none;
transition: 0.25s;
}
.btn:not(.disabled):hover {
opacity: 0.8;
}
.btn.disabled {
background-color: #bbb;
}
</style>
</head>
<body>
<div>
<!-- label: 子元素中的文本 在点击后, 也能触发勾选 -->
<label>
<input type="checkbox" />
<span>我已阅读并同意用户注册协议</span>
</label>
<div class="btn disabled">提交注册</div>
</div>
<script>
// 获取 checkbox 元素
let chb = document.getElementsByTagName('input')[0]
// 监听 变化: change:变化 点击->触发了变化
chb.onchange = function () {
console.dir(this); // 查看checked属性
//checked 属性: 代表勾选框的勾选状态
console.dir(this.checked)
// 勾选框的父元素的下方的元素
const btn = this.parentElement.nextElementSibling
// 勾选 ? 真-移除不可用 : 假-添加不可用
this.checked
? btn.classList.remove('disabled')
: btn.classList.add('disabled')
}
// 根据勾选状态, 切换 按钮的disabled 样式
</script>
</body>
</html>
输入框事件
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body>
<div>
<input type="text" />
</div>
<script>
const inp = document.getElementsByTagName('input')[0]
//获的焦点: 点击后光标闪烁时
inp.onfocus = function () {
console.log('获得焦点')
}
// 失去焦点
inp.onblur = function () {
console.log('失去焦点')
}
// 内容变更事件: change
// 触发: 修改其内容->失去焦点后 触发
inp.onchange = function () {
console.log('内容变更')
}
// 内容变更的实时监听:
inp.oninput = function () {
// 输入框的 value属性 保存输入框的值
console.log(this.value)
}
// 键盘事件有3个: 按下,抬起,整个过程
// keyup: 按键抬起
inp.onkeyup = function (e) {
// 所有通过事件触发的函数, 都会接受一个默认参数
// 形参名随意, 但是 event 是事件的意思, 习惯叫event, 偷懒写: e
// console.log(arguments)
console.log('e:', e)
console.log('按键抬起')
// 回车: keyCode -- 13
if (e.keyCode == 13) {
console.log('回车操作')
}
}
</script>
</body>
</html>
手机号验证(XXX)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
<style>
.err {
color: red;
}
.hidden {
display: none;
}
</style>
</head>
<body>
<div>
<div>
<span>手机号</span>
<input type="text" />
</div>
<div class="err hidden">手机号格式不正确</div>
</div>
<script>
const inp = document.getElementsByTagName('input')[0]
// blur: 失去焦点
inp.onblur = function () {
// this.value: 输入框的值
const reg_phone = /^1[3-9]\d{9}$/
// 判断手机号格式是否合法, 决定 hidden样式的去留
const err = this.parentElement.nextElementSibling
if (reg_phone.test(this.value)) {
err.classList.add('hidden')
} else {
err.classList.remove('hidden')
}
}
// 当输入框获取焦点时: onfocus, 隐藏 err 提示
// 对象.属性名: 这就是读操作, this.value 就是读
inp.onfocus = function () {
this.parentElement.nextElementSibling.classList.add('hidden')
}
</script>
</body>
</html>
实时验证
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
<style>
.pwd > div:last-child {
display: inline-block;
background-color: rgba(0, 0, 0, 0.5);
padding: 9px;
border-radius: 4px;
margin-top: 10px;
color: white;
}
.err {
color: red;
}
.hidden {
display: none !important;
}
</style>
</head>
<body>
<div class="pwd">
<div>
<span>密码:</span>
<input type="password" />
</div>
<div class="hidden">
<div>长度为8~14个字符</div>
<div>字母/数字以及标点符号至少包含2种</div>
<div>不允许有空格,中文</div>
</div>
</div>
<script>
let inp = document.getElementsByTagName('input')[0]
// 1. 输入框获得焦点时 - 把提示框的 hidden样式删除
inp.onfocus = function () {
this.parentElement.nextElementSibling.classList.remove('hidden')
}
// 2. 输入框失去焦点时 - 把提示框的 hidden样式添加
inp.onblur = function () {
document.querySelector('.pwd>div:last-child').classList.add('hidden')
}
// 3. 监听输入框的实时变化: oninput
inp.oninput = function () {
// 数组解构: const [a,b,c] = [11,22,33]
const [c1, c2, c3] = this.parentElement.nextElementSibling.children
//1.长度
const len = this.value.length
if (len >= 8 && len <= 14) {
c1.classList.remove('err')
} else {
c1.classList.add('err')
}
// 2. 不能有中文/空格
// \s:空白字符 |是或 [...] 是匹配中文
if (this.value.match(/\s|[\u4e00-\u9fa5]/)) {
c3.classList.add('err')
} else {
c3.classList.remove('err')
}
// 2. 数字 字母 标点符号: 至少有2种
// 储备: 数学运算中 true->1 false->0
const hasNum = this.value.match(/\d/)
const hasLetter = this.value.match(/[a-z]/i)
// [] 代表其中元素任意一个
const hasP = this.value.match(/[!@#$%^&*,.';"]/)
console.log(hasP)
// match的返回值是 数组类型 或 null
// 此处需要用 Boolean() 强转布尔类型
const res = Boolean(hasNum) + Boolean(hasLetter) + Boolean(hasP)
res >= 2 ? c2.classList.remove('err') : c2.classList.add('err')
}
</script>
</body>
</html>
属性读取
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body>
<a href="http://tmooc.cn" id="a1" title="Tmooc">Go To Tmooc</a>
<script>
const a = document.getElementsByTagName('a')[0]
console.dir(a) //查看 其中的各种属性
// 标签所有的系统属性 都可以直接读取
console.log(a.id)
console.log(a.href)
console.log(a.title)
// 修改
a.href = 'http://www.baidu.com'
a.title = '百度一下'
// 早期版本中, 提供函数方式来读取属性/修改属性
// get获取 Attribute属性 : 现在用的少
console.log(a.getAttribute('title'))
//改: set:设置
a.setAttribute('title', 'Tmooc 我又来了')
// 判断是否存在某个属性:
console.log(a.hasAttribute('target')) //true代表有
// 新语法中, 不存在的属性,默认值是空字符串
console.log(a.target == '')
</script>
</body>
</html>
自定义属性
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body>
<!-- 标签的属性分两种: 系统属性 和 自定义属性 -->
<!-- 自定义属性: 格式要求 data-属性名 -->
<div id="d1" data-a="AA" data-b="BB">Hello</div>
<script>
const d1 = document.getElementById('d1')
// dataset 属性: 固定的 用于存储自定义属性
console.dir(d1) // 查看 dataset 属性
// 新语法
console.log(d1.dataset.a)
console.log(d1.dataset.b)
// 旧语法
console.log(d1.getAttribute('data-a'))
</script>
</body>
</html>
大小图切换
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
<style>
.box > img {
width: 500px;
}
.box > div > img {
width: 121px;
/* 边框盒子: 宽度=边框+内边距+内容 */
box-sizing: border-box;
}
.box > div > img:hover,
.box > div > img.cur {
border: 2px solid red;
}
</style>
</head>
<body>
<div class="box">
<img src="./images/1-l.jpg" alt="" />
<div>
<!-- 为每一个小图增加一个自定义属性, 保存对应的大图的名字 -->
<img data-big="1-l.jpg" class="cur" src="./images/1.jpg" alt="" />
<img data-big="2-l.jpg" src="./images/2.jpg" alt="" />
<img data-big="3-l.jpg" src="./images/3.jpg" alt="" />
<img data-big="4-l.jpg" src="./images/4.jpg" alt="" />
</div>
</div>
<script>
// 任务1: 鼠标悬浮小图, 切换 cur 这个class 给悬浮项
// 事件: onmouseover
const imgs = document.querySelectorAll('.box>div>img')
/*
1. 查询出所有小图
2. 遍历小图,挨个添加mouseover事件
3. 事件出发后,找到当前cur,删除其样式,为当前项添加cur
*/
imgs.forEach(img => {
img.onmouseover = function () {
document.querySelector('.box .cur').classList.remove('cur')
this.classList.add('cur')
// 读取自定义的 data-big 属性
console.log(this.dataset.big)
//const { big } = this.dataset //对象解构
const big = this.dataset.big;
const big_img = document.querySelector('.box>img')
// 拼接出 全路径
big_img.src = './images/' + big
}
})
</script>
</body>
</html>
标签栏切换
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
<style>
.tab {
display: inline-block;
user-select: none;
}
.tab > div:first-child {
border-bottom: 2px solid #e01222;
display: flex;
}
.tab > div:first-child > span {
font-weight: bold;
padding: 10px;
}
.tab > div:first-child > span.cur {
background-color: #e01222;
color: white;
}
.tab > div:last-child > div {
height: 200px;
display: none;
}
.tab > div:last-child > div.show {
display: block;
}
.tab #tab1 {
background-color: #e01222;
}
.tab #tab2 {
background-color: deeppink;
}
.tab #tab3 {
background-color: deepskyblue;
}
.tab #tab4 {
background-color: darkred;
}
</style>
</head>
<body>
<div class="tab">
<div>
<span data-id="tab1" class="cur">京东秒杀</span>
<span data-id="tab2">每日特价</span>
<span data-id="tab3">品牌秒杀</span>
<span data-id="tab4">品类秒杀</span>
</div>
<div>
<div id="tab1" class="show">京东秒杀...</div>
<div id="tab2">今日特价...</div>
<div id="tab3">品牌秒杀...</div>
<div id="tab4">品类秒杀...</div>
</div>
</div>
<script>
const titles = document.querySelectorAll('.tab>div:first-child>span')
titles.forEach(title => {
title.onclick = function () {
document.querySelector('.tab .cur').classList.remove('cur')
this.classList.add('cur')
// 移除之前 show
document.querySelector('.tab .show').classList.remove('show')
// 从自定义属性 dataset 中解构出 id
//const { id } = this.dataset
const id = this.dataset.id;
// 通过id查找到对应的元素
document.getElementById(id).classList.add('show')
}
})
</script>
</body>
</html>
事件冒泡机制
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
<style>
#red {
background-color: red;
width: 300px;
height: 300px;
}
#blue {
background-color: blue;
width: 200px;
height: 200px;
}
/* 多光标模式: alt+左键 , 按ESC退出此模式*/
#green {
background-color: green;
width: 100px;
height: 100px;
}
</style>
</head>
<body>
<!-- 事件冒泡机制: -->
<!-- 子元素触发一个事件后, 会通知给其所有的祖先元素, 这是浏览器自带的效果, 称为冒泡机制 -->
<!-- 类似: 泽权 -> 暴打了 高达 -> 高达会告诉他爸被打了.. -> 告诉他爷爷被打了 -> 祖爷爷自己被打了.. -->
<div id="red">
<div id="blue">
<div id="green"></div>
</div>
</div>
<script>
// 绿(子) 蓝(父) 红(祖父)
// 冒泡机制: 子元素发生事件 -> 会通知所有祖先元素
// id 属性可以直接用 id='red'
red.onclick = function (e) {
// 参数e: 保存了事件有关的各种信息
// 其中 的target属性, 代表具体是哪个元素触发的事件
console.log('target:', e.target)
console.log('red侦测到点击事件')
}
blue.onclick = function () {
console.log('blue侦测到点击事件')
}
green.onclick = function () {
console.log('green侦测到点击事件')
}
</script>
</body>
</html>
事件委托
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
<style>
.indicator {
padding: 10px;
background-color: lightgray;
user-select: none;
}
.indicator > span {
display: inline-block;
width: 16px;
height: 16px;
background-color: white;
transition: 0.25s;
}
.indicator > .cur {
background-color: aqua;
border-radius: 50%;
}
</style>
</head>
<body>
<!-- 冒泡机制的应用场景: 事件委托 -->
<!--
工作时 -- 报销流程非常繁琐:
方式1: 教会每个工作人员报销流程
方式2: 1个负责人会报销流程: 其他人报销让其帮忙即可
------- 这个负责人就是委托人, 代理人..
在代码中:
以前: 遍历元素 挨个添加事件
现在: 让父元素来处理子元素的事件, 父元素就是 代理人
-->
<div class="indicator">
<span class="cur"></span>
<span></span>
<span></span>
<span></span>
</div>
<script>
// 根据冒泡机制: 任意子元素悬浮事件, 都会触发父元素的相同事件
const ind = document.getElementsByClassName('indicator')[0]
ind.onmouseover = function (e) {
// 注意事项: 所有子元素+当前元素自身都能触发事件, 所以一定要用 if判断进行过滤, 找到你想要的
// target: 触发事件的元素
// console.log('target:', e.target)
if (e.target.localName == 'span') {
console.log('target:', e.target)
console.dir(e.target)
document.querySelector('.cur').classList.remove('cur')
//为当前项添加 cur 样式
// this: 指向函数运行时所在的对象, 此处是父元素
// target: 才是触发事件的元素
e.target.classList.add('cur')
}
}
</script>
</body>
</html>
练习 - 分页
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-QceLgdZV-1645336739310)(DOM02.assets/image-20220106180557698.png)]
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
<style>
.pages {
background-color: lightgray;
padding: 5px;
width: 400px;
text-align: center;
user-select: none;
}
.pages > span {
display: inline-block;
width: 30px;
height: 30px;
line-height: 30px;
background-color: white;
color: deepskyblue;
border-radius: 4px;
}
.pages > span:hover,
.pages > span.cur {
color: white;
background-color: deepskyblue;
}
</style>
</head>
<body>
<div class="pages">
<span class="cur">1</span>
<span>2</span>
<span>3</span>
<span>4</span>
<span>5</span>
</div>
<script>
//要求:用委托方式实现
/*
1. 先添加基本的css样式
2. 为pages添加点击事件
3. 利用事件的target,用if过滤出span元素出发
4. 移除cur 样式
5. 为当前点击元素 添加cur样式
*/
const page = document.getElementsByClassName('pages')[0];
console.log(page);
page.onclick=function(e){
if(e.target.localName=='span'){
document.querySelector('.cur').classList.remove('cur')
e.target.classList.add('cur');
}
}
</script>
</body>
</html>
小总结
当为多个子元素添加事件时, 有两种方式
- 找到所有的子元素, 进行遍历, 挨个添加事件
- 利用冒泡机制, 只给父元素添加事件, 让父元素来监听子元素触发的事件然后做事 –
委托
晚上作业
把今天的各种练习, 尝试用委托方式来实现
明天: 购物车的制作, 操作标签内容之类…