本系列:(一)JavaScript基础 第1-2天 · (二)JavaScript基础 第3-5天 · (三)Web APIs 第1-3天 · (四)Web APIs 第4-6天与个人实战
Web APIs - 第4天
进一步学习 DOM 相关知识,实现可交互的网页特效
- 能够插入、删除和替换元素节点
- 能够依据元素节点关系查找节点
日期对象
掌握 Date 日期对象的使用,动态获取当前计算机的时间。
ECMAScript 中内置了获取系统时间的对象 Date,使用 Date 时与之前学习的内置对象 console 和 Math 不同,它需要借助 new 关键字才能使用。
实例化
1 2 3 4 5 6 7 8 9
|
const date = new Date('2020-05-01')
console.log(typeof date)
|
方法
1 2 3 4 5 6
| const date = new Date();
const year = date.getFullYear(); const month = date.getMonth();
|
getFullYear 获取四位年份
getMonth 获取月份,取值为 0 ~ 11
getDate 获取月份中的每一天,不同月份取值也不相同
getDay 获取星期,取值为 0 ~ 6
getHours 获取小时,取值为 0 ~ 23
getMinutes 获取分钟,取值为 0 ~ 59
getSeconds 获取秒,取值为 0 ~ 59
时间戳
时间戳是指1970年01月01日00时00分00秒起至现在的总秒数或毫秒数,它是一种特殊的计量时间的方式。
注:ECMAScript 中时间戳是以毫秒计的。
1 2 3 4 5 6 7 8 9
| const date = new Date() console.log(date.getTime())
console.log(+new Date()) console.log(Date.now())
|
获取时间戳的方法,分别为 getTime 和 Date.now 和 +new Date()
DOM 节点
掌握元素节点创建、复制、插入、删除等操作的方法,能够依据元素节点的结构关系查找节点
回顾之前 DOM 的操作都是针对元素节点的属性或文本的,除此之外也有专门针对元素节点本身的操作,如插入、复制、删除、替换等。
插入节点
在已有的 DOM 节点中插入新的 DOM 节点时,需要关注两个关键因素:首先要得到新的 DOM 节点,其次在哪个位置插入这个节点。
如下代码演示:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| <body> <h3>插入节点</h3> <p>在现有 dom 结构基础上插入新的元素节点</p> <hr> <div class="box"></div> <button class="btn">插入节点</button> <script> const btn = document.querySelector('.btn') btn.addEventListener('click', function () { const p = document.createElement('p') p.innerText = '创建的新的p标签' p.className = 'info' const p2 = document.querySelector('p').cloneNode(true) p2.style.color = 'red'
document.querySelector('.box').appendChild(p) document.querySelector('.box').appendChild(p2) }) </script> </body>
|
结论:
-
createElement 动态创建任意 DOM 节点
-
cloneNode 复制现有的 DOM 节点,传入参数 true 会复制所有子节点
-
appendChild 在末尾(结束标签前)插入节点
再来看另一种情形的代码演示:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
| <body> <h3>插入节点</h3> <p>在现有 dom 结构基础上插入新的元素节点</p> <hr> <button class="btn1">在任意节点前插入</button> <ul> <li>HTML</li> <li>CSS</li> <li>JavaScript</li> </ul> <script> const btn1 = document.querySelector('.btn1') btn1.addEventListener('click', function () {
const relative = document.querySelector('li:nth-child(2)')
const li1 = document.createElement('li') li1.style.color = 'red' li1.innerText = 'Web APIs'
const li2 = document.querySelector('li:first-child').cloneNode(true) li2.style.color = 'blue'
document.querySelector('ul').insertBefore(li1, relative) document.querySelector('ul').insertBefore(li2, relative) }) </script> </body>
|
结论:
-
createElement 动态创建任意 DOM 节点
-
cloneNode 复制现有的 DOM 节点,传入参数 true 会复制所有子节点
-
insertBefore 在父节点中任意子节点之前插入新节点
删除节点
删除现有的 DOM 节点,也需要关注两个因素:首先由父节点删除子节点,其次是要删除哪个子节点。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| <body> <button>删除节点</button> <ul> <li>HTML</li> <li>CSS</li> <li>Web APIs</li> </ul>
<script> const btn = document.querySelector('button') btn.addEventListener('click', function () { let ul = document.querySelector('ul') let lis = document.querySelectorAll('li')
ul.removeChild(lis[0]) }) </script> </body>
|
结论:removeChild 删除节点时一定是由父子关系。
查找节点
DOM 树中的任意节点都不是孤立存在的,它们要么是父子关系,要么是兄弟关系,不仅如此,我们可以依据节点之间的关系查找节点。
父子关系
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| <body> <button class="btn1">所有的子节点</button> <ul> <li>HTML</li> <li>CSS</li> <li>JavaScript 基础</li> <li>Web APIs</li> </ul> <script> const btn1 = document.querySelector('.btn1') btn1.addEventListener('click', function () { const ul = document.querySelector('ul')
console.log(ul.childNodes) console.log(ul.children) }) </script> </body>
|
结论:
childNodes 获取全部的子节点,回车换行会被认为是空白文本节点
children 只获取元素类型节点
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
| <body> <table> <tr> <td width="60">序号</td> <td>课程名</td> <td>难度</td> <td width="80">操作</td> </tr> <tr> <td>1</td> <td><span>HTML</span></td> <td>初级</td> <td><button>变色</button></td> </tr> <tr> <td>2</td> <td><span>CSS</span></td> <td>初级</td> <td><button>变色</button></td> </tr> <tr> <td>3</td> <td><span>Web APIs</span></td> <td>中级</td> <td><button>变色</button></td> </tr> </table> <script> const buttons = document.querySelectorAll('table button') for(let i = 0; i < buttons.length; i++) { buttons[i].addEventListener('click', function () { this.parentNode.parentNode.style.color = 'red' }) } </script> </body>
|
结论:parentNode 获取父节点,以相对位置查找节点,实际应用中非常灵活。
兄弟关系
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| <body> <ul> <li>HTML</li> <li>CSS</li> <li>JavaScript 基础</li> <li>Web APIs</li> </ul> <script> const lis = document.querySelectorAll('ul li')
for(let i = 0; i < lis.length; i++) { lis[i].addEventListener('click', function () { console.log(this.previousSibling) console.log(this.nextSibling) }) } </script> </body>
|
结论:
previousSibling 获取前一个节点,以相对位置查找节点,实际应用中非常灵活。
nextSibling 获取后一个节点,以相对位置查找节点,实际应用中非常灵活。
Web APIs - 第5天笔记
目标: 能够利用JS操作浏览器,具备利用本地存储实现学生就业表的能力
js组成
JavaScript的组成
-
ECMAScript:
- 规定了js基础语法核心知识。
- 比如:变量、分支语句、循环语句、对象等等
-
Web APIs :
- DOM 文档对象模型, 定义了一套操作HTML文档的API
- BOM 浏览器对象模型,定义了一套操作浏览器窗口的API

