DOM- 节点操作

  • 1.DOM节点的基本概念
    • 1.1.DOM节点的概念
    • 1.2.节点类型
  • 2.查找节点
    • 2.1.父节点查找:
      • 2.1.1.父节点查找语法:
      • 2.1.2.高级父级查找语法:
      • 2.1.3.关闭二维码案例
      • 2.1.4.关闭多个二维码案例
        • 拓展:visibility:hidden和display:none的区别
    • 2.2.子节点查找:
      • 2.2.1.childNodes
      • 2.2.2.children (重点)
        • 语法:
    • 2.3.兄弟关系查找:
      • 2.3.1. 下一个兄弟节点
      • 2.3.2. 上一个兄弟节点
  • 3.增加节点
    • 3.1.创建节点
    • 3.2.追加节点
      • 3.2.1.插入到父元素的最后一个子元素:
        • 语法:
      • 3.2.2.插入到父元素中某个子元素的前面:
        • 语法:
      • 3.2.3.综合案例-学成在线
        • 项目准备
          • 静态页面代码
            • html部分
            • css部分
            • JavaScript部分准备
        • JavaScript部分需求实现代码
          • 思路分析
          • 我的代码
          • 参考代码
          • 我的代码bug分析
          • 我的代码优化和完善
            • 思路:
            • 代码:
            • 我的代码优化和完善后的运行结果
      • 3.2.4.克隆节点
        • 克隆节点概念
        • 克隆节点语法:
  • 4.删除节点
    • 4.1.删除节点的概念
    • 4.2.删除节点语法
  • 5.时间对象
    • 5.1.时间对象的概念和作用
    • 5.2.实例化
      • 5.2.1.获得当前时间
      • 5.2.2.获得指定时间
    • 5.3.时间对象方法
      • 5.3.1.时间对象方法与作用
      • 5.3.2.时间对象方法与作用案例
        • 例2:需求:将当前时间以:YYYY-MM-DD HH:mm 形式显示在页面**
          • **HTML+CSS部分**
            • 思路:
            • 代码:
          • **JavaScript部分**
            • 我的思路与代码:
            • 参考代码:
            • 我的代码优化:
    • 5.4.时间戳
      • 5.4.1.时间戳的基本概念
        • **概念**
        • **使用时间戳的目的:**
      • 5.4.2.三种方式获取时间戳
        • 方式1.使用 getTime() 方法
        • 方式2.简写 +new Date()
        • 方式3.使用 Date.now(),只能得到当前的
      • 5.4.3.案例-春节倒计时效果
        • 素材分析:HTML+CSS部分
        • JavaScript 部分
          • 需求1:显示当前时间(日期与时分秒)
            • 思路:
            • 代码:
          • 需求2:实现倒计时效果
            • 思路:
            • 代码:
            • 细节:
        • 完整代码
  • 6.重绘与重排
    • 6.1. 浏览器是如何进行界面渲染的
    • 6.2.2. 重绘和回流(重排)
      • 1.回流(或称重排)
      • 2.重绘
      • 会导致回流(重排)的操作:
  • 7.综合案例——微博发布
    • 7.1.需求
    • 7.2.素材与素材分析
      • 7.2.1.素材
      • 7.2.2.素材分析
    • 7.3.需求实现
      • 7.3.1.需求1:文本区域输入文字,字数统计同步变化
        • 代码与思路
      • 7.3.2.需求2 :判断用户输入内容是否为空,并给予用户弹窗提示
        • 思路:
        • 代码:
        • 细节:为什么要去除空格?以及去除空格的方法
      • 7.3.3.需求3:将用户发布的微博信息显示在网页中
        • 思路:
        • 代码:
        • 遇到问题:
        • 补充知识点:实例化生成本地时间
        • 7.3.4.需求5:控制显示输入空字符和重置
          • 思路:
          • 代码:
        • 7.3.5.需求4:删除微博留言
          • 思路:
          • 代码:
          • 细节:
    • 7.4.完整代码
  • 8.综合案例-购物车
    • 8.1.需求
      • 8.1.1.需求页面
      • 8.1.2.需求明确
        • 1.点击加号事件
        • 2.点击减号事件
        • 3.点击删除事件
        • 4.商品数量总量和总价计算
    • 8.2.素材
    • 8.3.素材分析
    • 8.4.我的代码与实现思路(JavaScript部分)
    • 8.5.优化
      • 8.5.1.bug分析与修复
        • 1.编写代码过程遇到的bug
          • (1)调用数组对象属性方法出错
          • (2)无法修改小计中的价格
          • (3)遗忘删除节点操作
          • (4)作用域问题与for循环输出结果预判出错问题——商品总件数和总价模块部分
        • 2.代码存在的bug
      • 8.5.2.参考代码与我的代码对比分析与我的代码优化
        • 1.删除商品数据后总价变化
        • 2.合并加号、减号和删除事件的循环
    • 8.6.优化后的完整代码

1.DOM节点的基本概念

1.1.DOM节点的概念

DOM树

DOM树里每一个内容(标签、注释、文本等)都称之为节点。

1.2.节点类型

1.元素节点

所有的标签 比如 body、 div、script、style等

html 是根节点

2.属性节点

所有的属性 比如 链接路径href、类(class)、id

3.文本节点

所有的文本,如 标签< button >按钮3< /button >里面的‘按钮3’就是文本节点

4. 其他

重点记住元素节点

2.查找节点

节点关系:

父节点

子节点

兄弟节点

2.1.父节点查找:

parentNode 属性:返回最近一级的父节点 ,找不到返回为null

2.1.1.父节点查找语法:

子元素.parentNode

例:通过节点查找,父级div.father将本身和子级div.son隐藏

父级和子级html

 <div class="father">我爱罗<div class="son">Tom</div></div>

思路:

1.获取子级标签div.son;
2.查找结点,父级div.father将本身和子级div.son隐藏

代码:

<!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>/* .father{display:  none;} */</style>
</head>
<body><div class="father">我爱罗<div class="son">Tom</div></div><script>// 父节点查找语法://子元素.parentNode//高级父级查找语法://注意:parentNode只能查找最近一级的父级节点,即当前子节点的直接父级节点//更高级别的父级需要编写多个parentNode//爷爷节点查找语法://  子元素.parentNode.parentNode//例:通过节点查找,父级div.father将本身和子级div.son隐藏//1.获取子级标签div.sonlet son = document.querySelector('.son')//测试:找爸爸,观察是否获取到直接父级// console.log(son.parentNode)//2.查找节点,父级div.father将本身和子级div.son隐藏son.parentNode.style.display = 'none'</script>
</body>
</html>

运行结果:
运行前:

运行后:

因此这个运行结果相当于css中的给父级div.father添加display:none样式

.father{display:  none;}

2.1.2.高级父级查找语法:

注意:parentNode只能查找最近一级的父级节点,即当前子节点的直接父级节点,更高级别的父级需要编写多个parentNode

爷爷节点查找语法:

   子元素.parentNode.parentNode

2.1.3.关闭二维码案例

需求:关闭二维码案例

素材

<!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></script>
</body></html>

HTML+CSS素材思路分析:

通过子绝父相定位,将关闭按钮定位在二维码图片最左上方

JavaScript 部分

思路:

1.获取子级标签 close_btn;
2.查找父级节点,点击close_btn,,通过父级节点将父级整体(或二维码)隐藏。

代码:

 <script>//1.获取子级标签 close_btnlet btn = document.querySelector('.close_btn')//2.查找父级节点,点击close_btn,,通过父级节点将父级整体(或二维码)隐藏btn.addEventListener('click',function(){btn.parentNode.style.display = 'none'})</script>

运行结果:

2.1.4.关闭多个二维码案例

素材

<!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.获取子级标签 close_btnlet btn = document.querySelector('.close_btn')//2.查找父级节点,点击close_btn,,通过父级节点将父级整体(或二维码)隐藏btn.addEventListener('click',function(){btn.parentNode.style.display = 'none'})</script>
</body></html>

素材分析

erweima为父级盒子,close为子级盒子,erweima设置二维码图片背景,close设置关闭按钮背景,通过子绝父相定位,来将子级盒子close定位在父级盒子erweima最右侧

JavaScript部分

思路分析

总体思路:查找父节点,隐藏父级详细思路:由于每个盒子样式相同且都要逐个关闭,所以采用遍历获取子级元素1.获取子级元素2.事件监听:点击close,关闭或隐藏当前的父级3.查找父级节点,隐藏父级,关闭二维码

我的代码

 //思路://查找父节点,隐藏父级//由于每个盒子样式相同且都要逐个关闭,所以采用遍历获取子级元素//1.获取子级元素let close = document.querySelectorAll('.close')//2.事件监听:点击close,关闭或隐藏当前的父级for(let i = 0;i < close.length;i++){close[i].addEventListener('click',function(){//3.查找父级节点,隐藏父级,关闭二维码this.parentNode.style.display = 'none'})}

我的代码运行效果:
点击关闭按钮,从底部向上(或自底向上)关闭二维码,没有实现点击当前二维码实现关闭效果

参考代码

script>// 1. 获取元素  关闭按钮let close_btn = document.querySelectorAll('.close')// 2. 绑定多个点击事件给closefor (let i = 0; i < close_btn.length; i++) {close_btn[i].addEventListener('click', function () {// 3. 关闭当前的那个二维码  点击谁,就关闭谁的爸爸this.parentNode.style.visibility = 'hidden'})}</script>

优化:
将this.parentNode.style.display = 'none’修改为this.parentNode.style.visibility = ‘hidden’,实现了期望效果

 <script>//思路://查找父节点,隐藏父级//由于每个盒子样式相同且都要逐个关闭,所以采用遍历获取子级元素//1.获取子级元素let close = document.querySelectorAll('.close')//2.事件监听:点击close,关闭或隐藏当前的父级for(let i = 0;i < close.length;i++){close[i].addEventListener('click',function(){//3.查找父级节点,隐藏父级,关闭二维码// this.parentNode.style.display = 'none'this.parentNode.style.visibility = 'hidden'})}</script>

运行结果

拓展:visibility:hidden和display:none的区别

参考文章链接

1.Mr, Jia的csdn博客:visibility:hidden和display:none的区别
https://blog.csdn.net/SoLoJia/article/details/1235155332.你好张淑芬的csdn博客:display:none和visibility:hidden的区别
https://blog.csdn.net/flower521528/article/details/123521504
visibility:hidden display:none
(1) 作用不同 (1)作用不同
可以让元素消失,属于css样式,它只是简单的让元素看不见,但本身的位置还在,如果对div进行hidden,那么div除了看不见,其他所有的样式都在 让这个元素失去块元素的效果,其本身这个元素也是直接消失,会影响到布局问题。
(2)使用后HTML元素有所不同 (2)使用后HTML元素有所不同
使用该属性后,HTML元素(对象)仅仅是在视觉上看不见(完全透明),而它所占据的空间位置仍然存在,也即是说它仍具有高度、宽度等属性值。 使用该属性后,HTML元素(对象)的宽度、高度等各种属性值都将“丢失”。
(3)定义不同 (3)定义不同
定义不同,visibility属性指定一个元素是否是可见的, display这个属性用于定义建立布局时元素生成的显示框类型。

在本例中,由于使用display:none失去块元素的效果,让这个元素直接消失,影响到布局问题,所以引起从底部向上(或自底向上)关闭二维码,没有实现点击当前二维码实现关闭效果。因此本例使visibility:hidden实现隐藏能够更好实现效果。

2.2.子节点查找:

2.2.1.childNodes

获得所有子节点、包括文本节点(空格、换行)、注释节点等

2.2.2.children (重点)

获得所有元素节点,返回的还是一个伪数组

语法:

 子节点查找语法:父元素.children

实例

查找ul中的子级让第一个元素的文字变绿色,再点击button,通过查找子级让父级中的所有子级li文字变红色。

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><button>来点我啊!</button><ul><li>我是孩子</li><li>我是孩子</li><li>我是孩子</li><li>我是孩子</li><li>我是孩子</li><li>我是孩子</li></ul></body>
</html>

思路

//思路:1.获取button按钮和li的父级ul2.查找ul中的子级让第一个元素变绿色3.注册触发点击事件,通过查找子级让父级中的所有子级li变红色3.1.查找子级,让所有子级变红色

代码

//思路://1.获取button按钮和li的父级ullet btn = document.querySelector('button')let ul = document.querySelector('ul')//2.查找ul中的子级让第一个元素变绿色ul.children[0].style.color = 'green'//3.注册触发点击事件,通过查找子级让父级中的所有子级li变红色,btn.addEventListener('click',function(){//观察ul的子级返回的是什么console.log(ul.children)for( let i = 0;i < ul.children.length; i++){//3.1.让所有子级变红色ul.children[i].style.color = 'red'}})//观察使用获取ul子级childNodes效果// console.log(ul.childNodes)


2.3.兄弟关系查找:

2.3.1. 下一个兄弟节点

nextElementSibling 属性

2.3.2. 上一个兄弟节点

previousElementSibling 属性

实例

点击button,让ul中的three类的li标签变蓝色和它的前一个兄弟变红及后一个兄弟的li标签变天蓝色

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><button>点击</button><ul><li>第1个</li><li>第2个</li><li class="three">第3个</li><li>第4个</li><li>第5个</li><li>第6个</li><li>第7个</li><li>第8个</li></ul>
</body>
</html>

思路:

       1.获取button和three类标签     2,注册事件触发btn,让ul中的three类的li标签文字变蓝色和它的前一个兄弟文字变红及后一个兄弟的li标签文字变天蓝色;2.1.让ul中的three类的li标签变蓝色2.2.查找下一个兄弟节点,three前一个兄弟(第2个)文字变红2.3.查找后一个兄弟节点,three下一个兄弟的(第4个)li标签文字变天蓝色

