第三阶段的重点: 使用JS
来操作浏览器
- JSCORE: 加深JS的基础 并且 进行了提升 – 一些ES6的语法
- DOM:
Document Object Model
– 文档对象模型
比如:
在餐馆中点菜: 在菜单上选中一个文本: 水煮鱼; 炒鸡蛋; ...
- 隐藏的中间环节:
厨师帮你把菜 从原材料 做成 菜肴...
后期: 服务员会端上菜品
学习DOM: 类似于从
顾客
变身成厨子
: 拥有更高的权限 来决定菜品
的样式
概念: DOM树
把HTML文本代码 转换成 JS的对象类型 后的结构, 描述为 树形结构 -DOM树
- 每个元素下都
可以
有自己的子元素 –开枝散叶
; 此结构用图形表示 就像一棵树一样, 形象的比喻成DOM树
- 这颗树上的每个元素, 称为
节点
,元素节点
– node节点
初体验
<!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>你好,DOM</title>
</head>
<body>
<h1>Hello DOM</h1>
<a href="http://tmooc.cn">Tmooc</a>
<ul>
<li>泡泡</li>
<li>亮亮</li>
</ul>
<script>
//相当于厨房: 所有做菜的材料都在这里
// 浏览器后台中的 element/元素 展示的就是 document 对象
console.log(window) //找到 document 属性
// log: 会美化打印结果 -- 看到的并非对象本身
console.log(document)
// dir: 直接输出 看本质
console.dir(document)
// 初体验: DOM的特点是 可以用JS来操作, JS拥有丰富的逻辑
// 例如: 实时在标题栏显示当前时间
// 每隔参数2 的时间--单位ms 毫秒; 执行参数1的函数
setInterval(() => {
const now = new Date().toLocaleTimeString()
console.log('now:', now)
// 当前时间 赋值给 标题栏
document.title = now
}, 1000); // 1000ms = 1s
const now = new Date().toLocaleTimeString()
console.log('now:', now)
// 当前时间 赋值给 标题栏
document.title = now
</script>
</body>
</html>
class
<!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>class 09:44</title>
<!--
样式重置: 浏览器的品牌非常多, 不同的浏览器对于同一个标签 会有不同的样式呈现, 如果采用默认的标签样式 会导致网站在不同浏览器上出现不同的样式差异
解决: 在制作网站时, 需要一个统一的样式重置文件, 设置css样式
-->
<link rel="stylesheet" href="./reset.css">
<style>
ul {
display: flex;
}
ul>li {
margin: 0 5px;
color: #777;
background-color: #eee;
font-weight: bold;
padding: 5px 15px;
/* 超过 1半的高, 就是圆角矩形, 尽量大些即可 */
border-radius: 100px;
}
/* :hover 伪类选择器 -- 伪类 - 假的class选择器 */
/* 相当于: 当鼠标悬浮时添加了 .hover; 鼠标离开时自动删除了.hover */
/* 这是浏览器提供的一个 全自动的操作 -- 便于用户使用 */
ul>li:hover {
color: white;
background-color: #f65536;
}
/* 多个选择器联合书写: 代表同时具有 */
/* li标签, 同时带有 class=suibian */
li.suibian {
color: white;
background-color: #f65536;
}
</style>
</head>
<body>
<!-- <button>Hello</button> -->
<ul>
<!-- active:激活的,活动的 -->
<li class="suibian">早餐</li>
<li>午餐</li>
<li>下午茶</li>
<li>晚餐</li>
<li>夜宵</li>
</ul>
<script>
// DOM的核心操作只有两个:
// 1. 先找到要操作的元素
// 2. 对元素进行操作
console.dir(document)
// 方法: querySelectorAll(css选择器)
// 辅助 快速查找到 选择器指定的元素们
// 技巧: qsa 出提示
const lis = document.querySelectorAll('li')
console.log(lis);
// 返回值的原型是 NodeList.prototype, 属于伪数组
// 但是原型中提供了 forEach 方法, 可以快速遍历
lis.forEach((value, index, array) => {
console.log(index, value)
console.dir(value) //查看元素的具体组成
// 一个元素实际上由非常多的属性组成
// 其中 on 开头的属性, 都是事件相关
// https://www.runoob.com/jsref/dom-obj-event.html
// onclick: 鼠标点击时触发
value.onclick = function () {
// this: onclick所在的对象, 在哪个li元素 就是哪个
console.log(this, '被点击了!');
// 点击时, 为点击的元素 的 class = 'suibian'
this.className = 'suibian'
}
})
</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>练习 11:05</title>
<link rel="stylesheet" href="./reset.css">
<style>
li {
background-color: #eee;
padding: 10px;
margin: 3px;
width: 100px;
}
/* 注意: 这是自定义的active, 不是 :active这个伪类 */
li.active {
background-color: orange;
}
</style>
</head>
<body>
<h2>选择今日的午餐</h2>
<ul>
<li>羊汤泡馍</li>
<li>酸辣粉</li>
<li>炒饭</li>
<li>麻辣烫</li>
</ul>
<script>
const lis = document.querySelectorAll('li')
lis.forEach(li => {
li.onclick = function () {
li.className = 'active'
// this.className = 'active'
}
})
</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>练习 11:36</title>
<link rel="stylesheet" href="./reset.css">
<style>
li {
/* 用户-选择文本: 不能 */
user-select: none;
width: 100px;
padding: 10px;
background-color: #eee;
margin-bottom: 4px;
transition: 0.3s;
border-radius: 100px;
}
li.active {
background-color: orange;
padding-left: 40px;
}
</style>
</head>
<body>
<h1>选择你的特长:</h1>
<ul>
<li class="active">唱歌</li>
<li>跳舞</li>
<li>打篮球</li>
<li>踢足球</li>
</ul>
<script>
const lis = document.querySelectorAll('li')
lis.forEach(li => {
li.onclick = function () {
const ac = document.querySelector('li.active')
ac.classList.remove('active')
// 切换效果: 有就删除, 没有就添加
// 由于切换效果非常常用, 所以DOM直接封装成了方法, 可以直接用
console.dir(li) // 找 classList 属性
// classList: 相当于菜谱 -- 记录一些做菜的方法
// 存储了一些操作class的方法, 可以直接用
// toggle: 用于切换class
li.classList.toggle('active')
// if (li.className == '') {
// li.className = 'active'
// } else {
// li.className = ''
// }
}
})
</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>only 单个激活 14:01</title>
<link rel="stylesheet" href="./reset.css">
<style>
li {
padding: 10px 0;
user-select: none;
cursor: pointer;
}
li.active {
color: red;
/* 鼠标指针事件们: 无 */
pointer-events: none;
/* 已激活的项目, 不能再次激活 */
}
</style>
</head>
<body>
<ul>
<li class="active">个人信息</li>
<li>我的订单</li>
<li>收货地址</li>
<li>我的购物车</li>
<li>账户安全</li>
<li>退出</li>
</ul>
<script>
// 带 All : 查询一堆, 结果是伪数组 多个元素
const lis = document.querySelectorAll('li')
console.dir(lis)
lis.forEach(li => li.onclick = function () {
// 唯一性: 添加高亮前, 先找到之前高亮的, 删掉其高亮
// 不带 All : 查一个满足条件的
const ac = document.querySelector('li.active')
console.dir(ac)
ac.classList.remove('active') //remove:删除class
li.classList.add('active')
})
</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>练习 14:38</title>
<link rel="stylesheet" href="./reset.css">
<style>
ul {
background-color: #002c69;
padding: 0 20px;
display: flex;
}
li {
padding: 10px 25px;
color: white;
white-space: nowrap;
user-select: none;
}
li.active {
background-color: orange;
pointer-events: none;
}
</style>
</head>
<body>
<ul>
<li class="active">首页</li>
<li>关于净美仕</li>
<li>公司动态</li>
<li>产品中心</li>
<li>联系我们</li>
</ul>
<script>
const lis = document.querySelectorAll('li')
lis.forEach(li => li.onclick = function () {
// 做法1: 找到之前高亮的, 删除其高亮
// const ac = document.querySelector('li.active')
// ac.classList.remove('active')
// 做法2: 遍历所有的li, 挨个删除样式
lis.forEach(li => li.classList.remove('active'))
li.classList.add('active')
})
</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>下拉菜单 15:16</title>
<link rel="stylesheet" href="./reset.css">
<style>
#box {
background-color: #f9f9fb;
border: 1px solid #cdcdcd;
padding: 5px;
/* 子绝父相 */
position: relative;
}
#box>ul {
padding: 20px;
border: 1px solid #ccc;
position: absolute;
border-radius: 4px;
background-color: #f9f9fb;
/* calc(): 可以计算, 支持 + - * / */
/* 注意!! 计算符号左右必须有空格, 否则无法识别 */
top: calc(100% + 5px);
}
#box li {
/* 上 右 下 左 : 顺时针 */
padding: 5px 20px 5px 5px;
cursor: pointer;
}
#box li:hover {
background-color: #ddd;
}
#box>button {
padding: 5px;
font-weight: bold;
/* rem:相对于根元素的字体大小, 即html的 */
font-size: 1rem;
border-radius: 4px;
}
#box>button:hover {
background-color: #cdcdcd;
}
#box>ul.hide {
display: none;
}
</style>
</head>
<body>
<!--
网页上大多数 在用户操作后 有样式变化的都是通过操作class实现
-->
<!-- 把所有要显示的元素都书写出来 -->
<div id="box">
<button>中文(简体)</button>
<ul class="hide">
<li>English</li>
<li>日本语</li>
<li>韩语</li>
<li>中文(简体)</li>
</ul>
</div>
<script>
// 当点击按钮时, 切换 ul 标签的 .hide 样式
const btn = document.querySelector('button')
console.log('btn', btn)
btn.onclick = function () {
// 目标: 找到ul标签, 修改其class
// 查询方案1: 利用css 全局查找 -- 查询范围大,效率低
// 查询方案2: 与已知元素的关系查, 例如 兄弟 父子
// next:下一个 element:元素 sibling:兄弟姐妹
const ul = btn.nextElementSibling
console.log('ul', ul)
ul.classList.toggle('hide') //切换 hide
}
// 点击选项后: 让按钮上的文本变化成对应的文字 并且 隐藏ul
const lis = document.querySelectorAll('#box li')
lis.forEach(li => li.onclick = function () {
console.dir(this) // 查看哪个属性上存放的是文本
// innerHTML 或 innerText :存储的是标签中的文字
btn.innerHTML = this.innerHTML
// 按钮.文本 = 点击项.文本
// ul 是 li 的父元素 parent:父母
const ul = this.parentElement
console.log('ul', ul)
ul.classList.add('hide')
})
</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>练习 16:25</title>
<link rel="stylesheet" href="./reset.css">
<style>
#box {
width: 300px;
user-select: none;
}
#box>div {
background-color: #ddd;
color: red;
padding: 10px;
cursor: pointer;
}
#box>ul {
background-color: green;
padding: 10px;
transition: 0.4s;
height: 180px;
overflow: hidden;
}
#box li {
color: black;
padding: 10px 0;
}
#box>ul.hide {
/* display: none; */
height: 0;
/* overflow: hidden; */
padding-top: 0;
padding-bottom: 0;
}
</style>
</head>
<body>
<h2>您的选择是: <b>??</b></h2>
<div id="box">
<div id="title">点击查看菜单</div>
<ul class="hide">
<li>羊汤</li>
<li>麻辣烫</li>
<li>水煮鱼</li>
<li>辣子鸡丁</li>
</ul>
</div>
<script>
const title = document.querySelector('#title')
title.onclick = function () {
this.nextElementSibling.classList.toggle('hide')
}
const lis = document.querySelectorAll('#box li')
const b = document.querySelector('b')
lis.forEach(li => li.onclick = function () {
// 不要在这里查b: 每次点击都查一次, 浪费性能
b.innerHTML = this.innerHTML
this.parentElement.classList.add('hide')
})
</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>练习 17:17</title>
<link rel="stylesheet" href="./reset.css">
<style>
#box div {
width: 400px;
/* 背景图的大小: cover - 保持横纵比, 覆盖满整个元素 */
background-size: cover;
margin-bottom: 5px;
height: 50px;
transition: 0.3s;
border-radius: 4px;
}
#box div.active {
height: 184px;
}
</style>
</head>
<body>
<div id="box">
<div style="background-image: url('./imgs/bigskin-1.jpg');"></div>
<div style="background-image: url('./imgs/bigskin-2.jpg');"></div>
<div style="background-image: url('./imgs/bigskin-3.jpg');"></div>
<div style="background-image: url('./imgs/bigskin-4.jpg');"></div>
<div style="background-image: url('./imgs/bigskin-5.jpg');"></div>
<!-- <img src="./imgs/bigskin-1.jpg" alt="">
<img src="./imgs/bigskin-2.jpg" alt="">
<img src="./imgs/bigskin-3.jpg" alt="">
<img src="./imgs/bigskin-4.jpg" alt="">
<img src="./imgs/bigskin-5.jpg" alt=""> -->
</div>
<script>
const imgs = document.querySelectorAll('#box div')
imgs.forEach(img => img.onclick = function () {
// 遍历删除每个的激活
imgs.forEach(img => img.classList.remove('active'))
// 为当前点击项添加激活
this.classList.add('active')
})
</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>练习 17:42</title>
<link rel="stylesheet" href="./reset.css" />
<style>
#box {
display: flex;
}
#box div {
/* 关闭弹性盒子的自动缩放功能 */
flex: none;
width: 60px;
background-size: cover;
margin-right: 5px;
height: 184px;
transition: 0.3s;
border-radius: 4px;
}
#box div.active {
width: 400px;
}
</style>
</head>
<body>
<div id="box">
<div style="background-image: url('./imgs/bigskin-1.jpg')"></div>
<div style="background-image: url('./imgs/bigskin-2.jpg')"></div>
<div style="background-image: url('./imgs/bigskin-3.jpg')"></div>
<div style="background-image: url('./imgs/bigskin-4.jpg')"></div>
<div style="background-image: url('./imgs/bigskin-5.jpg')"></div>
</div>
<script>
const imgs = document.querySelectorAll('#box div')
imgs.forEach(
img =>
(img.onclick = function () {
imgs.forEach(img => img.classList.remove('active'))
this.classList.add('active')
})
)
</script>
</body>
</html>
总结
DOM: Document Object Model
- 文档对象模型
- HTML: 提供了一些官方的
有限的
效果 – 不满足实际开发的需求 - DOM: 深层次的, 利用JS来
灵活
实现任何的效果 – 自定义特效
核心知识点:
- document对象: 此对象中包含操作页面元素的所有API
- 查找元素的方式:
- 依赖css选择器全局查找
- querySelector: 查询单个元素
- querySelectorAll: 查询多个元素
- 依赖关系
- 父: parentElement
- 子: ??
- 兄: ??
- 弟: nextElementSibling
- 依赖css选择器全局查找
- 事件相关:
on
开头的属性- onclick: 点击事件
- 样式相关:
- class
- className: 就是 class 属性本身
- classList: 一个集合, 存放了很多操作class的方法, 更加易用
- add : 添加
- remove: 移除
- toggle: 切换
- class