window对象
BOM (Browser Object Model ) 是浏览器对象模型
- window对象是一个全局对象,也可以说是JavaScript中的顶级对象
- 像document、alert()、console.log()这些都是window的属性,基本BOM的属性和方法都是window的
- 所有通过var定义在全局作用域中的变量、函数都会变成window对象的属性和方法
- window对象下的属性和方法调用的时候可以省略window

定时器-延迟函数
JavaScript 内置的一个用来让代码延迟执行的函数,叫 setTimeout
语法:
setTimeout 仅仅只执行一次,所以可以理解为就是把一段代码延迟执行, 平时省略window
间歇函数 setInterval : 每隔一段时间就执行一次, , 平时省略window
清除延时函数:
注意点
- 延时函数需要等待,所以后面的代码先执行
- 返回值是一个正整数,表示定时器的编号
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| <body> <script>
let timerId = setTimeout(function () { console.log('我只执行一次') }, 3000)
console.log(timerId)
clearTimeout(timerId)
</script> </body>
|
location对象
location (地址) 它拆分并保存了 URL 地址的各个组成部分, 它是一个对象
| 属性/方法 |
说明 |
| href |
属性,获取完整的 URL 地址,赋值时用于地址的跳转 |
| search |
属性,获取地址中携带的参数,符号 ?后面部分 |
| hash |
属性,获取地址中的啥希值,符号 # 后面部分 |
| reload() |
方法,用来刷新当前页面,传入参数 true 时表示强制刷新 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| <body> <form> <input type="text" name="search"> <button>搜索</button> </form> <a href="#/music">音乐</a> <a href="#/download">下载</a>
<button class="reload">刷新页面</button> <script> console.log(location.href)
console.log(location.search)
console.log(location.hash)
const btn = document.querySelector('.reload') btn.addEventListener('click', function () { location.reload(true) }) </script> </body>
|
navigator对象
navigator是对象,该对象下记录了浏览器自身的相关信息
常用属性和方法:
1 2 3 4 5 6 7 8 9 10
| (function () { const userAgent = navigator.userAgent const android = userAgent.match(/(Android);?[\s\/]+([\d.]+)?/) const iphone = userAgent.match(/(iPhone\sOS)\s([\d_]+)/) if (android || iphone) { location.href = 'http://m.itcast.cn' }})();
|
histroy对象
history (历史)是对象,主要管理历史记录, 该对象与浏览器地址栏的操作相对应,如前进、后退等
使用场景
history对象一般在实际开发中比较少用,但是会在一些OA 办公系统中见到。