代码:

<!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><button>点击</button><ul><li>第1个</li><li>第2个</li><li class="three">第3个</li><li>第4个</li><li>第5个</li><li>第6个</li><li>第7个</li><li>第8个</li></ul><script>//点击button,让ul中的three类的li标签和它的前一个兄弟变红及后一个兄弟的li标签变天蓝色//   1.获取button和three类标签     let btn = document.querySelector('button')let three =document.querySelector('.three')//2,注册事件触发btn,让ul中的three类的li标签文字变蓝色和它的前一个兄弟文字变红及后一个兄弟的li标签文字变天蓝色btn.addEventListener('click',function(){//2.1.让ul中的three类的li标签变蓝色three.style.color = 'blue'//2.2.查找下一个兄弟节点,three前一个兄弟(第2个)文字变红three.nextElementSibling.style.color = 'red'//2.3.查找后一个兄弟节点,three下一个兄弟(第4个)的li标签文字变天蓝色three.previousElementSibling.style.color = 'skyblue'})</script></body>
</html>

运行结果:
运行前:

运行后:

3.增加节点

很多情况下,我们需要在页面中增加元素,比如,点击发布按钮,可以新增一条信息

一般情况下,我们新增节点,按照如下操作:

(1).创建一个新的节点

(2). 把创建的新的节点放入到指定的元素内部

3.1.创建节点

即创造出一个新的网页元素,再添加到网页内,一般先创建节点,然后插入节点

创建元素节点方法:

document.createElement('要创建节点的标签名')

3.2.追加节点

要想在界面看到,还得插入到某个父元素中

3.2.1.插入到父元素的最后一个子元素:

插入到父元素的最后一个子元素,从最后一个子元素后面开始追加新节点,(或当子元素为空时的,追加第一个元素)

语法:

父元素.appendChild(要插入的子元素)

3.2.2.插入到父元素中某个子元素的前面:

语法:

父元素.insertBefore(要追加的子元素,放到的前面哪个子元素)

注意
1.括号内写的是变量,不要写 ’ ‘,创建元素时要加入’‘,此时该元素不是变量,追加元素不要加’',此时元是变量;
2.插入到父元素中某个子元素的前面中追加第一个元素语法

父元素.insertBefore(要追加的子元素,父级.children[0])

实例1

在父级ul中创建并分别在最后一个元素后面追加类名为one以及文本内容为’我是Tuffy’的新的节点为和第二个元素前面追加类名为two,文本内容为’我是尼格买提’的新的节点

<!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>我是Tom</li><li>我是Jerry</li><li>我是Spike</li></ul></body>
</html>

思路:

1.获取父级标签,创建要追加的子级节点
2.添加新节点的类名属性和文本
3.追加节点, 在最后一个元素后面追加类名为one以及文本内容为'我是Tuffy'的新的节点
4.追加节点,第二个元素前面追加新的节点,第二个元素前面追加类名为two,文本内容为'我是尼格买提'的新的节点

代码:

<!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>我是Tom</li><li>我是Jerry</li><li>我是Spike</li></ul><script>//   1.创建节点// document.createElement('要创建节点的标签名')     // let div = document.createElement('div')// //创建divclass类名属性节点// div.className = 'current'//在父级ul中创建并分别在最后一个元素后面追加类名为one以及文本内容为'我是Tuffy'的新的节点为和第二个元素前面追加类名为two,文本内容为'我是尼格买提'的新的节点//1.获取父级标签,创建要追加的子级节点let ul = document.querySelector('ul')let li = document.createElement('li')let lis = document.createElement('li')//2.添加新节点的类名属性和文本li .className = 'one'li.innerHTML = '我是Tuffy'lis.className = 'two'lis.innerHTML= '我是尼格买提'//3.追加节点, 在最后一个元素后面追加类名为one以及文本内容为'我是Tuffy'的新的节点//插入到父元素的最后一个子元素,从最后一个子元素后面开始追加新节点,(或当子元素为空时的,追加第一个元素)//父元素.appendChild(要插入的子元素),// 注意:括号内写的是变量,不要写'',创建元素时要加入'',此时该元素不是变量,追加元素不要加'',此时元素是变量// 如: ul.appendChild('li') 不能顺利追加liul.appendChild(li)//4.追加节点,第二个元素前面追加新的节点,第二个元素前面追加类名为two,文本内容为'我是尼格买提'的新的节点//插入到父元素中某个子元素的前面//语法:父元素.insertBefore(要追加的子元素,放到的前面哪个子元素)ul.insertBefore(lis,ul.children[1])</script>
</body>
</html>

运行结果:

实例2:从后面创建和追加第一个元素’我是Tuffy’的新的节点,从前面追加第一个元素’我是尼格买提’

<!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></ul></body>
</html>

思路:


1.获取父级标签,创建要追加的子级节点
2.添加新节点的文本
3.追加节点, 在最后一个元素后面追加文本内容为'我是Tuffy'的新的节点
4.追加节点,当前第一个元素前面追加文本内容为'我是尼格买提'的新的节点

代码:

<!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>我是Tom</li><li>我是Jerry</li><li>我是Spike</li> --></ul><script>//1.获取父级标签,创建要追加的子级节点let ul = document.querySelector('ul')let li = document.createElement('li')let lis = document.createElement('li')//2.添加新节点的类名文本li.innerHTML = '我是Tuffy'lis.innerHTML= '我是尼格买提'//3.追加节点, 在最后一个元素后面追加文本内容为'我是Tuffy'的新的节点//插入到父元素的最后一个子元素,从最后一个子元素后面开始追加新节点,(或当子元素为空时的,追加第一个元素)//父元素.appendChild(要插入的子元素),// 注意:括号内写的是变量,不要写'',创建元素时要加入'',此时该元素不是变量,追加元素不要加'',此时元素是变量// 如: ul.appendChild('li') 不能顺利追加liul.appendChild(li)// //4.追加节点,当前第一个元素前面追加文本内容为'我是尼格买提'的新的节点// //插入到父元素中某个子元素的前面// //语法:父元素.insertBefore(要追加的子元素,放到的前面哪个子元素)//插入到父元素中某个子元素的前面中追加第一个元素语法:// 父元素.insertBefore(要追加的子元素,父级.children[0])// ul.insertBefore(lis,ul.children[1])ul.insertBefore(lis,ul.children[0])</script>
</body>
</html>

运行结果:

将ul.insertBefore(lis,ul.children[0])注释,观察运行结果


将ul.insertBefore(lis,ul.children[0])取消注释,观察运行结果

3.2.3.综合案例-学成在线

案例渲染

需求:按照数据渲染页面

项目准备

静态页面代码

(代码已在素材中给出)

盒子模型简要分析

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>学成在线首页</title><link rel="stylesheet" href="style.css"><style></style>
</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="data:images/course01.png" alt=""><h4>Think PHP 5.0 博客系统实战项目演练</h4><div class="info"><span>高级</span> • <span>1125</span>人在学习</div></li><li><img src="data:images/course01.png" alt=""><h4>Think PHP 5.0 博客系统实战项目演练</h4><div class="info"><span>高级</span> • <span>1125</span>人在学习</div></li><li><img src="data:images/course01.png" alt=""><h4>Think PHP 5.0 博客系统实战项目演练</h4><div class="info"><span>高级</span> • <span>1125</span>人在学习</div></li><li><img src="data:images/course01.png" alt=""><h4>Think PHP 5.0 博客系统实战项目演练</h4><div class="info"><span>高级</span> • <span>1125</span>人在学习</div></li><li><img src="data:images/course01.png" alt=""><h4>Think PHP 5.0 博客系统实战项目演练</h4><div class="info"><span>高级</span> • <span>1125</span>人在学习</div></li><li><img src="data:images/course01.png" alt=""><h4>Think PHP 5.0 博客系统实战项目演练</h4><div class="info"><span>高级</span> • <span>1125</span>人在学习</div></li><li><img src="data:images/course01.png" alt=""><h4>Think PHP 5.0 博客系统实战项目演练</h4><div class="info"><span>高级</span> • <span>1125</span>人在学习</div></li><li><img src="data:images/course01.png" alt=""><h4>Think PHP 5.0 博客系统实战项目演练</h4><div class="info"><span>高级</span> • <span>1125</span>人在学习</div></li></ul></div></div></body></html>
css部分
* {margin: 0;padding: 0;
}
.w {width: 1200px;margin: auto;
}
body {background-color: #f3f5f7;
}
li {list-style: none;
}
a {text-decoration: none;
}
.clearfix:before,.clearfix:after {content:"";display:table; }.clearfix:after {clear:both;}.clearfix {*zoom:1;}   .header {height: 42px;/* background-color: pink; *//* 注意此地方会层叠 w 里面的margin */margin: 30px auto;
}
.logo {float: left;width: 198px;height: 42px;
}
.nav {float: left;margin-left: 60px;
}
.nav ul li {float: left;margin: 0 15px;
}
.nav ul li a {display: block;height: 42px;padding: 0 10px;line-height: 42px;font-size: 18px;color: #050505;
}
.nav ul li a:hover {border-bottom: 2px solid #00a4ff;color: #00a4ff;
}
/* search搜索模块 */
.search {float: left;width: 412px;height: 42px;margin-left: 70px;
}
.search input {float: left;width: 345px;height: 40px;border: 1px solid #00a4ff;border-right: 0;color: #bfbfbf;font-size: 14px;padding-left: 15px;
}
.search button {float: left;width: 50px;height: 42px;/* 按钮button默认有个边框需要我们手动去掉 */border: 0;background: url(images/btn.png);
}
.user {float: right;line-height: 42px;margin-right: 30px;font-size: 14px;color: #666;
}
/* banner区域 */
.banner {height: 421px;background-color: #1c036c;
}
.banner .w {height: 421px;background: url(images/banner2.png) no-repeat top center;
}
.subnav {float: left;width: 190px;height: 421px;background: rgba(0,0,0, 0.3);
}
.subnav ul li {height: 45px;line-height: 45px;padding: 0 20px;
}
.subnav ul li a {font-size: 14px;color: #fff;
}
.subnav ul li a span {float: right;
}
.subnav ul li a:hover {color: #00a4ff;
}
.course {float: right;width: 230px;height: 300px;background-color: #fff;/* 浮动的盒子不会有外边距合并的问题 */margin-top: 50px;
}
.course h2 {height: 48px;background-color: #9bceea;text-align: center;line-height: 48px;font-size: 18px;color: #fff;
}
.bd {padding: 0 20px;
}
.bd ul li {padding: 14px 0;border-bottom: 1px solid #ccc;
}
.bd ul li h4 {font-size: 16px;color: #4e4e4e;
}
.bd ul li p {font-size: 12px;color: #a5a5a5;
}
.bd .more {display: block;height: 38px;border: 1px solid #00a4ff;margin-top: 5px;text-align: center;line-height: 38px;color: #00a4ff;font-size: 16px;font-weight: 700;
}
/* 精品推荐模块 */
.goods {height: 60px;background-color: #fff;margin-top: 10px;box-shadow: 0 2px 3px 3px rgba(0,0,0, 0.1);/* 行高会继承, 会继承给3个孩子 */line-height: 60px;
}
.goods h3 {float: left;margin-left: 30px;font-size: 16px;color: #00a4ff;
}
.goods ul {float: left;margin-left: 30px;
}
.goods ul li {float: left;
}
.goods ul li a {padding: 0 30px;font-size: 16px;color: #050505;border-left: 1px solid #ccc;
}
.mod {float: right;margin-right: 30px;font-size: 14px;color: #00a4ff;
}
.box {margin-top: 30px;
}
.box-hd {height: 45px;
}
.box-hd h3 {float: left;font-size: 20px;color: #494949;
}
.box-hd a {float: right;font-size: 12px;color: #a5a5a5;margin-top: 10px;margin-right: 30px;
}
/* 把li 的父亲ul 修改的足够宽一行能装开5个盒子就不会换行了 */
.box-bd ul {width: 1225px;
}
.box-bd ul li {position: relative;top: 0;float: left;width: 228px;height: 270px;background-color: #fff;margin-right: 15px;margin-bottom: 15px;transition: all .3s;}
.box-bd ul li:hover {top: -8px;box-shadow: 2px 2px 2px 2px rgba(0,0,0,.3);
}
.box-bd ul li img {width: 100%;
}
.box-bd ul li h4 {margin: 20px 20px 20px 25px;font-size: 14px;color: #050505;font-weight: 400;
}
.box-bd .info {margin: 0 20px 0 25px;font-size: 12px;color: #999;
}
.box-bd .info span {color: #ff7c2d;
}
/* footer 模块 */
.footer {height: 415px;background-color: #fff;
}
.footer .w {padding-top: 35px;
}
.copyright {float: left;
}
.copyright p {font-size: 12px;color: #666;margin: 20px 0 15px 0;
}
.copyright .app {display: block;width: 118px;height: 33px;border: 1px solid #00a4ff;text-align: center;line-height: 33px;color: #00a4ff;font-size: 16px;
}
.links {float: right;
}
.links dl {float: left;margin-left: 100px;
}
.links dl dt {font-size: 16px;color: #333;margin-bottom: 5px;
}
.links dl dd a {color: #333;font-size: 12px;
}

JavaScript部分准备

data是一个数组对象里面存放数据

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},]

JavaScript部分需求实现代码

思路分析
1.创建子级节点,并在页面追加渲染出若干个li
2.通过js数组对象操作,逐一修改li里面的内容
我的代码

