一、节点操作
1、DOM 节点
- DOM节点: DOM树里每一个内容都称之为节点
- 节点类型(元素节点最重要,因为需要对他操作)
- 元素节点
所有的标签 比如 body、 div
html 是根节点 - 属性节点
所有的属性 比如 href - 文本节点
所有的文本 - 其他
- 元素节点
节点可以让我们更好的理清标签元素之间的关系
2、查找节点
- 关闭二维码案例:
点击关闭按钮 i, 关闭的是二维码的盒子, 需要获取box盒子
- 思考:
关闭按钮 i 和 box 是什么关系呢? 父子关系
所以,我们完全可以这样做:
点击关闭按钮, 直接关闭它的爸爸,就无需获取 box 元素了 - 节点关系:
父节点
子节点
兄弟节点
(1) 父节点查找:
parentNode 属性,子元素.parentElement 返回的是一个对象
返回最近一级的父节点 找不到返回为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>
<style>
.box{
display: flex;
}
.box img{
border: 1px solid #000;
}
.box i{
width: 10px;
height: 10px;
border: 1px solid #000;
line-height: 7px;
text-align: center;
color: #ccc;
cursor: pointer;
}
</style>
</head>
<body>
<div class="box">
<img src="./images/456.png" alt="">
<i>x</i>
</div>
<div class="box">
<img src="./images/456.png" alt="">
<i>x</i>
</div>
<div class="box">
<img src="./images/456.png" alt="">
<i>x</i>
</div>
<div class="box">
<img src="./images/456.png" alt="">
<i>x</i>
</div>
<div class="box">
<img src="./images/456.png" alt="">
<i>x</i>
</div>
<script>
//获取元素
let i = document.querySelectorAll('i')
//绑定事件
for (let j = 0; j < i.length; j++){
i[j].addEventListener('click',function(){
//关闭当前的二维码,点击谁就关闭谁的爸爸
//没用display='none',这样关掉后不占位,剩下的所有二维码会自动往上移
//this.parentElement返回的是一个对象
this.parentElement.style.visibility = 'hidden'
})
}
</script>
</body>
</html>
注意:
使用visibility = 'hidden'
而不是display='none'
是因为:
(2)子节点查找
- childNodes
获得所有子节点、包括文本节点(空格、换行)、注释节点等,这些节点获取来没啥用,所以childNodes了解即可 - children (重点)
仅获得所有元素节点,返回的是一个伪数组
- 例:点击按钮,让所有孩子变红色
<button>点击</button>
<ul>
<li>孩子1</li>
<li>孩子2</li>
<li>孩子3</li>
<li>孩子4</li>
</ul>
<script>
// 获取元素
let btn = document.querySelector('button')
let ul = document.querySelector('ul')
//事件监听
btn.addEventListener('click',function(){
//通过ul控制所有li,ul.children是伪数组,循环
for (let i = 0; i<ul.children.length; i++ ){
ul.children[i].style.color = 'red'
}
})
</script>
注意,通过
父元素.children
获得的是一个伪数组,想对里面的元素操作都得先遍历或者取出(父元素.children[0])
(3)兄弟节点查找
- 下一个兄弟节点
nextElementSibling 属性 - 上一个兄弟节点
previousElementSibling 属性
<!-- 兄弟[i+1]变红色 -->
兄弟[i].nextElementSibling.style.color = 'red'
3、增加节点
-
很多情况下,我们需要在页面中增加元素
比如,点击发布按钮,可以新增一条信息
-
一般情况下,我们新增节点,按照如下操作:
创建一个新的节点
把创建的新的节点放入到指定的元素内部
创建节点
创造出一个新的网页元素,创建元素节点方法:
注意标签名只能是标签选择器,如div、p等,不能是类选择器或者ID选择器,如果想创建类选择器:
<script>
let div = document.createElement('div')
div.className = 'box'
</script>
追加节点
要想在界面看到,还得插入到某个父元素中
-
插入到父元素的最后一个子元素
-
插入到父元素中某个子元素的前面
-
例:
案例–学成在线案例渲染
追加各个小课程
分析:
①:准备好空的ul 结构
②:根据数据的个数,创建一个新的空li
③:li里面添加内容 img 标题等
④:追加给ul
<!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>
<link rel="stylesheet" href="./index.css">
</head>
<body>
<div class="box">
<div class="head">
<h3>精品推荐</h3>
<p>查看全部</p>
</div>
<div class="body">
<ul>
<!-- 开始是空的,一个li也没有,后面在script里面追加,实现html个js分离 -->
</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: 'Cocos 深度学习你不会错过的实战',
num: 590
}
]
//获取元素
let ul = document.querySelector('ul')
for(let i = 0; i<data.length;i++){
//根据数据的个数,创建li
let li = document.createElement('li')
//li添加内容
li.innerHTML = `
<img src="${data[i].src}" alt=""></img>
<h4>${data[i].title}</h4>
<div class="info">
<span>高级</span> •
<span>${data[i].num}</span>人在学习
</div> `
//追加给ul
ul.appendChild(li)
}
</script>
</body>
</html>
原本是将
<script>
写到 ul 里面实现数据渲染的,现在可以通过追加实现 html 和 js 分离
4、克隆节点
特殊情况下,我们新增节点,按照如下操作:
复制一个原有的节点
把复制的节点放入到指定的元素内部
- 克隆节点
cloneNode会克隆出一个跟原标签一样的元素,括号内传入布尔值
若为true,则代表克隆时会包含后代节点一起克隆
若为false,则代表克隆时不包含后代节点
默认为false
克隆与新建节点一样,需要配合追加节点操作,否则结构中还是不会有此节点
5、删除节点
若一个节点在页面中已不需要时,可以删除它
在 JavaScript 原生DOM操作中,要删除元素必须通过父元素删除
- 语法:
如不存在父子关系则删除不成功
删除节点和隐藏节点(display:none) 有区别的: 隐藏节点还是存在的,但是删除,则从html中删除节点
二、时间对象
- 时间对象:用来表示时间的对象
- 作用:可以得到当前系统时间
1、实例化
- 代码中 new 关键字,一般将这个操作称为实例化
- 在代码中发现了 new 关键字时,一般将这个操作称为实例化
2、时间对象方法
因为时间对象返回的数据我们不能直接使用,所以需要转换为实际开发中常用的格式
案例–页面显示时间
需求:将当前时间以:YYYY-MM-DD HH:mm 形式显示在页面
<!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>
div{
width: 300px;
height: 50px;
}
</style>
</head>
<body>
<div></div>
<script>
setInterval(function(){
//new时间对象
//小括号为空可以得到当前时间
let date = new Date()
let year = date.getFullYear()
let month = date.getMonth()+1
let day = date.getDate()
let hour = date.getHours()
let min = date.getMinutes()
let sec = date.getSeconds()
let div = document.querySelector('div')
div.innerHTML = `${year}-${month}-${day} ${hour}:${min}:${sec}`
},1000)
</script>
</body>
</html>
3、时间戳
- 时间戳概念
是指1970年01月01日00时00分00秒起至现在的毫秒数,它是一种特殊的计量时间的方式
可以用来倒计时,我们无法直接用将来的时间减去现在的时间,但是将来的时间有时间戳,现在的时间也有时间戳,时间戳可以做差然后转换为小时:分钟:秒,就可以倒计时。 - 三种方式获取时间戳
- 使用
getTime()
方法
- 简写
+new Date()
,+是正号
- 使用
Date.now()
无需实例化
但是只能得到当前的时间戳, 而前面两种可以返回指定时间的时间戳
- 使用
下课倒计时效果
需求:计算到下课还有多少时间
分析:
①:用将来时间减去现在时间就是剩余的时间
②:核心: 使用将来的时间戳减去现在的时间戳
③:把剩余的时间转换为 天 时 分 秒
注意:
1. 通过时间戳得到是毫秒,需要转换为秒在计算
2. 转换公式:
d = parseInt(总秒数 /60/60 /24); // 计算天数
h = parseInt(总秒数 /60/60 %24) // 计算小时
m = parseInt(总秒数 /60 %60 ); // 计算分数
s = parseInt(总秒数%60); // 计算当前秒数
<!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">今天是</p>
<p class="title">下班倒计时</p>
<p class="clock">
<span id="hour">00</span>
<i>:</i>
<span id="minutes">25</span>
<i>:</i>
<span id="second">20</span>
</p>
<p class="tips">现在是</p>
</div>
<script>
//下班倒计时
//获取元素
let h = document.querySelector('#hour')
let m = document.querySelector('#minutes')
let s = document.querySelector('#second')
//先调用一下,因为定时器会有一秒空白期,先调用可以避免
time()
setInterval(time,1000)
function time(){
//现在的时间戳
let now = +new Date()
//指定时间的时间戳
let fu = +new Date('2022-7-19 24:00:00')
//计算时间戳差值,转换为s
let count = (fu-now) / 1000
//转换为时分秒
let hour = parseInt (count/60/60%24)
hour = hour < 10 ? '0'+ hour:hour
let min = parseInt (count/60%60)
min = min < 10 ? '0'+ min:min
let sec = parseInt (count%60)
sec = sec < 10 ? '0'+ sec:sec
//写入时间
h.innerHTML = hour
m.innerHTML = min
s.innerHTML = sec
}
</script>
</body>
</html>
三、综合案例–发布微博
需求1
注册input事件
将文本的内容的长度赋值给对应的数值
表单的maxlength属性可以直接限制在200个数之间
需求2
判断如果内容为空,则提示不能输入为空, 并且直接return
防止输入无意义空格, 使用字符串.trim()去掉首尾空格, 并将表单的value值设置为空字符串
需求3
获取文本域的内容, 赋值给新标签里面的text.value
随机获取数据数组里面的内容, 替换新建立节点的图片和名称
利用时间对象将时间动态化 new Date().toLocaleString()
需求4
在事件处理函数里面获取点击按钮,注册点击事件,删除评论,
放到追加进ul的前面,这样创建元素的同时顺便绑定了删除事件,不用后面再循环绑定很麻烦
(易错点: 必须在事件里面获取,外面获取不到,因为只有发布了的才能被删除)
删除对应的元素
需求5
将表单域内容重置为空
将use里面的内容重置为0
<!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>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
ul {
list-style: none;
}
/* 文本框 */
.wei {
width: 900px;
margin: 0 auto;
}
.wei textarea {
width: 900px;
height: 112px;
resize: none;
border-radius: 10px;
outline: none;
padding-top: 10px;
padding-left: 20px;
font-size: 18px;
}
/* 底部字数按钮 */
.wei .bottom {
float: right;
}
.wei span {
color: #666;
}
.wei .use {
color: red;
}
.wei button {
width: 100px;
height: 30px;
background-color: rgb(0, 132, 255);
border: 0;
line-height: 30px;
text-align: center;
color: #fff;
font: bold 14px '宋体';
cursor: pointer;
}
button:hover {
background: rgb(0, 225, 255);
}
/* 微博内容发布列表 */
ul {
margin-top: 80px;
}
ul li {
position: relative;
padding: 20px 0;
border-bottom: 1px dashed #ccc;
}
/* 头像昵称发布时间 */
ul li .info {
position: relative;
}
ul li .info .userpic {
width: 80px;
height: 80px;
border-radius: 50%;
}
ul li .info .username {
position: absolute;
top: 15px;
left: 100px;
font: bold 16px '宋体';
}
ul li .info .sendtime {
position: absolute;
top: 40px;
left: 100px;
color: #aaa;
font-size: 12px;
}
/* 发布内容 */
ul li .content {
padding-left: 100px;
color: #666;
}
/* x删除评论 */
ul li .del {
position: absolute;
top: 0;
right: 0;
font-size: 28px;
cursor: pointer;
}
</style>
</head>
<body>
<div class="wei">
<img src="./images/9.6/tip.png" alt="">
<br>
<!-- maxlength控制最大输入长度 -->
<textarea placeholder="说点什么吧..." id="area" cols="30" rows="10" maxlength="200"></textarea>
<div class="bottom">
<span class="use">0</span>
<span>/</span>
<span>200</span>
<button>发布</button>
</div>
<!-- 微博内容发布列表 -->
<div>
<ul>
<!-- 等js新建节点追加 -->
</ul>
</div>
</div>
<script>
// 模拟数据
let dataArr = [
{ uname: '司马懿', imgSrc: './images/9.5/01.jpg' },
{ uname: '女娲', imgSrc: './images/9.5/02.jpg' },
{ uname: '百里守约', imgSrc: './images/9.5/03.jpg' },
{ uname: '亚瑟', imgSrc: './images/9.5/04.jpg' },
{ uname: '虞姬', imgSrc: './images/9.5/05.jpg' },
{ uname: '张良', imgSrc: './images/9.5/06.jpg' },
{ uname: '安其拉', imgSrc: './images/9.5/07.jpg' },
{ uname: '李白', imgSrc: './images/9.5/08.jpg' },
{ uname: '阿珂', imgSrc: './images/9.5/09.jpg' },
{ uname: '墨子', imgSrc: './images/9.5/10.jpg' },
{ uname: '鲁班', imgSrc: './images/9.5/11.jpg' },
{ uname: '嬴政', imgSrc: './images/9.5/12.jpg' },
{ uname: '孙膑', imgSrc: './images/9.5/13.jpg' },
{ uname: '周瑜', imgSrc: './images/9.5/14.jpg' },
{ uname: '老夫子', imgSrc: './images/9.5/15.jpg' },
{ uname: '狄仁杰', imgSrc: './images/9.5/16.jpg' },
{ uname: '扁鹊', imgSrc: './images/9.5/17.jpg' },
{ uname: '马可波罗', imgSrc: './images/9.5/18.jpg' },
{ uname: '露娜', imgSrc: './images/9.5/19.jpg' },
{ uname: '孙悟空', imgSrc: './images/9.5/20.jpg' },
{ uname: '黄忠', imgSrc: './images/9.5/21.jpg' },
{ uname: '百里玄策', imgSrc: './images/9.5/22.jpg' },
]
// 需求1
// 注册input事件
// 将文本的内容的长度赋值给对应的数值
// 表单的maxlength属性可以直接限制在200个数之间
// 获取元素
let text = document.querySelector('textarea')
let use = document.querySelector('.use')
// 事件监听,输入出发监听
text.addEventListener('input', function () {
//不断获得文本框的字符长度,表单数据获取需要通过元素的value获取,而对于div则需要通过innerHTML获取
use.innerHTML = text.value.length
})
// 需求2
// 判断如果内容为空,则提示不能输入为空, 并且直接return
// 防止输入无意义空格, 使用字符串.trim()去掉首尾空格, 并将表单的value值设置为空字符串
//获取元素
let btn = document.querySelector('button')
btn.addEventListener('click', function () {
if (text.value.trim() === '') {
text.value = ''
use.innerHTML = 0
return alert('内容不能为空')
}
// 需求3
// 获取文本域的内容, 赋值给新标签里面的text.value
// 随机获取数据数组里面的内容, 替换新建立节点的图片和名称
// 利用时间对象将时间动态化 new Date().toLocaleString()
function getRandom(min, max) {
return Math.floor(Math.random() * (max - min + 1) + min)
}
let random = getRandom(0, dataArr.length - 1)
let ul = document.querySelector('ul')
let li = document.createElement('li')
li.innerHTML = `<!-- 头像昵称发布时间 -->
<div class="info">
<img class="userpic" src=${dataArr[random].imgSrc} alt="">
<span class="username">${dataArr[random].uname}</span>
<span class="sendtime">${new Date().toLocaleString()}</span>
</div>
<!-- 发布内容 -->
<div class="content">${text.value}</div>
<!-- X -->
<div class="del">X</div>
`
// 需求4
// 在事件处理函数里面获取点击按钮, 注册点击事件
// (易错点: 必须在事件里面获取, 外面获取不到)
// 删除对应的元素
// 因为li只新建还没追加,在document里面找不到,所以在li里面找
let del = li.querySelector('.del')
del.addEventListener('click',function(){
ul.removeChild(li)
})
ul.insertBefore(li, ul.children[0])
// 需求5
// 将表单域内容重置为空
// 将use里面的内容重置为0
text.value = ''
use.innerHTML = 0
})
</script>
</body>
</html>
四、重绘和回流
1、 浏览器是如何进行界面渲染的
解析(Parser)HTML,生成DOM树(DOM Tree)
同时解析(Parser) CSS,生成样式规则 (Style Rules)
根据DOM树和样式规则,生成渲染树(Render Tree)
进行布局 Layout(回流/重排):根据生成的渲染树,得到节点的几何信息(位置,大小)
进行绘制 Painting(重绘): 根据计算和获取的信息进行整个页面的绘制
Display: 展示在页面上
2、 重绘和回流(重排)
-
回流(重排)
当 Render Tree 中部分或者全部元素的尺寸、结构、布局等发生改变时,浏览器就会重新渲染部分或全部文档的过程称为回流。 -
重绘
由于节点(元素)的样式的改变并不影响它在文档流中的位置和文档布局时(比如:color、background-color、outline等), 称为重绘。 -
重绘不一定引起回流,而回流一定会引起重绘
-
会导致回流(重排)的操作:
页面的首次刷新
浏览器的窗口大小发生改变
元素的大小或位置发生改变
改变字体的大小
内容的变化(如:input框的输入,图片的大小)
激活css伪类 (如::hover)
脚本操作DOM(添加或者删除可见的DOM元素)
简单理解,影响到布局了,就会有回流
五、购物车案例
需求:能够实现商品数量加减、删除,以及总价和总数的计算
<!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>
<!-- 引入初始化 -->
<style>
* {
margin: 0;
padding: 0;
}
ul {
list-style: none;
}
a {
text-decoration: none;
color: #666;
}
body {
background: #fff;
color: #666;
font-size: 14px;
}
input {
outline: none;
}
.clearfix::before,
.clearfix::after {
content: '';
display: block;
clear: both;
}
.clearfix {
*zoom: 1;
}
</style>
<!-- 引入购物车样式 -->
<style>
table {
width: 800px;
margin: 0 auto;
border-collapse: collapse;
}
th {
font: normal 14px/50px '宋体';
color: #666;
}
th,
td {
border: none;
text-align: center;
border-bottom: 1px dashed #ccc;
}
input[type='checkbox'] {
width: 13px;
height: 13px;
}
tbody p {
position: relative;
bottom: 10px;
}
tbody .add,
tbody .reduce {
float: left;
width: 22px;
height: 22px;
border: 1px solid #ccc;
text-align: center;
background: none;
outline: none;
cursor: pointer;
}
tbody input[type='text'] {
width: 50px;
float: left;
height: 18px;
text-align: center;
}
tbody .count-c {
width: 98px;
margin: 0 auto;
}
button[disabled] {
color: #ddd;
cursor: not-allowed;
}
tbody tr:hover {
background: #eee;
}
tbody tr.active {
background: rgba(241, 209, 149, 0.945);
}
.controls {
width: 790px;
margin: 10px auto;
border: 1px solid #ccc;
line-height: 50px;
padding-left: 10px;
position: relative;
}
.controls .del-all,
.controls .clear {
float: left;
margin-right: 50px;
}
.controls p {
float: right;
margin-right: 100px;
}
.controls span {
color: red;
}
.controls .pay {
position: absolute;
right: 0;
width: 80px;
height: 54px;
background: red;
font: bold 20px/54px '宋体';
color: #fff;
text-align: center;
bottom: -1px;
}
.controls .total-price {
font-weight: bold;
}
</style>
</head>
<body>
<div class="car">
<table>
<thead>
<tr>
<th><input type="checkbox" id="all" />全选</th>
<th>商品</th>
<th>单价</th>
<th>商品数量</th>
<th>小计</th>
<th>操作</th>
</tr>
</thead>
<tbody id="carBody">
<tr>
<td>
<input class="s_ck" type="checkbox" readonly />
</td>
<td>
<img src="./images/01.jpg" />
<p>牛奶</p>
</td>
<td class="price">5¥</td>
<td>
<div class="count-c clearfix">
<button class="reduce" disabled>-</button>
<input type="text" value="1" />
<button class="add">+</button>
</div>
</td>
<td class="total">5¥</td>
<td>
<a href="javascript:" class="del">删除</a>
</td>
</tr>
<tr>
<td>
<input class="s_ck" type="checkbox" />
</td>
<td>
<img src="./images/01.jpg" />
<p>牛奶</p>
</td>
<td class="price">10¥</td>
<td>
<div class="count-c clearfix">
<button class="reduce" disabled>-</button>
<input type="text" value="1" />
<button class="add">+</button>
</div>
</td>
<td class="total">10¥</td>
<td>
<a href="javascript:" class="del">删除</a>
</td>
</tr>
<tr>
<td>
<input class="s_ck" type="checkbox" />
</td>
<td>
<img src="./images/01.jpg" />
<p>牛奶</p>
</td>
<td class="price">20¥</td>
<td>
<div class="count-c clearfix">
<button class="reduce" disabled>-</button>
<input type="text" value="1" />
<button class="add">+</button>
</div>
</td>
<td class="total">20¥</td>
<td>
<a href="javascript:" class="del">删除</a>
</td>
</tr>
<tr>
<td>
<input class="s_ck" type="checkbox" />
</td>
<td>
<img src="./images/01.jpg" />
<p>牛奶</p>
</td>
<td class="price">35¥</td>
<td>
<div class="count-c clearfix">
<button class="reduce" disabled>-</button>
<input type="text" value="1" />
<button class="add">+</button>
</div>
</td>
<td class="total">35¥</td>
<td>
<a href="javascript:" class="del">删除</a>
</td>
</tr>
</tbody>
</table>
<div class="controls clearfix">
<a href="javascript:" class="del-all">删除所选商品</a>
<a href="javascript:" class="clear">清理购物车</a>
<a href="javascript:" class="pay">去结算</a>
<p>
已经选中<span id="totalCount">4</span>件商品;总价:<span id="totalPrice" class="total-price">0¥</span>
</p>
</div>
</div>
<script>
// + - 删除是相同的,一一对应的 可以用一个for来遍历绑定事件
//加
let add = document.querySelectorAll('.add')
//减
let reduce = document.querySelectorAll('.reduce')
//删除
let del = document.querySelectorAll('.del')
//每个商品个数
let input = document.querySelectorAll('.count-c input')
//单价
let price = document.querySelectorAll('.price')
//每个商品总价
let total = document.querySelectorAll('.total')
//商品盒子
let carBody = document.querySelector('#carBody')
//总共商品数
let goods = document.querySelector('#totalCount')
//总价
let money = document.querySelector('#totalPrice')
for (let i = 0; i < add.length; i++) {
//1、加号
add[i].addEventListener('click', function () {
input[i].value++
reduce[i].disabled = false
total[i].innerHTML = parseInt(price[i].innerHTML) * input[i].value + '¥'
result()
})
//2、减号
reduce[i].addEventListener('click', function () {
input[i].value--
if (input[i].value <= 1) {
reduce[i].disabled = true
}
total[i].innerHTML = parseInt(price[i].innerHTML) * input[i].value + '¥'
result()
})
//3、删除
del[i].addEventListener('click', function () {
//没办法用carBody.removeChild(carBody.children[i]),例如第一次点击删除1想删除1号商品
// 第二次想点击删除2的删除2号商品但这个时候商品2是父节点的第一个孩子
carBody.removeChild(this.parentNode.parentNode)
result()
})
}
function result() {
let sum = 0
let num = 0
//删除后,需要重新获取每个商品个数和总价,否则还是删除之前的数,如删除1号商品后,
//对2号商品操作会显示在3号商品,因为此时3号商品才是第二个孩子
//每个商品个数
let input = document.querySelectorAll('.count-c input')
//每个商品总价
let total = document.querySelectorAll('.total')
for (let i = 0; i < total.length; i++) {
sum += +parseInt(total[i].innerHTML)
num += +input[i].value
}
goods.innerHTML = num
money.innerHTML = sum + '¥'
}
// div span ul li 标签 有文字内容 怎么得到或则设置文字内容呢 元素.innerText 元素.innerHTML
// 表单 input 单选 复选 textarea select 怎么得到或则设置值 表单的value
// 特殊的 button 是通过inner来设置
</script>
</body>
</html>