常见方法:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| <body> <button class="back">←后退</button> <button class="forward">前进→</button> <script>
const forward = document.querySelector('.forward') forward.addEventListener('click', function () { history.go(1) }) const back = document.querySelector('.back') back.addEventListener('click', function () { history.go(-1) }) </script> </body>
|
本地存储(今日重点)
本地存储:将数据存储在本地浏览器中
常见的使用场景:
https://todomvc.com/examples/vanilla-es6/ 页面刷新数据不丢失
好处:
1、页面刷新或者关闭不丢失数据,实现数据持久化
2、容量较大,sessionStorage和 localStorage 约 5M 左右
localStorage(重点)
作用: 数据可以长期保留在本地浏览器中,刷新页面和关闭页面,数据也不会丢失
特性:以键值对的形式存储,并且存储的是字符串, 省略了window

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| <!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>本地存储-localstorage</title> </head>
<body> <script> localStorage.setItem('age', 18)
console.log(typeof localStorage.getItem('age'))
localStorage.removeItem('age') </script> </body>
</html>
|
sessionStorage(了解)
特性:
- 用法跟localStorage基本相同
- 区别是:当页面浏览器被关闭时,存储在 sessionStorage 的数据会被清除
存储:sessionStorage.setItem(key,value)
获取:sessionStorage.getItem(key)
删除:sessionStorage.removeItem(key)
localStorage 存储复杂数据类型
问题:本地只能存储字符串,无法存储复杂数据类型.
解决:需要将复杂数据类型转换成 JSON字符串,在存储到本地
语法:JSON.stringify(复杂数据类型)
JSON字符串:
- 首先是1个字符串
- 属性名使用双引号引起来,不能单引号
- 属性值如果是字符串型也必须双引号
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| <body> <script> const goods = { name: '小米', price: 1999 }
localStorage.setItem('goods', JSON.stringify(goods))
</script> </body>
|
问题:因为本地存储里面取出来的是字符串,不是对象,无法直接使用
解决:把取出来的字符串转换为对象
语法:JSON.parse(JSON字符串)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| <body> <script> const goods = { name: '小米', price: 1999 }
localStorage.setItem('goods', JSON.stringify(goods))
console.log(JSON.parse(localStorage.getItem('goods')))
</script> </body>
|
综合案例
数组map 方法
使用场景:
map 可以遍历数组处理数据,并且返回新的数组
语法:
1 2 3 4 5 6 7 8 9 10 11 12
| <body> <script> const arr = ['red', 'blue', 'pink'] const newArr = arr.map(function (ele, index) { return ele + '颜色' }) console.log(newArr) </script> </body>
|
map 也称为映射。映射是个术语,指两个元素的集之间元素相互“对应”的关系。
map重点在于有返回值,forEach没有返回值(undefined)
数组join方法
作用:join() 方法用于把数组中的所有元素转换一个字符串
语法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| <body> <script> const arr = ['red', 'blue', 'pink']
const newArr = arr.map(function (ele, index) { return ele + '颜色' }) console.log(newArr)
console.log(newArr.join()) console.log(newArr.join('')) console.log(newArr.join('|')) </script> </body>
|
Web APIs - 第6天笔记
目标:能够利用正则表达式完成小兔鲜注册页面的表单验证,具备常见的表单验证能力
正则表达式
正则表达式(Regular Expression)是一种字符串匹配的模式(规则)
使用场景:
- 例如验证表单:手机号表单要求用户只能输入11位的数字 (匹配)
- 过滤掉页面内容中的一些敏感词(替换),或从字符串中获取我们想要的特定部分(提取)等