没有实现需求,写了for循环,但是只追加渲染了一个li

<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}]//创建子级节点,并在页面追加渲染出若干个li//通过js数组对象操作,逐一修改li里面的内容//1.获取父级元素,创建子级节点let ul = document.querySelector('ul')let li = document.createElement('li')for(let i = 0 ; i < data.length ; i++){ul.appendChild(li)}</script>
参考代码
<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. 创建小lilet 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>
我的代码bug分析

我的创建节点和追加节点操作没有同时和在一个地方进行,应当是在哪创建节点,就在哪追加节点,创建多少个子节点,就追加多少个子节点,而我的代码中创建了一个节点,却追加了data.length个节点,即创建节点应当写在for循环内部,也要创建data.length个节点

我的代码优化和完善
思路:
总体思路:创建子级节点,并在页面追加渲染出若干个li,通过innerHTML以及js数组对象逐一修改li里面的内容详细思路:1.在html将父级ul置空,获取父级元素ul2.根据数据数组data里面元素个数,循环创建和追加子级元素li,并先修改子级li里面的内容再追加给父级ul2.1.创建子级元素li2.2.通过innerHTML修改子级li里面的内容,使用反引号``包裹标签,用数组对象的属性填充数据2.3.将li追加给ul,从后和前面追加均可
代码:
<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}]//创建子级节点,并在页面追加渲染出若干个li//通过innerHTML以及js数组对象逐一修改li里面的内容//1.在html将父级ul置空,获取父级元素ullet ul = document.querySelector('ul')//2.根据数据数组data里面元素个数,循环创建和追加子级元素li,并先修改子级li里面的内容再追加给父级ulfor(let i = 0 ; i < data.length ; i++){//2.1.创建子级元素lilet li = document.createElement('li')//2.2.通过innerHTML修改子级li里面的内容,使用反引号``包裹标签,用数组对象的属性填充数据li.innerHTML = `<img src="${data[i].src}" alt=""><h4>${data[i].title}</h4><div class="info"><span>高级</span> • <span> ${data[i].num}</span>人在学习</div>`//2.3.将li追加给ul,从后和前面追加均可//从后面正序追加ul.appendChild(li)// //从前面倒序追加// ul.insertBefore(li,ul.children[0])}</script>
我的代码优化和完善后的运行结果

从后面正序追加

从前面倒序追加

3.2.4.克隆节点

克隆节点概念

特殊情况下(如:淘宝轮播图无缝滚动),我们新增节点,按照如下操作:

(1)复制一个原有的节点

(2) 把复制的节点放入到指定的元素内部

克隆节点语法:

元素.cloneNode(布尔值)

cloneNode,会克隆出一个跟原标签一样的元素,括号内传入布尔值:

(1)若为true,则代表克隆时会包含后代节点一起克隆

(2)若为false,则代表克隆时不包含后代节点

默认为false

实例
在body标签中克隆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>
</head>
<body><ul><li>内容内容</li></ul></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><ul><li>内容内容</li></ul><script>//克隆节点//语法:元素.cloneNode(布尔值)//如果括号为空则默认为false,若为false,则不克隆后代节点//在body标签中克隆ul带有后代节点以及不带有后代节点//1.获取ul标签,let ul = document.querySelector('ul')//2,克隆ul,且ul带有后代节点let newUL = ul.cloneNode(true)//2.1.在body追加克隆的uldocument.body.appendChild(newUL)//3,克隆ul,且ul不带有后代节点let newUl = ul.cloneNode(false)//3.1.在body追加克隆的uldocument.body.appendChild(newUl)</script>
</body>
</html>

运行结果:

4.删除节点

4.1.删除节点的概念

若一个节点在页面中已不需要时,可以删除它

在 JavaScript 原生DOM操作中,要删除元素必须通过父元素删除

4.2.删除节点语法

父元素.removeChild(子元素)

注:

(1).如不存在父子关系则删除不成功

(2).删除节点和隐藏节点(display:none) 有区别的: 隐藏节点还是存在的,但是删除,则从html中删除节点

实例:

需求:点击按钮,删除li

<!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><button>点击</button><ul><li>我是内容11111</li></ul></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><button>点击</button><ul><li>我是内容11111</li></ul><script>// 需求:点击按钮,删除li//1.获取标签 按钮button和父级ullet btn = document.querySelector('button')let ul = document.querySelector('ul')//2.注册事件,删除子级节点btn.addEventListener('click',function(){//删除节点的语法 父元素.removeChild(子元素)ul.removeChild(ul.children[0])})</script>
</body>
</html>

运行结果:

点击前:

点击后:

5.时间对象

  • 实例化

  • 时间对象方法

  • 时间戳

5.1.时间对象的概念和作用

时间对象:用来表示时间的对象

作用:可以得到当前系统时间

5.2.实例化

在代码中发现了 new 关键字时,一般将这个操作称为实例化

创建一个时间对象并获取时间

5.2.1.获得当前时间

语法:

 //获得当前时间let 变量名 = new Date()
//小括号为空可以得到当前的时间

5.2.2.获得指定时间

使用场景:指定时间为了在某年某月某日做一件事而做准备,比如:倒计时
语法:

  //小括号里面写上时间,可以返回指定的时间let 变量名 = new Date('年-月-日 时:分:秒')

例:

<script>//实例化//声明数组,写法一let arr = []//观察获取数组console.log(arr)//声明数组,写法二,实例化声明数组let arr1 = new Array()//观察获取数组console.log(arr1)//声明对象,写法一let obj = {}//观察获取对象console.log(obj)//声明对象,写法二,实例化声明对象let obj1 = new Object()//观察获取对象console.log(obj1)//new 实例化 时间对象//1.获得当前时间//语法:let 变量名 = new Date()//小括号为空可以得到当前的时间let date = new Date()//观察获取的当前时间console.log(date)//2.获得指定时间//小括号里面写上时间,可以返回指定的时间//语法:// let 变量名 = new Date('年-月-日 时:分:秒')let date1 = new Date('2022-7-20 15:00:30')//观察获取指定的时间console.log(date1)</script>

5.3.时间对象方法

5.3.1.时间对象方法与作用


方 法             作 用               说 明getFullYear() 获得年份             获取四位年份getMonth()    获得月份             取值为 0 ~ 11 (实际开发中需要+1,写成getMonth()+1)getDate()     获取月份中的每一天    不同月份取值也不相同getDay()      获取星期             取值为 0 ~ 6getHours()    获取小时             取值为 0 ~ 23getMinutes()  获取分钟             取值为 0 ~ 59getSeconds()  获取秒               取值为 0 ~ 59

5.3.2.时间对象方法与作用案例

例1:实例化后时间对象,观察时间对象常用方法

代码与思路:

 //例:实例化后时间对象,观察时间对象常用方法// new 实例化 时间对象//小括号为空可以得到当前的时间//1.实例化时间对象//let 变量名 = new Date()let date = new Date()//2.观察时间对象常用方法//获得年份 console.log(date.getFullYear())//获得月份  实际开发中需要+1,写成getMonth()+1console.log(date.getMonth()+1)// 获取月份中的每一天 console.log(date.getDate())//获取小时 console.log(date.getHours())//获取分钟  console.log(date.getMinutes())//获取秒    console.log(date.getSeconds())//获取星期 console.log(date.getDay())

例2:需求:将当前时间以:YYYY-MM-DD HH:mm 形式显示在页面**

HTML+CSS部分
思路:
自定义编写html和css基础页面,
本例中,我编写一个宽度600px、高度200px、背景颜色为cyan的div盒子,并让盒子中的字体加粗和文字水平垂直居中
代码:
<!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: 600px;height: 200px;background-color: cyan;font-weight:700 ;font-size: 20px;margin: 100px auto;line-height: 200px;text-align: center;}</style>
</head>
<body><!-- 静态初始页面 --><div>2023- 1-17 15: 58 : 54 星期2</div></body>
</html>

JavaScript部分
我的思路与代码:

1.总体思路:

获取标签,实例化时间对象,调用时间对象的方法,修改和写入获取标签的innerHTML中

2.详细思路:

1.获取div标签
2.实例化时间对象
3.调用时间对象常用方法,并将获取的值给相应的变量
4.修改和写入获取标签的innerHTML中

3.代码:

<!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: 600px;height: 200px;background-color: cyan;font-weight:700 ;font-size: 20px;margin: 100px auto;line-height: 200px;text-align: center;}</style>
</head>
<body><!-- 静态初始页面 --><div></div><!-- 2023- 1-17 15: 58 : 54 星期2 --><!--JavaScript部分 --><script>//总体思路:获取标签,实例化时间对象,调用时间对象的方法,修改和写入获取标签的innerHTML中//详细思路与代码://1.获取div标签let getTime = document.querySelector('div')//2.实例化时间对象let time = new Date()//3.调用时间对象常用方法,并将获取的值给相应的变量//获得年份 let year = time.getFullYear()//获得月份  实际开发中需要+1,写成getMonth()+1let month = time.getMonth()+1// 获取月份中的每一天 let day = time.getDate()//获取小时 let hour = time.getHours()//获取分钟  let minutes = time.getMinutes()//获取秒    let seconds = time.getSeconds()//时间对象获取星期let week = time.getDay()// 4.修改和写入获取标签的innerHTML中getTime.innerHTML = `${year}-${month}-${day}&nbsp;&nbsp;${hour}&nbsp;:&nbsp${minutes}&nbsp;:&nbsp${seconds}&nbsp&nbsp;&nbsp;星期${week}`</script></body>
</html>
参考代码:

参考代码使用定时器,将实例化时间对象 写到定时器里面,让显示的时间能够动起来,变成每时每刻的时间,并且先调用函数,就省去了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>div {width: 400px;height: 50px;background-color: pink;text-align: center;line-height: 50px;}</style>
</head><body><div></div><script>let arr = ['星期日', '星期一', '星期二', '星期三', '星期四', '星期五', '星期六']let div = document.querySelector('div')// 先调用,就省去了1秒的空白期getTime()setInterval(getTime, 1000)function getTime() {// 1. 实例化时间对象 一定写到定时器里面才可以额let date = new Date()let year = date.getFullYear()let month = date.getMonth() + 1let date1 = date.getDate()let hour = date.getHours()let min = date.getMinutes()let sec = date.getSeconds()let day = date.getDay()div.innerHTML = `今天是: ${year}年${month}月${date1}日 ${hour}:${min}:${sec} ${arr[day]}`}</script>
</body></html>

运行结果:

我的代码优化:

优化一:启用定时器,让时间随时动态发生过变化
思路:

1.将实例化和调用时间对象以及修改和写入获取标签的innerHTML的代码封装在函数time()中,
2.先调用函数,再把函数写入定时器中,

核心代码:

 //定义函数time存放实例化和调用时间对象,修改和写入获取标签的innerHTMLfunction time(){//2.实例化时间对象let time = new Date()//3.调用时间对象常用方法,并将获取的值给相应的变量//获得年份 let year = time.getFullYear()//获得月份  实际开发中需要+1,写成getMonth()+1let month = time.getMonth()+1// 获取月份中的每一天 let day = time.getDate()//获取小时 let hour = time.getHours()//获取分钟  let minutes = time.getMinutes()//获取秒    let seconds = time.getSeconds()//时间对象获取星期let week = time.getDay()// 4.修改和写入获取标签的innerHTML中//星期部分:将调用时间对象获取的星期数字与存放中文星期的数组的数组序号一一对应//比如:对象获取的星期一中的1对应存放中文星期的数组中的weekend[1]getTime.innerHTML = `${year}-${month}-${day}&nbsp;&nbsp;${hour}&nbsp;:&nbsp${minutes}&nbsp;:&nbsp${seconds}&nbsp&nbsp;&nbsp;星期${weekend[week]}`}//6.调用函数//目的:减少回调函数setInterval(函数名,毫秒数)在先调用执行1000ms再执行time函数产生的空白时间time()//5.启用定时器,让时间随时动态发生过变化//语法:setInterval(函数名,毫秒数)setInterval(time,1000)

细节:先调用函数,再使用定时器,避免1s空挡时间*

若不先调用函数:

time()

结果执行如下:

产生1s空挡时间


原因:
回调函数setInterval(函数名,毫秒数)在先调用执行1000ms再执行time函数

优化二:让星期中的数字中文显示

思路:

1.定时器外定义存放中文星期的数组
2.星期部分:将调用时间对象获取的星期数字与存放中文星期的数组的数组序号一一对应,
比如:对象获取的星期一中的1对应存放中文星期的数组中的weekend[1]

核心代码:

//定义存放中文星期的数组let weekend = ['日','一','二','三','四','五','六']
// 4.修改和写入获取标签的innerHTML中//星期部分:将调用时间对象获取的星期数字与存放中文星期的数组的数组序号一一对应//比如:对象获取的星期一中的1对应存放中文星期的数组中的weekend[1]getTime.innerHTML = `${year}-${month}-${day}&nbsp;&nbsp;${hour}&nbsp;:&nbsp${minutes}&nbsp;:&nbsp${seconds}&nbsp&nbsp;&nbsp;星期${weekend[week]}`

我的优化后的完整代码:

