目标:
- 掌握节点(标签)的增删改查
- 具备编写微博发布案例的能力
1. 节点操作
1.1 DOM 节点
-
目标:能说出DOM节点的类型
-
DOM节点:DOM树里每一个内容都称之为节点。
-
网页中的所有内容都是节点(标签、属性、文本、注释等),在DOM中,节点使用node来表示。
-
HTML DOM树中的所有节点均可通过JavaScript进行访问,所有HTML元素(节点)均可被修改,也可以创建或删除。
-
一般地,节点至少拥有nodeType(节点类型)、nodeName(节点名称)和nodeValue(节点值)这三个基本属性。
1.1.1 节点类型:
1.1.2 节点层级
利用DOM树可以把节点划分为不同的层级关系,常见的是父子兄层级关系。
1.2 查找节点
目标:能够具备根据节点关系查找目标节点的能力
关闭二维码案例:
点击关闭按钮, 关闭的是二维码的盒子, 还要获取erweima盒子
1.2.1 父节点查找
- parentNode 属性
- 返回最近一级的父节点 ,找不到返回为null
<!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 class="father">
<div class="son">儿子</div>
</div>
<script>
let son = document.querySelector('.son')
// 找爸爸
console.log(son.parentNode)
</script>
</body>
</html>
案例:关闭二维码案例
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
* {
margin: 0;
padding: 0;
}
.erweima {
position: relative;
width: 160px;
height: 160px;
margin: 100px auto;
border: 1px solid #ccc;
}
.erweima i {
position: absolute;
left: -13px;
top: 0;
width: 10px;
height: 10px;
border: 1px solid #ccc;
font-size: 12px;
line-height: 10px;
color: #ccc;
font-style: normal;
cursor: pointer;
}
</style>
</head>
<body>
<div class="erweima">
<img src="./images/code.png" alt="">
<i class="close_btn">x</i>
</div>
<script>
// 1. 获取元素 事件源 i 关闭的 erweima
let close_btn = document.querySelector('.close_btn')
let erweima = document.querySelector('.erweima')
// 2. 事件监听
close_btn.addEventListener('click', function () {
// erweima 关闭 他是隐藏的
erweima.style.display = 'none'
})
</script>
</body>
</html>
案例:关闭多个二维码案例
需求:多个二维码,点击谁,谁关闭
分析:
①:需要给多个按钮绑定点击事件
②:关闭的是当前的父节点
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
<style>
.erweima {
width: 149px;
height: 152px;
border: 1px solid #000;
background: url(./images/456.png) no-repeat;
position: relative;
}
.close {
position: absolute;
right: -52px;
top: -1px;
width: 50px;
height: 50px;
background: url(./images/bgs.png) no-repeat -159px -102px;
cursor: pointer;
border: 1px solid #000;
}
</style>
</head>
<body>
<div class="erweima">
<span class="close"></span>
</div>
<div class="erweima">
<span class="close"></span>
</div>
<div class="erweima">
<span class="close"></span>
</div>
<div class="erweima">
<span class="close"></span>
</div>
<div class="erweima">
<span class="close"></span>
</div>
<script>
// 1. 获取元素 关闭按钮
let close_btn = document.querySelectorAll('.close')
// 2. 绑定多个点击事件给close
for (let i = 0; i < close_btn.length; i++) {
close_btn[i].addEventListener('click', function () {
// 3. 关闭当前的那个二维码 点击谁,就关闭谁的爸爸
this.parentNode.style.visibility = 'hidden'
})
}
</script>
</body>
</html>
1.2.2 子节点查找
1.2.3 案例:新浪下拉菜单
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<style>
* {
margin: 0;
padding: 0;
}
li {
list-style-type: none;
}
a {
text-decoration: none;
font-size: 14px;
}
.nav {
margin: 100px;
}
.nav>li {
position: relative;
float: left;
width: 80px;
height: 41px;
text-align: center;
}
.nav li a {
display: block;
width: 100%;
height: 100%;
line-height: 41px;
color: #333;
}
.nav>li>a:hover {
background-color: #eee;
}
.nav ul {
display: none;
position: absolute;
top: 41px;
left: 0;
width: 100%;
border-left: 1px solid #FECC5B;
border-right: 1px solid #FECC5B;
}
.nav ul li {
border-bottom: 1px solid #FECC5B;
}
.nav ul li a:hover {
background-color: #FFF5DA;
}
</style>
</head>
<body>
<ul class="nav">
<li>
<a href="#">微博</a>
<ul>
<li>
<a href="">私信</a>
</li>
<li>
<a href="">评论</a>
</li>
<li>
<a href="">@我</a>
</li>
</ul>
</li>
<li>
<a href="#">微博</a>
<ul>
<li>
<a href="">私信</a>
</li>
<li>
<a href="">评论</a>
</li>
<li>
<a href="">@我</a>
</li>
</ul>
</li>
<li>
<a href="#">微博</a>
<ul>
<li>
<a href="">私信</a>
</li>
<li>
<a href="">评论</a>
</li>
<li>
<a href="">@我</a>
</li>
</ul>
</li>
<li>
<a href="#">微博</a>
<ul>
<li>
<a href="">私信</a>
</li>
<li>
<a href="">评论</a>
</li>
<li>
<a href="">@我</a>
</li>
</ul>
</li>
</ul>
<script>
// 1. 获取元素
var nav = document.querySelector('.nav');
var lis = nav.children; // 得到4个小li
// 2.循环注册事件
for (var i = 0; i < lis.length; i++) {
lis[i].onmouseover = function() {
this.children[1].style.display = 'block';
}
lis[i].onmouseout = function() {
this.children[1].style.display = 'none';
}
}
</script>
</body>
</html>
1.2.4 兄弟关系查找
1.3 增加节点
目标:能够具备根据需求新增节点的能力
1.3.1 创建节点
- 即创造出一个新的网页元素,再添加到网页内,一般先创建节点,然后插入节点
- 创建元素节点方法:
1.3.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>
</head>
<body>
<ul>
<li>我是大毛</li>
<li>我是二毛</li>
</ul>
<script>
// 二毛 ul.children[1]
// 1. 创建新的标签节点
// let div = document.createElement('div')
// div.className = 'current'
let ul = document.querySelector('ul')
let li = document.createElement('li')
li.innerHTML = '我是xiao ming'
// 2. 追加节点 父元素.appendChild(子元素) 后面追加
// ul.appendChild(li)
// 3. 追加节点 父元素.insertBefore(子元素, 放到那个元素的前面)
ul.insertBefore(li, ul.children[0])
</script>
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<ul>
<li>123</li>
</ul>
<script>
// 1. 创建节点元素节点
var li = document.createElement('li');
// 2. 添加节点 node.appendChild(child) node 父级 child 是子级 后面追加元素 类似于数组中的push
var ul = document.querySelector('ul');
ul.appendChild(li);
// 3. 添加节点 node.insertBefore(child, 指定元素);
var lili = document.createElement('li');
ul.insertBefore(lili, ul.children[0]);
// 4. 我们想要页面添加一个新的元素 : 1. 创建元素 2. 添加元素
</script>
</body>
</html>
1.3.3 案例:学成在线案例渲染
需求:按照数据渲染页面
分析:
①:准备好空的ul 结构
②:根据数据的个数,创建一个新的空li
③:li里面添加内容 img 标题等
④:追加给ul
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>学车在线首页</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<!-- 4. box核心内容区域开始 -->
<div class="box w">
<div class="box-hd">
<h3>精品推荐</h3>
<a href="#">查看全部</a>
</div>
<div class="box-bd">
<ul class="clearfix">
<!-- <li>
<img src="./images/course01.png" alt="">
<h4>
Think PHP 5.0 博客系统实战项目演练
</h4>
<div class="info">
<span>高级</span> • <span> 1125</span>人在学习
</div>
</li> -->
</ul>
</div>
</div>
<script>
let data = [
{
src: 'images/course01.png',
title: 'Think PHP 5.0 博客系统实战项目演练',
num: 1125
},
{
src: 'images/course02.png',
title: 'Android 网络动态图片加载实战',
num: 357
},
{
src: 'images/course03.png',
title: 'Angular2 大前端商城实战项目演练',
num: 22250
},
{
src: 'images/course04.png',
title: 'Android APP 实战项目演练',
num: 389
},
{
src: 'images/course05.png',
title: 'UGUI 源码深度分析案例',
num: 124
},
{
src: 'images/course06.png',
title: 'Kami2首页界面切换效果实战演练',
num: 432
},
{
src: 'images/course07.png',
title: 'UNITY 从入门到精通实战案例',
num: 888
},
{
src: 'images/course08.png',
title: '我会变,你呢?',
num: 590
},
{
src: 'images/course08.png',
title: '我会变,你呢?',
num: 590
}
]
let ul = document.querySelector('ul')
// 1. 根据数据的个数,决定这小li的个数
for (let i = 0; i < data.length; i++) {
// 2. 创建小li
let li = document.createElement('li')
// console.log(li)
// 4. 先准备好内容,再追加
li.innerHTML = `
<img src=${data[i].src} alt="">
<h4>
${data[i].title}
</h4>
<div class="info">
<span>高级</span> • <span> ${data[i].num}</span>人在学习
</div>
`
// 3. 追加给ul 父元素.appendChild(子元素)
ul.appendChild(li)
}
</script>
</body>
</html>
1.3.4 (复制节点)克隆节点
注意∶
1.如果括号参数为空或者为false,则是浅拷贝,即只克隆复制节点本身,不克隆里面的子节点。
⒉如果括号参数为true,则是深度拷贝,会复制节点本身以及里面所有的子节点。
1.4 删除节点 :node.removeChild(child)
注:
- 如不存在父子关系,则删除不成功
- 删除节点和隐藏节点(display:none) 有区别的: 隐藏节点还是存在的,但是删除,则从html中删除节点
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<button>删除</button>
<ul>
<li>熊大</li>
<li>熊二</li>
<li>光头强</li>
</ul>
<script>
// 1.获取元素
var ul = document.querySelector('ul');
var btn = document.querySelector('button');
// 2. 删除元素 node.removeChild(child)
// ul.removeChild(ul.children[0]);
// 3. 点击按钮依次删除里面的孩子
btn.onclick = function() {
if (ul.children.length == 0) {
this.disabled = true;
} else {
ul.removeChild(ul.children[0]);
}
}
</script>
</body>
</html>
2. 时间对象
- 目标:能够实例化时间对象
- 时间对象:用来表示时间的对象
- 作用:可以得到当前系统时间
2.1 实例化
- 在代码中发现了 new 关键字时,一般将这个操作称为实例化
- 创建一个时间对象并获取时间
2.2 时间对象方法
目标:能够使用时间对象中的方法写出常见日期
- 因为时间对象返回的数据我们不能直接使用,所以需要转换为实际开发中常用的格式
2.3 案例:页面显示时间
需求:将当前时间以:YYYY-MM-DD HH:mm 形式显示在页面
案例
分析:
①:调用时间对象方法进行转换
②:字符串拼接后,通过 innerText 给 标签
2.4 时间戳
目标:能够获得当前时间戳
2.5 案例:毕业倒计时效果
需求:计算到下课还有多少时间
分析:
①:用将来时间减去现在时间就是剩余的时间
②:核心: 使用将来的时间戳减去现在的时间戳
③:把剩余的时间转换为 天 时 分 秒
<!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>
.countdown {
width: 240px;
height: 305px;
text-align: center;
line-height: 1;
color: #fff;
background-color: brown;
/* background-size: 240px; */
/* float: left; */
overflow: hidden;
}
.countdown .next {
font-size: 16px;
margin: 25px 0 14px;
}
.countdown .title {
font-size: 33px;
}
.countdown .tips {
margin-top: 80px;
font-size: 23px;
}
.countdown small {
font-size: 17px;
}
.countdown .clock {
width: 142px;
margin: 18px auto 0;
overflow: hidden;
}
.countdown .clock span,
.countdown .clock i {
display: block;
text-align: center;
line-height: 34px;
font-size: 23px;
float: left;
}
.countdown .clock span {
width: 34px;
height: 34px;
border-radius: 2px;
background-color: #303430;
}
.countdown .clock i {
width: 20px;
font-style: normal;
}
</style>
</head>
<body>
<div class="countdown">
<p class="next">今天是2021年8月28日</p>
<p class="title">下班倒计时</p>
<p class="clock">
<span id="hour">00</span>
<i>:</i>
<span id="minutes">25</span>
<i>:</i>
<span id="scond">20</span>
</p>
<p class="tips">
现在是18:30:00
</p>
</div>
<script>
let hour = document.querySelector('#hour')
let minutes = document.querySelector('#minutes')
let scond = document.querySelector('#scond')
time()
setInterval(time, 1000)
function time() {
// 1. 得到现在的时间戳
let now = +new Date()
// 2. 得到指定时间的时间戳
let last = +new Date('2021-8-29 18:30:00')
// 3. (计算剩余的毫秒数) / 1000 === 剩余的秒数
let count = (last - now) / 1000
// console.log(count)
// 4. 转换为时分秒
// h = parseInt(总秒数 / 60 / 60 % 24) // 计算小时
let h = parseInt(count / 60 / 60 % 24)
h = h < 10 ? '0' + h : h
// m = parseInt(总秒数 / 60 % 60); // 计算分数
let m = parseInt(count / 60 % 60)
m = m < 10 ? '0' + m : m
// s = parseInt(总秒数 % 60); // 计算当前秒数
let s = parseInt(count % 60);
s = s < 10 ? '0' + s : s
// console.log(h, m, s)
hour.innerHTML = h
minutes.innerHTML = m
scond.innerHTML = s
}
</script>
</body>
</html>
3 .重绘和回流
3.1 浏览器是如何进行界面渲染的
- 解析(Parser)HTML,生成DOM树(DOM Tree)
- 同时解析(Parser) CSS,生成样式规则 (Style Rules)
- 根据DOM树和样式规则,生成渲染树(Render Tree)
- 进行布局 Layout(回流/重排):根据生成的渲染树,得到节点的几何信息(位置,大小)
- 进行绘制 Painting(重绘): 根据计算和获取的信息进行整个页面的绘制
- Display: 展示在页面上
3.2. 重绘和回流(重排)
回流(重排)
- 当 Render Tree 中部分或者全部元素的尺寸、结构、布局等发生改变时,浏览器就会重新渲染部分或全部文档的过
程称为 回流。
重绘 - 由于节点(元素)的样式的改变并不影响它在文档流中的位置和文档布局时(比如:color、background-color、outline等), 称为重绘。
- 重绘不一定引起回流,而回流一定会引起重绘。