正则基本使用
-
定义规则
-
使用正则
test()方法 用来查看正则表达式与指定的字符串是否匹配
- 如果正则表达式与指定的字符串匹配 ,返回
true,否则false
1 2 3 4 5 6 7 8 9 10 11 12
| <body> <script> const str = 'web前端开发' const reg = /web/
console.log(reg.test(str)) console.log(reg.test('java开发')) </script> </body>
|
元字符
- 普通字符:
- 大多数的字符仅能够描述它们本身,这些字符称作普通字符,例如所有的字母和数字。
- 普通字符只能够匹配字符串中与它们相同的字符。
- 比如,规定用户只能输入英文26个英文字母,普通字符的话 /[abcdefghijklmnopqrstuvwxyz]/
- 元字符(特殊字符)
- 是一些具有特殊含义的字符,可以极大提高了灵活性和强大的匹配功能。
- 比如,规定用户只能输入英文26个英文字母,换成元字符写法: /[a-z]/
边界符
正则表达式中的边界符(位置符)用来提示字符所处的位置,主要有两个字符

如果 ^ 和 $ 在一起,表示必须是精确匹配
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| <body> <script> const reg = /^web/ console.log(reg.test('web前端')) console.log(reg.test('前端web')) console.log(reg.test('前端web学习')) console.log(reg.test('we'))
const reg1 = /web$/ console.log(reg1.test('web前端')) console.log(reg1.test('前端web')) console.log(reg1.test('前端web学习')) console.log(reg1.test('we'))
const reg2 = /^web$/ console.log(reg2.test('web前端')) console.log(reg2.test('前端web')) console.log(reg2.test('前端web学习')) console.log(reg2.test('we')) console.log(reg2.test('web')) console.log(reg2.test('webweb')) </script> </body>
|
量词
量词用来设定某个模式重复次数

注意: 逗号左右两侧千万不要出现空格
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53
| <body> <script> const reg1 = /^w*$/ console.log(reg1.test('')) console.log(reg1.test('w')) console.log(reg1.test('ww')) console.log('-----------------------')
const reg2 = /^w+$/ console.log(reg2.test('')) console.log(reg2.test('w')) console.log(reg2.test('ww')) console.log('-----------------------')
const reg3 = /^w?$/ console.log(reg3.test('')) console.log(reg3.test('w')) console.log(reg3.test('ww')) console.log('-----------------------')
const reg4 = /^w{3}$/ console.log(reg4.test('')) console.log(reg4.test('w')) console.log(reg4.test('ww')) console.log(reg4.test('www')) console.log(reg4.test('wwww')) console.log('-----------------------')
const reg5 = /^w{2,}$/ console.log(reg5.test('')) console.log(reg5.test('w')) console.log(reg5.test('ww')) console.log(reg5.test('www')) console.log('-----------------------')
const reg6 = /^w{2,4}$/ console.log(reg6.test('w')) console.log(reg6.test('ww')) console.log(reg6.test('www')) console.log(reg6.test('wwww')) console.log(reg6.test('wwwww'))
</script>
|
范围
表示字符的范围,定义的规则限定在某个范围,比如只能是英文字母,或者数字等等,用表示范围

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
| <body> <script> const reg1 = /^[abc]$/ console.log(reg1.test('a')) console.log(reg1.test('b')) console.log(reg1.test('c')) console.log(reg1.test('d')) console.log(reg1.test('ab'))
const reg2 = /^[a-z]$/ console.log(reg2.test('a')) console.log(reg2.test('p')) console.log(reg2.test('0')) console.log(reg2.test('A')) const reg3 = /^[a-zA-Z0-9]$/ console.log(reg3.test('B')) console.log(reg3.test('b')) console.log(reg3.test(9)) console.log(reg3.test(','))
const reg4 = /^[a-zA-Z0-9_]{6,16}$/ console.log(reg4.test('abcd1')) console.log(reg4.test('abcd12')) console.log(reg4.test('ABcd12')) console.log(reg4.test('ABcd12_'))
const reg5 = /^[^a-z]$/ console.log(reg5.test('a')) console.log(reg5.test('A')) console.log(reg5.test(8))
</script> </body>
|
字符类
某些常见模式的简写方式,区分字母和数字