<script>//总体思路:获取标签,实例化时间对象,调用时间对象的方法,修改和写入获取标签的innerHTML中//详细思路与代码://1.获取div标签和定义存放中文星期的数组//获取div标签let getTime = document.querySelector('div')//定义存放中文星期的数组let weekend = ['日','一','二','三','四','五','六']//定义函数time存放实例化和调用时间对象,修改和写入获取标签的innerHTMLfunction time(){//2.实例化时间对象let time = new Date()//3.调用时间对象常用方法,并将获取的值给相应的变量//获得年份 let year = time.getFullYear()//获得月份  实际开发中需要+1,写成getMonth()+1let month = time.getMonth()+1// 获取月份中的每一天 let day = time.getDate()//获取小时 let hour = time.getHours()//获取分钟  let minutes = time.getMinutes()//获取秒    let seconds = time.getSeconds()//时间对象获取星期let week = time.getDay()// 4.修改和写入获取标签的innerHTML中//星期部分:将调用时间对象获取的星期数字与存放中文星期的数组的数组序号一一对应//比如:对象获取的星期一中的1对应存放中文星期的数组中的weekend[1]getTime.innerHTML = `${year}-${month}-${day}&nbsp;&nbsp;${hour}&nbsp;:&nbsp${minutes}&nbsp;:&nbsp${seconds}&nbsp&nbsp;&nbsp;星期${weekend[week]}`}//6.调用函数//目的:减少回调函数setInterval(函数名,毫秒数)在先调用执行1000ms再执行time函数产生的空白时间time()//5.启用定时器,让时间随时动态发生过变化//语法:setInterval(函数名,毫秒数)setInterval(time,1000)</script>

运行结果

补充:

注意:所有关于时间的代码包括实例化必须写在定时器里面,不能写在外面。
实例化必须写在定时器内,当我1s调用时,先得到当前最新的时间,再从最新的时间拿到年月日时分秒。
若写在外面,页面一加载,先执行let time = new Date(),页面的时间将不会变化,因为定时器1s调用的是打开页面的当前时间的时分秒。

5.4.时间戳

5.4.1.时间戳的基本概念

概念

是指1970年01月01日00时00分00秒起至现在的毫秒数,它是一种特殊的计量时间的方式

使用时间戳的目的:

计算剩余时间和倒计时
算出过去的毫秒和现在的毫秒数,两者独立,互不影响,相减即可算出剩余毫秒数,然后再将结果转换为时分秒,得到换算为时分秒的剩余时间。
即:可以利用将来的时间戳减去现在的时间戳就是剩余时间的毫秒数,再将其转换为时分秒就是剩余时间。

5.4.2.三种方式获取时间戳

方式1.使用 getTime() 方法

语法:

//1.实例化let 变量名 = new Date()
//2.获取时间戳//变量名.getTime()console.log(变量名.getTime())

例:

//实例化let date = new Date()
//获取时间戳console.log(date.getTime())

方式2.简写 +new Date()

语法:

// 1).获取当前的时间戳
+new  Date()
// 2) .获取指定时间的时间戳
+new Date('年-月-日 时:分:秒')

例:

//方式2.简写 +new Date()// 1).获取当前的时间戳let b = +new  Date()console.log(b)// 2) .获取指定时间的时间戳//console.log(+new Date('年-月-日 时:分:秒'))let c = +new  Date('2023-1-22 00:00:00')console.log(c)

方式3.使用 Date.now(),只能得到当前的

特点:

1)无需实例化

2)但是只能得到当前的时间戳, 而前面两种可以返回指定时间的时间戳

语法:

Date.now()

例:

let a = Date.now()
console.log(a)

5.4.3.案例-春节倒计时效果

需求:计算到春节还有多少时间

案例

案例总体分析与注意事项:

分析:
①:用将来时间减去现在时间就是剩余的时间
②:核心: 使用将来的时间戳减去现在的时间戳
③:把剩余的时间转换为 天 时 分 秒

注意事项:

  1. 通过时间戳得到是毫秒,需要转换为秒在计算
  2. 转换公式:

d = parseInt(总秒数/ 60/60 /24); // 计算天数

h = parseInt(总秒数/ 60/60 %24) // 计算小时

m = parseInt(总秒数 /60 %60 ); // 计算分数

s = parseInt(总秒数%60); // 计算当前秒数

素材分析:HTML+CSS部分

素材:

<!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></body></html>

盒子模型分析:

countdown是最外层的大盒子,里面包着存放当前日期的next盒子、存放倒计时主题:下班倒计时title盒子、存放剩余时间的clock盒子以及存放现在的时分秒的tips盒子。此外,"clock盒子内包着剩余时间时分秒的hour、minutes以及scond三个盒子和两个i标签。

JavaScript 部分

需求1:显示当前时间(日期与时分秒)
思路:

总体思路

获取标签、实例化时间对象和调用时间对象方法,修改有关标签的innerHTML属性,通过定时器动态变化时间

详细思路


1.获取存放当前日期的next盒子以及现在时分秒时间的tips盒子
2.将实例化时间对象、调用时间对象方法、修改有关标签的innerHTML属性封装在函数里面,通过定时器执行且动态变化时间
2.1.实例化时间对象
2.2.调用时间对象方法,得到现在的年月日时分秒,时分秒小于10的时候自动补零
2.2.1.调用时间对象方法,得到现在的年月日时分秒,
2.2.2.时分秒小于10的时候自动补零
2.3.修改有关标签的innerHTML属性
3.调用函数减少1s时间空挡
4.定时器回调执行,动态变化时间
代码:
//1.获取存放当前日期的next盒子以及现在时分秒时间的tips盒子let today = document.querySelector('.next')let time = document.querySelector(' .tips')//2.将实例化时间对象、调用时间对象方法、修改有关标签的innerHTML属性封装在函数里面,通过定时器执行且动态变化时间function timeShowing(){//2.1.实例化时间对象let date = new Date()//2.2.调用时间对象方法,得到现在的年月日时分秒,时分秒小于10的时候自动补零//2.2.1.调用时间对象方法,得到现在的年月日时分秒,let year = date.getFullYear() let month = date.getMonth()+1 let day = date.getDate() let hour = date.getHours() let minute = date.getMinutes() let second = date.getSeconds() //2.2.2.时分秒小于10的时候自动补零hour = hour < 10 ?  '0'+ hour: hourminute = minute < 10 ? '0' + minute: minutesecond = second < 10 ? '0' + second: second//2.3.修改有关标签的innerHTML属性today.innerHTML = `今天是${year}年${month}月${day}日`time.innerHTML = `现在是${hour}:${minute}:${second}`}//3.调用函数减少1s时间空挡timeShowing()//4.定时器回调执行,动态变化时间setInterval(timeShowing,1000)

运行结果:

需求2:实现倒计时效果
思路:

总体思路:

1.计算剩余时间的时间戳,将剩余时间的时间戳转换为对应的时分秒,修改剩余时分秒的innerHTML属性,
2.封装剩余时间计算和转换代码封装在函数内,并调用函数,启用定时器让时间动态变化

详细思路:

1.定义变量,存放现在和未来时间戳;
2.定义变量,存放计算存放现在和未来时间戳之差,即:计算将来与现在的剩余时间,注意:时间戳之差的结果单位是毫秒,要将计算结果除以1000;
3.将剩余时间转换为时分秒,小于10的时候自动补零
4.获取剩余时间时分秒对应标签,修改剩余时分秒对应的标签的innerHTML属性
5.定义函数封装所有有关剩余时间计算、结果转换以及修改剩余时分秒的innerHTML属性的代码,调用函数,启用定时器,让剩余时间动态变化
代码:
//5.定义函数封装所有有关剩余时间计算、结果转换以及修改剩余时分秒的innerHTML属性的代码,调用函数,启用定时器,让剩余时间动态变化
//5.1.定义函数封装所有有关剩余时间变量的代码
function getRestTime (){//1.定义变量,存放现在和未来时间戳
let now = +new Date()
let future = +new Date('2023-1-22 00:00:00')//2.定义变量 ,存放计算存放现在和未来时间戳之差,即:计算将来与现在的剩余时间,注意:时间戳之差的结果单位是毫秒,要将计算结果除以1000;
let restTime = (future - now)/1000
//3.将剩余时间转换为时分秒,小于10的时候自动补零
//3.1.将剩余时间转换为时分秒
let restHour = parseInt(restTime/ 60 / 60 % 24) // 计算小时
let restMinute= parseInt(restTime /60 % 60 ); // 计算分数
let restSecond = parseInt(restTime % 60); // 计算当前秒数
//3.2.时分秒小于10的时候自动补零
restHour = restHour < 10 ?  '0'+ restHour: restHour
restMinute = restMinute < 10 ? '0' + restMinute: restMinute
restSecond = restSecond < 10 ? '0' + restSecond: restSecond
//4.获取剩余时间时分秒对应标签,修改剩余时分秒对应的标签的innerHTML属性
//4.1.获取剩余时间时分秒对应标签,
let hourRes = document.querySelector('#hour')
let minuteRes = document.querySelector('#minutes')
let scondRes = document.querySelector('#scond')
// 4.2.修改剩余时分秒对应的标签的innerHTML属性
hourRes.innerHTML = `${restHour}`
minuteRes.innerHTML = `${restMinute}`
scondRes.innerHTML = `${restSecond}`
}
//5.2.调用函数减少1s时间空挡
getRestTime()
//5.3.启用定时器,让剩余时间动态变化
setInterval(getRestTime,1000)


细节:

1.获取未来和现在的时间戳代码

let now = +new Date()
let future = +new Date('2023-1-22 00:00:00')

必须写在函数内,才会在定时器里面起作用;
若将上述代码写在外面运行结果如下:


因为若写在定时器的函数外面,得到的时间戳是浏览器启动时的时间戳,是静态的和固定不变的,并且定时器的数据自动变化只局限于自身内的函数,每隔一定时间,回调执行函数,因此不会调用外面全局变量的现在和未来的时间戳,从而让定时器内函数计算剩余时间的变量动态变化。
2.注意:时间戳之差的结果单位是毫秒,要将计算结果除以1000;
否则剩余时间结果计算出错,1分钟内剩余时间时分秒大幅度同时变化,不符合预期结果。
若不除以1000,运行结果如下:


3.本例中实际计算的剩余几天几小时几分几秒,仍需后期完善出计算和转换剩余天数的结果,由于时间有限,此处不予完善。

完整代码

<!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>// 需求1:显示当前时间(日期与时分秒)//总体思路:获取标签、实例化时间对象和调用时间对象方法,修改有关标签的innerHTML属性,通过定时器动态变化时间//1.获取存放当前日期的next盒子以及现在时分秒时间的tips盒子let today = document.querySelector('.next')let time = document.querySelector(' .tips')//2.将实例化时间对象、调用时间对象方法、修改有关标签的innerHTML属性封装在函数里面,通过定时器执行且动态变化时间function timeShowing(){//2.1.实例化时间对象let date = new Date()//2.2.调用时间对象方法,得到现在的年月日时分秒,时分秒小于10的时候自动补零//2.2.1.调用时间对象方法,得到现在的年月日时分秒,let year = date.getFullYear() let month = date.getMonth()+1 let day = date.getDate() let hour = date.getHours() let minute = date.getMinutes() let second = date.getSeconds() //2.2.2.时分秒小于10的时候自动补零hour = hour < 10 ?  '0'+ hour: hourminute = minute < 10 ? '0' + minute: minutesecond = second < 10 ? '0' + second: second//2.3.修改有关标签的innerHTML属性today.innerHTML = `今天是${year}年${month}月${day}日`time.innerHTML = `现在是${hour}:${minute}:${second}`}//3.调用函数减少1s时间空挡timeShowing()//4.定时器回调执行,动态变化时间setInterval(timeShowing,1000)
//  需求2:实现倒计时效果
//总体思路:
//1.计算剩余时间的时间戳,将剩余时间的时间戳转换为对应的时分秒,修改剩余时分秒的innerHTML属性;
// 2.封装剩余时间计算和转换代码封装在函数内,并调用函数,启用定时器让时间动态变化
//详细思路:
// //1.定义变量,存放现在和未来时间戳
// let now = +new Date()
// let future = +new Date('2023-1-22 00:00:00')
//5.定义函数封装所有有关剩余时间计算、结果转换以及修改剩余时分秒的innerHTML属性的代码,调用函数,启用定时器,让剩余时间动态变化
//5.1.定义函数封装所有有关剩余时间变量的代码
function getRestTime (){//1.定义变量,存放现在和未来时间戳
let now = +new Date()
let future = +new Date('2023-1-22 00:00:00')//2.定义变量 ,存放计算存放现在和未来时间戳之差,即:计算将来与现在的剩余时间,注意:时间戳之差的结果单位是毫秒,要将计算结果除以1000;// let restTime = future - now
let restTime = (future - now)/1000
//3.将剩余时间转换为时分秒,小于10的时候自动补零
//3.1.将剩余时间转换为时分秒
let restHour = parseInt(restTime/ 60 / 60 % 24) // 计算小时
let restMinute= parseInt(restTime /60 % 60 ); // 计算分数
let restSecond = parseInt(restTime % 60); // 计算当前秒数
//3.2.时分秒小于10的时候自动补零
restHour = restHour < 10 ?  '0'+ restHour: restHour
restMinute = restMinute < 10 ? '0' + restMinute: restMinute
restSecond = restSecond < 10 ? '0' + restSecond: restSecond
//4.获取剩余时间时分秒对应标签,修改剩余时分秒对应的标签的innerHTML属性
//4.1.获取剩余时间时分秒对应标签,
let hourRes = document.querySelector('#hour')
let minuteRes = document.querySelector('#minutes')
let scondRes = document.querySelector('#scond')
// 4.2.修改剩余时分秒对应的标签的innerHTML属性
hourRes.innerHTML = `${restHour}`
minuteRes.innerHTML = `${restMinute}`
scondRes.innerHTML = `${restSecond}`
}
//5.2.调用函数减少1s时间空挡
getRestTime()
//5.3.启用定时器,让剩余时间动态变化
setInterval(getRestTime,1000)</script>
</body></html>

6.重绘与重排

6.1. 浏览器是如何进行界面渲染的

(1).浏览器解析(Parser)HTML,生成DOM树(DOM Tree)

(2).同时浏览器解析(Parser) CSS,生成样式规则 (Style Rules)

(3) .根据DOM树和样式规则,生成渲染树(Render Tree)

(4).进行布局 Layout(回流/重排):根据生成的渲染树,得到节点的几何信息(位置,大小),确定页面中的盒子布局

(5).进行绘制 Painting(重绘): 根据计算和获取的信息进行整个页面的绘制(如:给盒子上色、修改字体颜色、修改文字字体等不影响页面布局的操作)

(6).Display: 展示在页面上

6.2.2. 重绘和回流(重排)

1.回流(或称重排)

当渲染树中部分或者全部元素的尺寸、结构、布局等发生改变时,浏览器就会重新渲染部分或全部文档的过程称为 回流。
即涉及影响页面中盒子的尺寸、结构、显示隐藏、内部文字大小等页面布局信息的变化过程就是回流。

2.重绘

由于节点(元素)的样式的改变并不影响它在文档流中的位置和文档布局时(比如:color、background-color、outline等), 称为重绘。
即不影响页面中盒子布局的位置和文档布局就是重绘。

注意:

重绘不一定引起回流,而回流一定会引起重绘。

因为:
(1).若改变一个盒子的背景色,则是重绘过程,这个过程并没有影响页面中盒子的尺寸、结构、布局等信息的变化,所以重绘不一定引起回流。

(2)浏览器在进行页面渲染时,先进行回流,再进行重绘,进行回流时,页面中盒子的尺寸、结构、显示隐藏、内部文字大小等信息发生变化,导致页面结构重新布局,在布局后进行重绘。

会导致回流(重排)的操作:

1.页面的首次刷新

2.浏览器的窗口大小发生改变

3.元素的大小或位置发生改变

4.改变字体的大小

5.内容的变化(如:input框的输入,图片的大小)

6.激活css伪类 (如::hover)

7.脚本操作DOM(添加或者删除可见的DOM元素)

例:

7.综合案例——微博发布

7.1.需求

需求1

  1. 注册input事件
  2. 将文本的内容的长度赋值给对应的数值
  3. 表单的maxlength属性可以直接限制在200个数之间

需求2

克隆预定义好的模板,将模板的hidden属性设置为false, 并最终展示到页面上
判断如果内容为空,则提示不能输入为空, 并且直接return
防止输入无意义空格, 使用字符串.trim()去掉首尾空格, 并将表单的value值设置为空字符串

需求3

获取文本域的内容, 赋值给由模板克隆出来的新标签里面的content.innerText
随机获取数据数组里面的内容, 替换newNode的图片和名称
利用时间对象将时间动态化 new Date().toLocaleString()

需求4

在事件处理函数里面获取点击按钮,注册点击事件
(易错点: 必须在事件里面获取,外面获取不到)
删除对应的元素 (通过this获取对应的那条需要删除的元素)

需求5

将表单域内容重置为空
将userCount里面的内容重置为0

7.2.素材与素材分析

7.2.1.素材

html+css部分

HTML

<div class="w"><!-- 操作的界面 --><div class="controls"><img src="./images/9.6/tip.png" alt="" /><br /><!-- maxlength 可以用来限制表单输入的内容长度 --><textarea placeholder="说点什么吧..." id="area" cols="30" rows="10" maxlength="200"></textarea><div><span class="useCount" id="useCount">0</span><span>/</span><span>200</span><button id="send">发布</button></div></div><!-- 微博内容列表 --><div class="contentList"><ul id="list"><!-- 添加了hidden属性元素会直接隐藏掉 --><li hidden><div class="info"><img class="userpic" src="./images/9.6/03.jpg" /><span class="username">死数据:百里守约</span><p class="send-time">死数据:发布于 2020年12月05日 00:07:54</p></div><div class="content">死数据:111</div><span class="the_del">X</span></li></ul></div></div>