替换和修饰符
replace 替换方法,可以完成字符的替换

1 2 3 4 5 6 7 8 9
| <body> <script> const str = '欢迎大家学习前端,相信大家一定能学好前端,都成为前端大神' </script> </body>
|
修饰符约束正则执行的某些细节行为,如是否区分大小写、是否支持多行匹配等
- i 是单词 ignore 的缩写,正则匹配时字母不区分大小写
- g 是单词 global 的缩写,匹配所有满足正则表达式的结果
1 2 3 4 5 6 7 8 9 10 11 12 13
| <body> <script> const str = '欢迎大家学习前端,相信大家一定能学好前端,都成为前端大神'
const strEnd = str.replace(/前端/g, 'web') console.log(strEnd) </script> </body>
|
正则插件

change 事件
给input注册 change 事件,值被修改并且失去焦点后触发
判断是否有类

元素.classList.contains() 看看有没有包含某个类,如果有则返回true,么有则返回false
个人实战文档
本次实战是对自己整个api阶段的总结。
参考效果如下地址:
http://erabbit.itheima.net/#/product/3995139
本次实战主要分为以下几个模块。
顶部导航模块
需求:
- 顶部导航开始不显示
- 等页面滑到主导航栏,这个新顶部导航栏滑动下拉显示,并且改为固定定位
- 等页面滑到上面,新顶部导航栏隐藏
图片切换模块
放大镜效果
业务分析:
①:鼠标经过对应小盒子,左侧中等盒子显示对应中等图片
②: 鼠标经过中盒子,右侧会显示放大镜效果的大盒子
③: 黑色遮罩盒子跟着鼠标来移动
④: 鼠标在中等盒子上移动,大盒子的图片跟着显示对应位置
思路分析:
①:鼠标经过小盒子,左侧中等盒子显示对应中等图片
- 获取对应的元素
- 采取事件委托的形式,监听鼠标经过小盒子里面的图片, 注意此时需要使用
mouseover 事件,因为需要事件冒泡触发small
- 让鼠标经过小图片的爸爸li盒子,添加类,其余的li移除类(注意先移除,后添加)
- 鼠标经过小图片,可以拿到小图片的src, 可以做两件事
- 让中等盒子的图片换成这个 这个小图片的src
- 让大盒子的背景图片,也换成这个小图片的 src (稍后做)
②: 鼠标经过中等盒子,右侧大盒子显示
-
用到鼠标经过和离开,鼠标经过中盒子,大盒子 利用 display 来显示和隐藏
-
鼠标离开不会立马消失,而是有200ms的延时,用户体验更好,所以尽量使用定时器做个延时 setTimeout
-
显示和隐藏也尽量定义一个函数,因为鼠标经过离开中等盒子,会显示隐藏,同时,鼠标经过大盒子,也会显示和隐藏
-
给大盒子里面的背景图片一个默认的第一张图片
③: 黑色遮罩盒子跟着鼠标来移动
-
先做鼠标经过 中等盒子,显示隐藏 黑色遮罩 的盒子
-
让黑色遮罩跟着鼠标来走, 需要用到鼠标移动事件 mousemove
-
让黑色盒子的移动的核心思想:不断把鼠标在中等盒子内的坐标给黑色遮罩层 let top 值,这样遮罩层就可以跟着移动了
1 2 3 4 5 6 7 8
| let mx = 0, my = 0; if (x <= 100) mx = 0 if (x > 100 && x < 300) mx = x - 100 if (x >= 300) mx = 200
if (y <= 100) my = 0 if (y > 100 && y < 300) my = y - 100 if (y >= 300) my = 200
|
- 大盒子图片移动的计算方法:
- 中等盒子是 400px 大盒子 是 800px 的图片
- 中等盒子移动1px, 大盒子就应该移动2px, 只不过是负值
1 2
| large.style.backgroundPositionX = - 2 * mx + 'px' large.style.backgroundPositionY = - 2 * my + 'px'
|
放大镜完整代码:
其他模块
此模块可以根据自己时间添加
点击模块
tab栏切换模块
返回顶部模块
页面滚动底部,可以出现一个侧边栏,点击返回顶部,可以返回顶部