css

 * {margin: 0;padding: 0;}ul {list-style: none;}.w {width: 900px;margin: 0 auto;}.controls textarea {width: 878px;height: 100px;resize: none;border-radius: 10px;outline: none;padding-left: 20px;padding-top: 10px;font-size: 18px;}.controls {overflow: hidden;}.controls div {float: right;}.controls div span {color: #666;}.controls div .useCount {color: red;}.controls div button {width: 100px;outline: none;border: none;background: rgb(0, 132, 255);height: 30px;cursor: pointer;color: #fff;font: bold 14px '宋体';transition: all 0.5s;}.controls div button:hover {background: rgb(0, 225, 255);}.controls div button:disabled {background: rgba(0, 225, 255, 0.5);}.contentList {margin-top: 50px;}.contentList li {padding: 20px 0;border-bottom: 1px dashed #ccc;position: relative;}.contentList li .info {position: relative;}.contentList li .info span {position: absolute;top: 15px;left: 100px;font: bold 16px '宋体';}.contentList li .info p {position: absolute;top: 40px;left: 100px;color: #aaa;font-size: 12px;}.contentList img {width: 80px;border-radius: 50%;}.contentList li .content {padding-left: 100px;color: #666;word-break: break-all;}.contentList li .the_del {position: absolute;right: 0;top: 0;font-size: 28px;cursor: pointer;}

JavaScript

// maxlength 是一个表单属性, 作用是给表单设置一个最大长度// 模拟数据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' },]

7.2.2.素材分析

w大盒子包含controls和contentList两个盒子,controls盒子包含textarea标签和div标签,div标签包含3个span标签和一个button发布按钮,然后通过css调整样式和改变盒子的位置,在input标签添加 maxlength="200"来限制用户输入


contentList盒子内包含list类的ul盒子,后期通过js向list里面追加li,li标签里面包含info、content、the del 这三个盒子,其中info盒子存放用户的发布信息的细节信息:用户头像userpic盒子、用户名username盒子、信息发布时间send-time盒子,content盒子用来存放用户发布信息的内容,the del盒子用来操作删除的盒子。

7.3.需求实现

7.3.1.需求1:文本区域输入文字,字数统计同步变化

  1. 注册input事件
  2. 将文本的内容的长度赋值给对应的数值
  3. 表单的maxlength属性可以直接限制在200个数之间

代码与思路

// 需求1// 1. 注册input事件// 2. 将文本的内容的长度赋值给对应的数值// 3. 表单的maxlength属性可以直接限制在200个数之间//思路://1.获取文本内容textarea标签和控制字数变化的useCount盒子标签let textarea = document.querySelector('textarea')let useCount = document.querySelector('#useCount')//2.事件监听,input事件,文本内容值得长度 value.length发生变化textarea.addEventListener('input',function(){// console.log(textarea.value.length)useCount.innerHTML = textarea.value.length})

运行结果:

7.3.2.需求2 :判断用户输入内容是否为空,并给予用户弹窗提示

详细需求

克隆预定义好的模板,将模板的hidden属性设置为false, 并最终展示到页面上
判断如果内容为空,则提示不能输入为空, 并且直接return
防止输入无意义空格, 使用字符串.trim()去掉首尾空格, 并将表单的value值设置为空字符串

思路:

总体思路:
点击发布,判断输入内容不能为空,并将去掉首尾空格, 并将表单的value值设置为空字符串详细思路
//1.事件监听,点击发布,事件监听用户输入内容value值是否为空 ,返回提示输入输入内容不能为空,请重新输入的提示;
//2.使用字符串.trim()去掉首尾空格, 并将表单的value值设置为空字符串

代码:

//总体思路://点击发布,判断输入内容不能为空,并将去掉首尾空格, 并将表单的value值设置为空字符串//详细思路//1.获取发送按钮标签//2.事件监听,点击发布,事件监听用户输入内容value值是否为空 ,返回提示输入输入内容不能为空,请重新输入的提示;//3.使用字符串.trim()去掉首尾空格, 并将表单的value值设置为空字符串let send =document.querySelector('button')send.addEventListener('click',function(){if(textarea.value.trim() === ''){//细节://1.为什么要去空格?//若输入多个空格,点击发布也无法判断输入为空,不能给出输入不能为空,请重新输入的提示;//2.去除空格方法,字符串.trim()//   防止输入无意义空格, 使用字符串.trim()去掉首尾空格//console.log('  str')//console.log('  str '.trim())return alert('输入内容不能为空,请重新输入')}

细节:为什么要去除空格?以及去除空格的方法

1.为什么要去空格?
若输入多个空格,点击发布也无法判断输入为空,不能给出输入不能为空,请重新输入的提示;

2.去除空格方法,字符串.trim(), 防止输入无意义空格, 使用字符串.trim()去掉首尾空格
例:

//2.去除空格方法,字符串.trim()
//   防止输入无意义空格, 使用字符串.trim()去掉首尾空格console.log('  str')console.log('  str '.trim())

7.3.3.需求3:将用户发布的微博信息显示在网页中

详细需求

获取文本域的内容, 赋值给由模板克隆出来的新标签里面的content.innerText
随机获取数据数组里面的内容, 替换newNode的图片和名称
利用时间对象将时间动态化 new Date().toLocaleString()

思路:

业务明确:

必须是用户输入内容并点击发布后,在页面才能显示用户自己发布的各种信息,所以这个需求应当写在监听微博发布事件函数内,
即:这个需求写在需求2的发布微博事件监听中

详细思路:

1.获取父级标签,在父级ul中创建并后面追加li标签和文本内容
2.声明和调用随机函数,生成微博发布后的随机用户信息
3.修改li标签的文本内容,随机替换新子节点的文本内容,利用时间对象将时间动态化
4.追加节点  父元素.insertBefore(子元素, 放到那个元素的前面)

代码:

//1.获取父级标签,在父级ul中创建并后面追加li标签和文本内容//1.1.获取父级标签let list = document.querySelector('#list')//错误:1.1创建父节点list的ul盒子和子节点li// let list = document.createElement('#list')//1.2.创建子节点let li = document.createElement('li')//2.声明和调用随机函数,生成微博发布后的随机用户信息//2.1.声明随机函数function randomGet (min,max){return Math.floor(Math.random()*(max- min + 1))+min}//2.2.调用函数let random = randomGet(0,dataArr.length-1)//3.修改li标签的文本内容,随机替换新子节点的文本内容,利用时间对象将时间动态化li.innerHTML = `<div class="info"><img class="userpic" src = ${dataArr[random].imgSrc} /><span class="username">${dataArr[random].uname}</span><p class="send-time">${new Date().toLocaleString()}</p></div><div class="content">${textarea.value}</div><span class="the_del">X</span>`// 4.追加节点  父元素.insertBefore(子元素, 放到那个元素的前面)list.insertBefore(li,list.children[0])

遇到问题:

增加节点语法出错

错误示例:
获取父节点和子节点,修改子节点的innerHTML,追加子节点导致起初无法在页面中显示li
代码如下:

//错误:1.1创建父节点list的ul盒子和子节点lilet list = document.createElement('#list')//1.2.创建子节点let li = document.createElement('li')//2.声明和调用随机函数,生成微博发布后的随机用户信息//2.1.声明随机函数function randomGet (min,max){return Math.floor(Math.random()*(max- min + 1))+min}//2.2.调用函数let random = randomGet(0,dataArr.length-1)//3.修改li标签的文本内容,随机替换新子节点的文本内容,利用时间对象将时间动态化// 4.追加节点  父元素.insertBefore(子元素, 放到那个元素的前面)list.insertBefore(li,list.children[0])


正确的增加子节点操作是:
获取父级标签,创建子级节点,在父级追加子级元素

补充知识点:实例化生成本地时间

语法:

new Date().toLocaleString()

7.3.4.需求5:控制显示输入空字符和重置

将表单域内容重置为空
将userCount里面的内容重置为0

详细需求:
输入为空或空格,控制输入字数字符为0,发布微博后重置输入内容和控制输入字数字符置零

思路:

需求:输入为空或空格,控制输入字数字符为0,

在微博内容输入事件中判断用户输入字符为空或空格,修改控制字数变化字符的innerHTML设置为0

需求:发布微博后重置输入内容和控制输入字数字符置零

在点击发布微博事件中:1.将输入内容定为空字符串2.将控制输入字数字符的innerHTML定为0
代码:

需求:输入为空或空格,控制输入字数字符为0,

textarea.addEventListener('input',function(){// console.log(textarea.value.length)useCount.innerHTML = textarea.value.length//优化:若用户输入多个空格,控制字数变化的useCount的值为0//判断用户输入字符为空或空格,修改控制字数变化字符的innerHTML设置为0if(textarea.value.trim() === ''){useCount.innerHTML = 0}})


需求:发布微博后重置输入内容和控制输入字数字符置零

send.addEventListener('click',function(){//需求5// 将表单域内容重置为空// 将userCount里面的内容重置为0//1.将输入内容定为空字符串textarea.value = ''//2.将控制输入字数字符的innerHTML定为0useCount.innerHTML = 0})

运行结果
点击发布前:

点击发布后:

7.3.5.需求4:删除微博留言

详细需求:

在事件处理函数里面获取点击按钮,注册点击事件
(易错点: 必须在事件里面获取,外面获取不到)
删除对应的元素 (通过this获取对应的那条需要删除的元素)

思路:
业务明确:只有在生成微博内容的li后,才会有删除标志X的标签
1.获取删除标签,注册点击删除事件,其中删除事件是移除li标签以及里面的所有内容
2.删除节点的语法 父元素.removeChild(子元素)
代码:
 // 需求4// 在事件处理函数里面获取点击按钮,注册点击事件// (易错点: 必须在事件里面获取,外面获取不到)// 删除对应的元素 (通过this获取对应的那条需要删除的元素)//业务明确:只有在生成微博内容的li后,才会有删除标志X的标签//1.获取删除标签,注册点击删除事件,其中删除事件是移除li标签以及里面的所有内容let del = document.querySelector('.the_del')del.addEventListener('click',function(){//2.删除节点的语法 父元素.removeChild(子元素)list.removeChild(li)})

运行结果:

点击孙悟空的留言进行删除:

细节:

1.界面没有X号,就无法获取和绑定事件,要有X号,必须在点击发布后,这样才能做删除微博留言操作,删除必须写在点击发布里面;
2.技巧:点击发布事件,就生成一个新的删除事件,在点击发布后li就绑定一个删除事件,这样在进行删除li时,逐个遍历获取所有的li,即:在追加前面绑定删除事件,创建元素同时顺便绑定事件。
3.删除节点的语法 父元素.removeChild(子元素),直接写子元素的有关js变量
错误示例:
父元素.removeChild(父元素.chilren[子元素数组序号]),这样会报错,无法删除

list.removeChild(list.children[random])

不能这样写,会报错

7.4.完整代码

<!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;}.w {width: 900px;margin: 0 auto;}.controls textarea {width: 878px;height: 100px;resize: none;border-radius: 10px;outline: none;padding-left: 20px;padding-top: 10px;font-size: 18px;}.controls {overflow: hidden;}.controls div {float: right;}.controls div span {color: #666;}.controls div .useCount {color: red;}.controls div button {width: 100px;outline: none;border: none;background: rgb(0, 132, 255);height: 30px;cursor: pointer;color: #fff;font: bold 14px '宋体';transition: all 0.5s;}.controls div button:hover {background: rgb(0, 225, 255);}.controls div button:disabled {background: rgba(0, 225, 255, 0.5);}.contentList {margin-top: 50px;}.contentList li {padding: 20px 0;border-bottom: 1px dashed #ccc;position: relative;}.contentList li .info {position: relative;}.contentList li .info span {position: absolute;top: 15px;left: 100px;font: bold 16px '宋体';}.contentList li .info p {position: absolute;top: 40px;left: 100px;color: #aaa;font-size: 12px;}.contentList img {width: 80px;border-radius: 50%;}.contentList li .content {padding-left: 100px;color: #666;word-break: break-all;}.contentList li .the_del {position: absolute;right: 0;top: 0;font-size: 28px;cursor: pointer;}</style>
</head><body><div class="w"><!-- 操作的界面 --><div class="controls"><img src="./images/9.6/tip.png" alt="" /><br /><!-- maxlength 可以用来限制表单输入的内容长度 --><textarea placeholder="说点什么吧..." id="area" cols="30" rows="10" maxlength="200"></textarea><div><span class="useCount" id="useCount">0</span><span>/</span><span>200</span><button id="send">发布</button></div></div><!-- 微博内容列表 --><div class="contentList"><ul id="list"><!-- 添加了hidden属性元素会直接隐藏掉 --><!-- <li ><div class="info"><img class="userpic" src="./images/9.6/03.jpg" /><span class="username">死数据:百里守约</span><p class="send-time">死数据:发布于 2020年12月05日 00:07:54</p></div><div class="content">死数据:111</div><span class="the_del">X</span></li> --></ul></div></div><script>// maxlength 是一个表单属性, 作用是给表单设置一个最大长度// 模拟数据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// 1. 注册input事件// 2. 将文本的内容的长度赋值给对应的数值// 3. 表单的maxlength属性可以直接限制在200个数之间//思路://1.获取文本内容textarea标签和控制字数变化的useCount盒子标签let textarea = document.querySelector('textarea')let useCount = document.querySelector('#useCount')//2.事件监听,input事件,文本内容值得长度 value.length发生变化textarea.addEventListener('input',function(){// console.log(textarea.value.length)useCount.innerHTML = textarea.value.length//优化:若用户输入多个空格,控制字数变化的useCount的值为0//判断用户输入字符为空或空格,修改控制字数变化字符的innerHTML设置为0if(textarea.value.trim() === ''){useCount.innerHTML = 0}})//需求2// 克隆预定义好的模板,将模板的hidden属性设置为false, 并最终展示到页面上// 判断如果内容为空,则提示不能输入为空, 并且直接return// 防止输入无意义空格, 使用字符串.trim()去掉首尾空格, 并将表单的value值设置为空字符串//总体思路://点击发布,判断输入内容不能为空,并将去掉首尾空格, 并将表单的value值设置为空字符串//详细思路//1.获取发送按钮标签//2.事件监听,点击发布,事件监听用户输入内容value值是否为空 ,返回提示输入输入内容不能为空,请重新输入的提示;//3.使用字符串.trim()去掉首尾空格, 并将表单的value值设置为空字符串let send =document.querySelector('button')send.addEventListener('click',function(){if(textarea.value.trim() === ''){//细节://1.为什么要去空格?//若输入多个空格,点击发布也无法判断输入为空,不能给出输入不能为空,请重新输入的提示;//2.去除空格方法,字符串.trim()//   防止输入无意义空格, 使用字符串.trim()去掉首尾空格// console.log('  str')// console.log('  str '.trim())return alert('输入内容不能为空,请重新输入')}//需求3//获取文本域的内容, 赋值给由模板克隆出来的新标签里面的content.innerText// 随机获取数据数组里面的内容, 替换newNode的图片和名称// 利用时间对象将时间动态化 new Date().toLocaleString()//业务明确:必须是用户输入内容并点击发布后,在页面才能显示用户自己发布的各种信息,所以这个需求应当写在监听微博发布事件函数内,即:这个需求写在需求2的发布微博事件监听中//1.获取父级标签,在父级ul中创建并后面追加li标签和文本内容//1.1.获取父级标签let list = document.querySelector('#list')//错误:1.1创建父节点list的ul盒子和子节点li// let list = document.createElement('#list')//1.2.创建子节点let li = document.createElement('li')//2.声明和调用随机函数,生成微博发布后的随机用户信息//2.1.声明随机函数function randomGet (min,max){return Math.floor(Math.random()*(max- min + 1))+min}//2.2.调用函数let random = randomGet(0,dataArr.length-1)//3.修改li标签的文本内容,随机替换新子节点的文本内容,利用时间对象将时间动态化li.innerHTML = `<div class="info"><img class="userpic" src = ${dataArr[random].imgSrc} /><span class="username">${dataArr[random].uname}</span><p class="send-time">${new Date().toLocaleString()}</p></div><div class="content">${textarea.value}</div><span class="the_del">X</span>`// 4.追加节点  父元素.insertBefore(子元素, 放到那个元素的前面)list.insertBefore(li,list.children[0])//需求5// 将表单域内容重置为空// 将userCount里面的内容重置为0//1.将输入内容定为空字符串textarea.value = ''//2.将控制输入字数字符的innerHTML定为0useCount.innerHTML = 0// 需求4// 在事件处理函数里面获取点击按钮,注册点击事件// (易错点: 必须在事件里面获取,外面获取不到)// 删除对应的元素 (通过this获取对应的那条需要删除的元素)//业务明确:只有在生成微博内容的li后,才会有删除标志X的标签//1.获取删除标签,注册点击删除事件,其中删除事件是移除li标签以及里面的所有内容let del = document.querySelector('.the_del')del.addEventListener('click',function(){//2.删除节点的语法 父元素.removeChild(子元素)list.removeChild(li)//错误示例:父元素.removeChild(父元素.chilren[子元素数组序号])// list.removeChild(list.children[random])})})</script>
</body></html>

8.综合案例-购物车

8.1.需求

8.1.1.需求页面

8.1.2.需求明确

1.点击加号事件

点击加号事件,输入框数字变化且自增,同时启用减号,小计内的价格也发生变化,已经选中的总商品数量和总价也发生变化;

2.点击减号事件

点击减号,输入框数字变化且自减,小计内的价格也发生变化,已经选中的总商品数量和总价也发生变化,当单件商品数量减到0时,禁用减号;

3.点击删除事件

点击删除,输入框数字变化且自增,同时启用减号,小计内的价格也发生变化,已经选中的总商品数量和总价也发生变化,当总商品数量,禁用删除;

4.商品数量总量和总价计算

在点击加号、减号和删除商品后,商品总数和商品总价发生变化

8.2.素材

HTML+CSS部分
HTML

 <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">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">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">40¥</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">70¥</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">0</span>件商品;总价:<span id="totalPrice" class="total-price">0¥</span></p></div></div>

CSS

<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>

8.3.素材分析


car这个大盒子包着table 标签和controls类盒子。table标签包着thead和tbody标签。thead标签里面tr包着商品信息和用户操作行为的内容标题信息。tbody标签中包着4个tr,每个tr包着若干个td,这里的td主要包裹着商品数据和用户对商品的操作(比如:加减商品数量、删除商品和选定商品)。controls类盒子包裹着用户对所有商品的操作信息的盒子(比如:删除所选商品、清理购物车、选中商品数量和价格、以及去支付页面结算)

8.4.我的代码与实现思路(JavaScript部分)

<script>//0.获取标签//获取加号标签let add = document.querySelectorAll('.add')//获取减号标签let reduce = document.querySelectorAll('.reduce')//获取删除标签let del = document.querySelectorAll('.del')//获取商品数量输入框标签inputlet input = document.querySelectorAll('.count-c input')//获取商品单价标签let price = document.querySelectorAll('.price')//获取当前商品小计价格标签let total = document.querySelectorAll('.total')//获取商品总数标签let totalCount = document.querySelector('#totalCount')//获取商品总价标签let totalPrice = document.querySelector('#totalPrice')//获取删除商品数据(即每个商品数据有关的tr的父级)let tbody = document.querySelector('#carBody')//测试获取标签代码// alert(111)// console.log(input)//console.log(add)// console.log(totalCount)// console.log(totalPrice)//1.点击加号事件//点击加号事件,输入框数字变化且自增,同时启用减号,小计内的价格也发生变化,已经选中的总商品数量和总价也发生变化;for(let i = 0 ; i < add.length; i++){// 总价和单价是一样的//total[i].innerText = price[i].innerText// 1.1.注册加号点击事件,修改商品数量有关输入框input数组对象的里面的值value属性发生自增变化、启用减号和商品小计变化add[i].addEventListener('click',function(){  //测试input的value属性自增变化代码// console.log(input.value++)// console.log(input.value)// console.log(input[i].value)// console.log(input[i].value++)//1.2.点击加号,商品数量自增//input[i].value的值是字符串(String类型),需要将其转换为数字型或整数型input[i].value = parseInt(input[i].value)input[i].value ++//1.3点击加号后启用减号reduce[i].disabled = false//1.4.商品小计变化模块//测试观察总计的值// console.log(typeof(price[i].innerHTML))// console.log(typeof(input[i].value))console.log(parseInt(input[i].value ))console.log(parseInt(price[i].innerHTML))// console.log(parseInt(price[i].innerHTML * input[i].value ))//  console.log(parseInt(price[i].innerHTML)*parseInt(input[i].value)) total[i].innerHTML=`${parseInt(price[i].innerHTML)*input[i].value}¥`//1.5调用商品总件数和总价模块totalAccount ()   }  ) }//2.点击减号事件// 点击减号,输入框数字变化且自减,小计内的价格也发生变化,已经选中的总商品数量和总价也发生变化,当单件商品数量减到0时,禁用减号;for (let i = 0 ; i < reduce.length; i++){// 总价和单价是一样的// total[i].innerText = price[i].innerText// 2.1.注册减号点击事件,修改商品数量有关输入框input数组对象的里面的值value属性发生自增变化、商品数量为0禁用减号和商品小计变化reduce[i].addEventListener('click',function(){input[i].value = parseInt(input[i].value)//测试观察input[i].value的值// console.log(input[i].value) input[i].value--//2.2.当商品数量为0,就禁用减号if (input[i].value <= 0){reduce[i].disabled = true}//2.3.商品小计计算total[i].innerHTML=`${parseInt(price[i].innerHTML)*input[i].value}¥`//2.4.调用商品总件数和总价模块totalAccount ()}   ) }//3.点击删除事件// 点击删除,商品数据(即每个商品数据有关的tr)被删除,同时商品总数量和总价也发生变化// 复习// // 需求:点击按钮,删除li//     //1.获取标签 事件触发按钮button和要删除的子级有关的父级ul//     let btn = document.querySelector('button')//     let ul = document.querySelector('ul')//     //2.注册事件,删除子级节点//     btn.addEventListener('click',function(){//         //删除节点的语法 父元素.removeChild(子元素)//         ul.removeChild(ul.children[0])//     })for(let i = 0 ; i < del.length ; i++){// console.log(del[i]);// console.log(tbody.children[i]) // 总价和单价是一样的// total[i].innerText = price[i].innerText//3.1.点击删除,商品数据(即每个商品数据有关的tr)被删除,     del[i].addEventListener('click',function(){//删除tr,它的父级是tbodytbody.removeChild(tbody.children[0])//3.2重新计算删除某个商品后的商品总数和小计总价input[i].value = parseInt(input[i].value)input[i].value--total[i].innerHTML=`${parseInt(price[i].innerHTML)*input[i].value}¥`//3.3.同时商品总数量和总价也发生变化调用商品总件数和总价模块totalAccount ()})}//4.商品总件数和总价模块function totalAccount (){// let total = document.querySelectorAll('.total')// let input = document.querySelectorAll('.count-c input')//4.1.定义和初始化变量numProduct存放总计商品数量,变量priceTotal存放商品总价let numProduct = 0let priceTotal = 0//4.2.循环遍历输入框,计算每个对应商品数量输入框标签input的商品总数和总价for(let i = 0 ; i < input.length; i++){//全局变量与局部变量问题// let num = 0// console.log(input[i].value)numProduct  += parseInt(input[i].value)// console.log(parseInt(total[i].innerHTML))priceTotal  += parseInt(total[i].innerHTML)}//  console.log(numProduct)//4.3.将计算的商品总数和总价写入相应的有关标签//写入商品总数有关标签totalCount.innerHTML = `${numProduct}`//  console.log(priceTotal)//写入商品总价有关标签totalPrice.innerHTML = `${priceTotal}¥`} //4.4.调用商品总件数和总价模块函数,注意:函数名不能与变量名有冲突totalAccount ()//商品总件数和总价模块代码思路// let numProduct = 0// let priceTotal = 0//  for(let i = 0 ; i < input.length; i++){//   //全局变量与局部变量问题//   // let num = 0//   // console.log(input[i].value)//   numProduct  += parseInt(input[i].value)//   // console.log(parseInt(total[i].innerHTML))//   priceTotal  += parseInt(total[i].innerHTML)//  }// //  console.log(numProduct)// totalCount.innerHTML = `${numProduct}`// //  console.log(priceTotal)// totalPrice.innerHTML = `${priceTotal}¥`

点击加号

点击减号

点击删除

8.5.优化

8.5.1.bug分析与修复

1.编写代码过程遇到的bug

(1)调用数组对象属性方法出错

如:input的value属性
有关编写测试代码

错误: console.log(input.value++)console.log(input.value)


修正:
商品数量输入框input标签是document.querySelectorAll获取,得到的一个伪数组NodeList,同时也是一个数组对象,value是数组中一个dom对象属性,因此书写时要带索引号即input[i]

 console.log(input)
console.log(input[i].value)console.log(input[i].value++)


(2)无法修改小计中的价格

原因:没有将单价和商品输入框里面的值修改为数字型或整型
有关测试代码
错误用例:

console.log(typeof(price[i].innerHTML))console.log(typeof(input[i].value))


修复:
parseInt获取字符串前面的数字

 console.log(parseInt(input[i].value ))console.log(parseInt(price[i].innerHTML))   total[i].innerHTML=`${parseInt(price[i].innerHTML)*input[i].value}¥`

(3)遗忘删除节点操作

复习

//复习// 需求:点击按钮,删除li//1.获取标签 事件触发按钮button和要删除的子级有关的父级ullet btn = document.querySelector('button')let ul = document.querySelector('ul')//2.注册事件,删除子级节点btn.addEventListener('click',function(){//删除节点的语法 父元素.removeChild(子元素)ul.removeChild(ul.children[0])})
(4)作用域问题与for循环输出结果预判出错问题——商品总件数和总价模块部分

错误:

一开始编写这个函数时,把商品总数的有关变量初始化和修改有关标签写在for循环里面,导致商品总件数输出的每个商品各自的个数,不是所有商品的总件数,且数据为字符串类型进行计算

    //4.商品总件数和总价模块function totalAccount (){// let total = document.querySelectorAll('.total')// let input = document.querySelectorAll('.count-c input')//4.1.定义和初始化变量numProduct存放总计商品数量,变量priceTotal存放商品总价//4.2.循环遍历输入框,计算每个对应商品数量输入框标签input的商品总数和总价for(let i = 0 ; i < input.length; i++){let numProduct = 0let priceTotal = 0//全局变量与局部变量问题// let numProduct = 0// console.log(input[i].value)numProduct  += input[i].valueconsole.log(parseInt(total[i].innerHTML))priceTotal  += total[i].innerHTMLconsole.log(numProduct)//4.3.将计算的商品总数和总价写入相应的有关标签//写入商品总数有关标签totalCount.innerHTML = `${numProduct}`console.log(priceTotal)//写入商品总价有关标签totalPrice.innerHTML = `${priceTotal}¥`}} 


修复:
分析:
1.我们要得到的计算所有商品总数和商品总价的计算结果,循环内的代码执行是对每种商品的总件数和总价的计算和标签结果文本修改,并不是针对所有商品,而循环输出后的结果是计算所有商品的总件数和总价和标签结果文本修改,且数据为数字类型,需要进行类型转换;
2.由于一开始素材中每件商品件数不为0,若在循环体内声明商品件数和商品总价有关变量为局部变量,则会让有关变量置为循环体中设置的初始化的值,且在循环体外无法输出结果。

修复代码:

 //4.商品总件数和总价模块function totalAccount (){// let total = document.querySelectorAll('.total')// let input = document.querySelectorAll('.count-c input')//4.1.定义和初始化变量numProduct存放总计商品数量,变量priceTotal存放商品总价let numProduct = 0let priceTotal = 0//4.2.循环遍历输入框,计算每个对应商品数量输入框标签input的商品总数和总价for(let i = 0 ; i < input.length; i++){//全局变量与局部变量问题// let num = 0// console.log(input[i].value)numProduct  += parseInt(input[i].value)// console.log(parseInt(total[i].innerHTML))priceTotal  += parseInt(total[i].innerHTML)}//  console.log(numProduct)//4.3.将计算的商品总数和总价写入相应的有关标签//写入商品总数有关标签totalCount.innerHTML = `${numProduct}`//  console.log(priceTotal)//写入商品总价有关标签totalPrice.innerHTML = `${priceTotal}¥`} //4.4.调用商品总件数和总价模块函数,注意:函数名不能与变量名有冲突totalAccount ()

2.代码存在的bug

1.只能从第一个元素正确执行删除商品操作
相关错误代码1

for(let i = 0 ; i < del.length ; i++){// console.log(del[i]);// console.log(tbody.children[i]) //3.1.点击删除,商品数据(即每个商品数据有关的tr)被删除,     del[i].addEventListener('click',function(){tbody.removeChild(tbody.children[0])// tbody.removeChild(this.parentNode.parentNode)//3.2重新计算删除所有商品后的总商品数和总价input[i].value = parseInt(input[i].value)input[i].value--total[i].innerHTML=`${parseInt(price[i].innerHTML)*input[i].value}¥`//3.3.同时商品总数量和总价也发生变化调用商品总件数和总价模块totalAccount ()})}

运行结果:
点击删除单价10元的商品,可是结果删除的5元的商品,且10元的商品单价和件数结果被置为0

相关错误代码2

for(let i = 0 ; i < del.length ; i++){// console.log(del[i]);// console.log(tbody.children[i]) //3.1.点击删除,商品数据(即每个商品数据有关的tr)被删除,     del[i].addEventListener('click',function(){tbody.removeChild(tbody.children[i])// tbody.removeChild(this.parentNode.parentNode)//3.2重新计算删除所有商品后的总商品数和总价input[i].value = parseInt(input[i].value)input[i].value--total[i].innerHTML=`${parseInt(price[i].innerHTML)*input[i].value}¥`//3.3.同时商品总数量和总价也发生变化调用商品总件数和总价模块totalAccount ()})}

运行结果:

修复后的代码
错误代码2是tbody子级tr被删除后,它的索引号发生变化,导致删除时无法找到这个元素

1.核心代码与原理

  tbody.removeChild(this.parentNode.parentNode)

删除当前事件监听元素的爸爸的爸爸
this指向删除(del)这个类标签,它的父级是td,td的父级是tr,tr是tbody要删除的子级,也可四个tr都被循环获取后,再将其被删除。

2.完整代码

 for(let i = 0 ; i < del.length ; i++){// console.log(del[i]);// console.log(tbody.children[i]) //3.1.点击删除,商品数据(即每个商品数据有关的tr)被删除,     del[i].addEventListener('click',function(){// tbody.removeChild(tbody.children[0])tbody.removeChild(this.parentNode.parentNode)//3.2重新计算删除所有商品后的总商品数和总价input[i].value = parseInt(input[i].value)input[i].value--total[i].innerHTML=`${parseInt(price[i].innerHTML)*input[i].value}¥`//3.3.同时商品总数量和总价也发生变化调用商品总件数和总价模块totalAccount ()})}

点击删除单价为10元的商品数据

2.由于素材中的数据是有不正确的计算结果,计算总价的起始结果不正确。

修复措施:
让总价和单价一致

//总价和单价是一样的total[i].innerText = price[i].innerText

8.5.2.参考代码与我的代码对比分析与我的代码优化

参考代码:

 <script>// + - 删除是相同的,一一对应的 我们完全可以用一个for来遍历绑定事件// +let adds = document.querySelectorAll('.add')// -let reduces = document.querySelectorAll('.reduce')// dellet dels = document.querySelectorAll('.del')// 输入框inputlet inputs = document.querySelectorAll('.count-c input')// 单价 price  5let prices = document.querySelectorAll('.price')// 小计 total  5 * 2 = 10let totals = document.querySelectorAll('.total')// 总价元素获取let totalResult = document.querySelector('.total-price')// 总的数量获取let totalCount = document.querySelector('#totalCount')// tbody 获取过来let carBody = document.querySelector('#carBody')for (let i = 0; i < adds.length; i++) {// 总价和单价是一样的totals[i].innerText = prices[i].innerText//1. 加号的操作adds[i].addEventListener('click', function () {// 点击了谁,就让对应的输入框自增就行了inputs[i].value++// 减号要启用reduces[i].disabled = false// prices[i].innerText  得到的是 5¥     parseInt('5¥')  === 5console.log(parseInt(prices[i].innerText))// 计算小计模块 // totals[i].innerText =  单价 * 数量  // totals[i].innerText = 20totals[i].innerText = parseInt(prices[i].innerText) * inputs[i].value + '¥'// 计算现在的总额 调用result()})//2. 减号的操作reduces[i].addEventListener('click', function () {// 点击了谁,就让对应的输入框自增就行了inputs[i].value--// prices[i].innerText  得到的是 5¥     parseInt('5¥')  === 5// console.log(parseInt(prices[i].innerText))// 判断如果表单里面的值 小于等于1 则,禁用按钮if (inputs[i].value <= 1) {this.disabled = true}// 计算小计模块 // totals[i].innerText =  单价 * 数量  // totals[i].innerText = 20totals[i].innerText = parseInt(prices[i].innerText) * inputs[i].value + '¥'// 计算现在的总额 调用result()})// 3. 删除操作dels[i].addEventListener('click', function () {// 父元素.removeChild(子元素)  // 我们要删除的是那个元素   tr  他的爸爸是 tbody// 删除的是当前元素爸爸的爸爸  就是 tr 就是当前的trcarBody.removeChild(this.parentNode.parentNode)// 调用总计模块result()})}// div  span   ul  li  标签  有文字内容  怎么得到或则设置文字内容呢  元素.innerText   元素.innerHTML// 表单  input 单选 复选    textarea  select  怎么得到或则设置值   表单的value // 特殊的  button 是通过inner来设置// 以前数组求和的方式 累加//  计算总价 result 函数  把所有的小计 totals 加起来的结果function result() {// 小计 total  5 * 2 = 10let totals = document.querySelectorAll('.total')// 输入框inputlet inputs = document.querySelectorAll('.count-c input')let sum = 0let num = 0for (let i = 0; i < totals.length; i++) {// sum = sum + 小计的数字  10¥sum = sum + parseInt(totals[i].innerText)num = num + parseInt(inputs[i].value)}// console.log(sum)totalResult.innerText = sum + '¥'// console.log(num)totalCount.innerText = num}result()</script>

1.删除商品数据后总价变化

我的代码是在删除后,在删除商品模块中重新计算删除某个商品后的商品总数和小计总价。

  for(let i = 0 ; i < del.length ; i++){// console.log(del[i]);// console.log(tbody.children[i]) // 总价和单价是一样的total[i].innerText = price[i].innerText//3.1.点击删除,商品数据(即每个商品数据有关的tr)被删除,     del[i].addEventListener('click',function(){//删除tr,它的父级是tbody// tbody.removeChild(tbody.children[0])tbody.removeChild(tbody.children[i])//删除当前事件监听元素的爸爸的爸爸// this指向删除(del)这个类标签,它的父级是td,td的父级是tr,tr是tbody要删除的子级   // tbody.removeChild(this.parentNode.parentNode)//3.2重新计算删除某个商品后的商品总数和小计总价input[i].value = parseInt(input[i].value)input[i].value--total[i].innerHTML=`${parseInt(price[i].innerHTML)*input[i].value}¥`//3.3.同时商品总数量和总价也发生变化调用商品总件数和总价模块totalAccount ()})

参考代码中由于为了避免在页面执行删除操作刷新后页面获取的商品件数和小计得到的还是之前未删除前4个的数据,就在商品总件数和总价模块中重新获取商品被删除后的件数和小计,从而计算商品总件数和总价。

function totalAccount () {// 小计 total  5 * 2 = 10let totals = document.querySelectorAll('.total')// 输入框inputlet inputs = document.querySelectorAll('.count-c input')let sum = 0let num = 0for (let i = 0; i < totals.length; i++) {// sum = sum + 小计的数字  10¥sum = sum + parseInt(totals[i].innerText)num = num + parseInt(inputs[i].value)}// console.log(sum)totalResult.innerText = sum + '¥'// console.log(num)totalCount.innerText = num}

2.合并加号、减号和删除事件的循环

由于执行加号、减号和删除事件都是循环执行且都是对同一列数据操作,因此可以将这三个需求写在同一个循环中。

 for(let i = 0 ; i < add.length; i++){// 总价和单价是一样的total[i].innerText = price[i].innerText// 1.1.注册加号点击事件,修改商品数量有关输入框input数组对象的里面的值value属性发生自增变化、启用减号和商品小计变化add[i].addEventListener('click',function(){  //测试input的value属性自增变化代码// console.log(input.value++)// console.log(input.value)// console.log(input[i].value)// console.log(input[i].value++)//1.2.点击加号,商品数量自增//input[i].value的值是字符串(String类型),需要将其转换为数字型或整数型input[i].value = parseInt(input[i].value)input[i].value ++//1.3点击加号后启用减号reduce[i].disabled = false//1.4.商品小计变化模块//测试观察总计的值// console.log(typeof(price[i].innerHTML))// console.log(typeof(input[i].value))console.log(parseInt(input[i].value ))console.log(parseInt(price[i].innerHTML))// console.log(parseInt(price[i].innerHTML * input[i].value ))//  console.log(parseInt(price[i].innerHTML)*parseInt(input[i].value)) total[i].innerHTML=`${parseInt(price[i].innerHTML)*input[i].value}¥`//1.5调用商品总件数和总价模块totalAccount ()   }  ) //2.点击减号事件// 点击减号,输入框数字变化且自减,小计内的价格也发生变化,已经选中的总商品数量和总价也发生变化,当单件商品数量减到0时,禁用减号;// 2.1.注册减号点击事件,修改商品数量有关输入框input数组对象的里面的值value属性发生自增变化、商品数量为0禁用减号和商品小计变化reduce[i].addEventListener('click',function(){input[i].value = parseInt(input[i].value)//测试观察input[i].value的值// console.log(input[i].value) input[i].value--//2.2.当商品数量为0,就禁用减号if (input[i].value <= 0){reduce[i].disabled = true}//2.3.商品小计计算total[i].innerHTML=`${parseInt(price[i].innerHTML)*input[i].value}¥`//2.4.调用商品总件数和总价模块totalAccount ()}   )
//3.点击删除事件// 点击删除,商品数据(即每个商品数据有关的tr)被删除,同时商品总数量和总价也发生变化// 复习// // 需求:点击按钮,删除li//     //1.获取标签 事件触发按钮button和要删除的子级有关的父级ul//     let btn = document.querySelector('button')//     let ul = document.querySelector('ul')//     //2.注册事件,删除子级节点//     btn.addEventListener('click',function(){//         //删除节点的语法 父元素.removeChild(子元素)//         ul.removeChild(ul.children[0])//     })//3.1.点击删除,商品数据(即每个商品数据有关的tr)被删除,     del[i].addEventListener('click',function(){//删除tr,它的父级是tbody// tbody.removeChild(tbody.children[0])// tbody.removeChild(tbody.children[i])//删除当前事件监听元素的爸爸的爸爸// this指向删除(del)这个类标签,它的父级是td,td的父级是tr,tr是tbody要删除的子级   tbody.removeChild(this.parentNode.parentNode)//3.2.同时商品总数量和总价也发生变化调用商品总件数和总价模块totalAccount ()})}

8.6.优化后的完整代码

<!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">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">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">40¥</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">70¥</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">0</span>件商品;总价:<span id="totalPrice" class="total-price">0¥</span></p></div></div><script>//0.获取标签//获取加号标签let add = document.querySelectorAll('.add')//获取减号标签let reduce = document.querySelectorAll('.reduce')//获取删除标签let del = document.querySelectorAll('.del')//获取商品数量输入框标签inputlet input = document.querySelectorAll('.count-c input')//获取商品单价标签let price = document.querySelectorAll('.price')//获取当前商品小计价格标签let total = document.querySelectorAll('.total')//获取商品总数标签let totalCount = document.querySelector('#totalCount')//获取商品总价标签let totalPrice = document.querySelector('#totalPrice')//获取删除商品数据(即每个商品数据有关的tr的父级)let tbody = document.querySelector('#carBody')//测试获取标签代码// alert(111)// console.log(input)//console.log(add)// console.log(totalCount)// console.log(totalPrice)//1.点击加号事件//点击加号事件,输入框数字变化且自增,同时启用减号,小计内的价格也发生变化,已经选中的总商品数量和总价也发生变化;for(let i = 0 ; i < add.length; i++){// 总价和单价是一样的total[i].innerText = price[i].innerText// 1.1.注册加号点击事件,修改商品数量有关输入框input数组对象的里面的值value属性发生自增变化、启用减号和商品小计变化add[i].addEventListener('click',function(){  //测试input的value属性自增变化代码// console.log(input.value++)// console.log(input.value)// console.log(input[i].value)// console.log(input[i].value++)//1.2.点击加号,商品数量自增//input[i].value的值是字符串(String类型),需要将其转换为数字型或整数型input[i].value = parseInt(input[i].value)input[i].value ++//1.3点击加号后启用减号reduce[i].disabled = false//1.4.商品小计变化模块//测试观察总计的值// console.log(typeof(price[i].innerHTML))// console.log(typeof(input[i].value))console.log(parseInt(input[i].value ))console.log(parseInt(price[i].innerHTML))// console.log(parseInt(price[i].innerHTML * input[i].value ))//  console.log(parseInt(price[i].innerHTML)*parseInt(input[i].value)) total[i].innerHTML=`${parseInt(price[i].innerHTML)*input[i].value}¥`//1.5调用商品总件数和总价模块totalAccount ()   }  ) //2.点击减号事件// 点击减号,输入框数字变化且自减,小计内的价格也发生变化,已经选中的总商品数量和总价也发生变化,当单件商品数量减到0时,禁用减号;// 2.1.注册减号点击事件,修改商品数量有关输入框input数组对象的里面的值value属性发生自增变化、商品数量为0禁用减号和商品小计变化reduce[i].addEventListener('click',function(){input[i].value = parseInt(input[i].value)//测试观察input[i].value的值// console.log(input[i].value) input[i].value--//2.2.当商品数量为0,就禁用减号if (input[i].value <= 0){reduce[i].disabled = true}//2.3.商品小计计算total[i].innerHTML=`${parseInt(price[i].innerHTML)*input[i].value}¥`//2.4.调用商品总件数和总价模块totalAccount ()}   )
//3.点击删除事件// 点击删除,商品数据(即每个商品数据有关的tr)被删除,同时商品总数量和总价也发生变化// 复习// // 需求:点击按钮,删除li//     //1.获取标签 事件触发按钮button和要删除的子级有关的父级ul//     let btn = document.querySelector('button')//     let ul = document.querySelector('ul')//     //2.注册事件,删除子级节点//     btn.addEventListener('click',function(){//         //删除节点的语法 父元素.removeChild(子元素)//         ul.removeChild(ul.children[0])//     })//3.1.点击删除,商品数据(即每个商品数据有关的tr)被删除,     del[i].addEventListener('click',function(){//删除tr,它的父级是tbody// tbody.removeChild(tbody.children[0])// tbody.removeChild(tbody.children[i])//删除当前事件监听元素的爸爸的爸爸// this指向删除(del)这个类标签,它的父级是td,td的父级是tr,tr是tbody要删除的子级   tbody.removeChild(this.parentNode.parentNode)//3.2.同时商品总数量和总价也发生变化调用商品总件数和总价模块totalAccount ()})}//4.商品总件数和总价模块function totalAccount (){let total = document.querySelectorAll('.total')let input = document.querySelectorAll('.count-c input')//4.1.定义和初始化变量numProduct存放总计商品数量,变量priceTotal存放商品总价let numProduct = 0let priceTotal = 0//4.2.循环遍历输入框,计算每个对应商品数量输入框标签input的商品总数和总价for(let i = 0 ; i < input.length; i++){//全局变量与局部变量问题// let num = 0// console.log(input[i].value)numProduct  += parseInt(input[i].value)// console.log(parseInt(total[i].innerHTML))priceTotal  += parseInt(total[i].innerHTML)}//  console.log(numProduct)//4.3.将计算的商品总数和总价写入相应的有关标签//写入商品总数有关标签totalCount.innerHTML = `${numProduct}`//  console.log(priceTotal)//写入商品总价有关标签totalPrice.innerHTML = `${priceTotal}¥`} //4.4.调用商品总件数和总价模块函数,注意:函数名不能与变量名有冲突totalAccount ()//商品总件数和总价模块代码思路// let numProduct = 0// let priceTotal = 0//  for(let i = 0 ; i < input.length; i++){//   //全局变量与局部变量问题//   // let num = 0//   // console.log(input[i].value)//   numProduct  += parseInt(input[i].value)//   // console.log(parseInt(total[i].innerHTML))//   priceTotal  += parseInt(total[i].innerHTML)//  }// //  console.log(numProduct)// totalCount.innerHTML = `${numProduct}`// //  console.log(priceTotal)// totalPrice.innerHTML = `${priceTotal}¥`</script></body></html>

前端JavaScript DOM BOM 自学复盘 D3相关推荐

  1. 前端JavaScript DOM BOM 自学复盘 D1(DOM-获取DOM元素、修改HTML标签/表单/css样式属性、定时器-间歇函数)

    内容概要 1. Web API 基本认知 1.1. 作用和分类 1.2. 什么是DOM 1.3. DOM作用 1.4 DOM树 1.4.1. DOM树是什么? 1.4.2. DOM 树的作用 1.5 ...

  2. 前端JavaScript之BOM与DOM

    什么是BOM,DOM avaScript分为 ECMAScript,DOM,BOM. BOM(Browser Object Model)是指浏览器对象模型,它使 JavaScript 有能力与浏览器进 ...

  3. web前端全部课件(html5+CSS3+javascript+dom+bom+jquery+jqm+bootstrap+angular+ext+weixin+less)...

    一.HTML5 BASIC课件 Unit01:Web基础知识.HTML快速入门.文本 Unit02:图像和链接.表格.结构标记 Unit03:列表.表单.其他常用标记 二.CSS3 BASIC课件 U ...

  4. Web前端——JavaScript(bom文档对象模型)

    >window对象 是bom的顶层对象,其中包含document对象: Window 对象表示浏览器中打开的窗口. 如果文档包含框架(frame 或 iframe 标签),浏览器会为 HTML ...

  5. JavaScript DOM / BOM (查询获取元素对象【增、删、改、查】 )以及常见鼠标事件

    1.查询获取元素(查) 1.1.根据ID获取 document.getElementById('id'); 1.2.根据标签名获取1(使用 getElementsByTagName() 方法可以返回带 ...

  6. JavaScript一线大厂面试秘籍:面向对象+dom\bom+事件+特性\动画+面试题+基础

    JavaScript(简称"JS")是一种具有函数优先的轻量级,解释型或即时编译型的高级编程语言.虽然它是作为开发Web页面的脚本语言而出名的,但是它也被用到了很多非浏览器环境中, ...

  7. 六、前端开发-JavaScript DOM

    六.前端开发语言体系-JavaScript DOM 文章目录 六.前端开发语言体系-JavaScript DOM JavaScript DOM DOM简介 DOM方法 DOM事件 DOM事件监听器 D ...

  8. [Javascript]:BOM对象详解和BOM与DOM的层次关系

    BOM与DOM的结构层次图 BOM对象是什么 BOM:浏览器对象模型(Brower Object Model),是用于操作浏览器而出现的API,BOM对象则是Javascript对BOM接口的实现. ...

  9. JavaScript之BOM和DOM入门

    JavaScript之BOM和DOM入门 JavaScript的组成包含三大部分,分别为ECMAScript.DOM和BOM.JavaScript组成,如下图所示: ECMAScript是JavaSc ...

最新文章

  1. SoapUI实践:自动化测试、压力测试、持续集成
  2. 解读4G发牌事件,了解下4G那点事!
  3. php带截切图片上传_PHP大文件切割上传并带进度条功能示例
  4. salt return mysql_mysql中储存salt返回结果
  5. c++自底向上算符优先分析_PHP程序员从入门到佛系第十弹:PHP 运算符
  6. DDoS攻击原理及防护方法论
  7. 【原创翻译】The Free Lunch Is Over
  8. ubuntu 跟xshell的问题
  9. SpringCloud学习笔记001-SpringCloud_001_SpringCloud简介_单体架构_微服务架构_服务注册与发现_微服务调用关系
  10. 结对-结对编项目作业名称-开发环境搭建过程
  11. Tomcat安装与配置教程(图文教学)
  12. python 阿里云短信接口_阿里云短信接口 (Python)
  13. 575万奖金!2022年数学界「诺贝尔奖」发布,拓扑学大师获奖
  14. 第1课:郭盛华课程_零基础学Linux操作系统
  15. 【学习笔记】seckill-秒杀项目--(11)项目总结
  16. 【摘录】B2C大点名:国内B2C网站收集
  17. 垃圾收集器总结--CMS垃圾收集器
  18. Hook android系统调用研究(一)
  19. 在windows2019利用Bonobo Git Server搭建Git服务器
  20. 计算H时M分S秒以后是_厨房风机选型设计及计算方法

热门文章

  1. JS 根据符号拆分字符串split方法【笔记】
  2. 前端JS字符串转数值 Number和parseInt用法
  3. 软考报名后,这些细节也不容忽略
  4. 月活超抖音的这款App 除了“盗取信息”还有什么猫腻?
  5. 盛世狂欢意犹未尽之恋舞OL折扣平台多角度体验
  6. typeof 关键字的作用
  7. 各向异性渲染(二)Kajiya Kay头发渲染
  8. 【统计信号处理kay 第七章 两道习题python仿真】
  9. web前端网页设计与制作——华夏第一县HTML+CSS+JavaScript
  10. 西电学生邮箱收不到软件激活邮件的解决方法