Web API 基本认知
作用和分类
作用: 就是使用 JS 去操作 html 和浏览器。
分类:DOM (文档对象模型)、BOM(浏览器对象模型)。
什么是DOM
DOM(Document Object Model——文档对象模型)是用来呈现以及与任意 HTML 或 XML文档交互的API。
DOM作用:开发网页内容特效和实现用户交互。
DOM树
将 HTML 文档以树状结构直观的表现出来,我们称之为文档树或 DOM 树 描述网页内容关系的名词。
作用:文档树直观的体现了标签与标签之间的关系。
<!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>标题</title>
</head>
<body>
文本
<a href="">链接名</a>
<div id="" class="">文本</div>
</body>
</html>
DOM对象
DOM对象:浏览器根据html标签生成的 JS对象。
所有的标签属性都可以在这个对象上面找到。
修改这个对象的属性会自动映射到标签身上。
DOM的核心思想
把网页内容当做对象来处理
document 对象:是 DOM 里提供的一个对象。
所以它提供的属性和方法都是用来访问和操作网页内容的。
例:document.write()
网页所有内容都在document里面。
获取DOM对象
根据CSS选择器来获取DOM元素 (重点)
选择匹配的第一个元素
语法:
document.querySelector('css选择器')
参数:包含一个或多个有效的CSS选择器 字符串。
返回值:
CSS选择器匹配的第一个元素,一个 HTMLElement对象。
如果没有匹配到,则返回null。
选择匹配的多个元素
语法:
document.querySelectorAll('css选择器')
参数:
包含一个或多个有效的CSS选择器 字符串
返回值:
CSS选择器匹配的NodeList 对象集合
例如:
document.querySelectorAll('ul li')
其他获取DOM元素方法(了解)
//根据id获取一个元素
document.getElementById('nav')
//根据标签获取一类元素 获取页面 所有div
document.getElementsByTagName('div')
//根据 类名获取元素 获取页面 所有类名为w的
document.getElementsByClassName('w')
设置/修改DOM元素内容
document.write() 方法
1.document.write()
只能将文本内容追加到 </body>
前面的位置。
文本中包含的标签会被解析。
//永远都只是追加操作,且只能位置</body>前
document.write(‘Hello World’);
document.write(‘<h3>你好,世界!</h3>’)
对象.innerText 属性
元素innerText 属性
将文本内容添加/更新到任意标签位置。
文本中包含的标签不会被解析。
//innerText 将稳步内容添加/ 更新到任意标签位置
let info = document.getElementById(‘info’)
//intro.innerText = ‘hi,我叫李小毛!’
info.innerText = ‘<h4>hi,我叫李小毛!</h4>’
对象.innerHTML 属性
元素.innerHTML 属性
将文本内容添加/更新到任意标签位置。
文本中包含的标签会被解析。
//2.innerHTML属性
box.innerHHTML = ‘<h3>前端程序员<br>都很帅!</h3>’
案例:随机抽取的名字显示到指定的标签内部
<!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 {
display: inline-block;
width: 150px;
height: 30px;
border: 1px solid rgb(140, 160, 248);
vertical-align: middle;
text-align: center;
line-height: 30px;
/* margin: 300px; */
}
</style>
</head>
<body>
抽中的名字: <div></div>
<script>
// 1. 获取元素
let box = document.querySelector('div')
// 2. 得到随机的名字
// 随机数
function getRandom(min, max) {
return Math.floor(Math.random() * (max - min + 1)) + min
}
// 声明一个数组
let arr = ['李1毛', '李2毛', '李3毛', '李4毛', '李5毛', '李6毛', '李7毛', '李8毛']
// 生成1个随机数 作为数组的索引号
let random = getRandom(0, arr.length - 1)
// console.log(random)
// 3. 写入标签内部
box.innerHTML = arr[random]
// 之后删除这个 人的名字
// arr.splice(从哪里开始删, 删几个)
arr.splice(random, 1)
// console.log(arr)
</script>
</body>
</html>
设置/修改DOM元素属性
设置/修改元素常用属性
还可以通过 JS 设置/修改标签元素属性,比如通过 src更换 图片。
最常见的属性比如: href、title、src 等。
语法:对象.属性=值
//1.获取元素
let pic = document.querySelector(‘img’)
//2.操作元素
pic.src=‘. /images /demo.png’
pic.title= ‘这是一张图片’
案例:页面刷新,图片随机更换。
<!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>
img {
width: 500px;
height: 300px;
}
</style>
</head>
<body>
<img src="./images/1.png" alt="">
<script>
// 1. 获取图片元素
let pic = document.querySelector('img')
// 2. 随机得到图片序号
function getRandom(min, max) {
return Math.floor(Math.random() * (max - min + 1)) + min
}
let num = getRandom(1, 6)
// 3. 完成src 属性赋值
pic.src = `./images/${num}.webp`
</script>
</body>
</html>
设置/修改元素样式属性
1.通过 style 属性操作CSS。
语法:
对象.style.样式属性 = 值
let box = document.querySelector(‘.box’)
//2.修改背景颜色
box.style.background.Color ='blue'
box.style.width ='200px'
box.style.marginTop ='100px'
2.设置/修改元素样式属性
操作类名(className) 操作CSS
如果修改的样式比较多,直接通过style属性修改比较繁琐,我们可以通过借助于css类名的形式。
语法:
//active是一个css类名
元素.className =‘active’
注意:
1.由于class是关键字, 所以使用className去代替。
2.className是使用新值换旧值, 如果需要添加一个类,需要保留之前的类名。
3.通过 classList 操作类控制CSS
为了解决className 容易覆盖以前的类名,我们可以通过classList方式追加和删除类名
语法:
//追加一个类
元素.classList.add (‘类名’)
//删除一个类
元素.classList.remove (‘类名’)
//切换一个类
元素.classList.toggle (‘类名’)
设置/修改 表单元素 属性
表单很多情况,也需要修改属性,比如点击眼睛,可以看到密码,本质是把表单类型转换为文本框。
正常的有属性有取值的 跟其他的标签属性没有任何区别。
获取: DOM对象.属性名
设置: DOM对象.属性名 = 新值
表单.value=‘用户名’
表单.type=‘password’
表单属性中添加就有效果,移除就没有效果,一律使用布尔值表示。
如果为true 代表添加了该属性
如果是false 代表移除了该属性
比如: disabled、checked、selected
定时器-间歇函数
定时器函数介绍
定时器函数可以开启和关闭定时器
案例:倒计时效果
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<textarea name="" id="" cols="30" rows="3">
用户注册协议
欢迎注册成为前端开发网用户!在您注册过程中,您需要完成我们的注册流程并通过点击同意的形式在线签署以下协议,请您务必仔细阅读、充分理解协议中的条款内容后再点击同意(尤其是以粗体或下划线标识的条款,因为这些条款可能会明确您应履行的义务或对您的权利有所限制)。
【请您注意】如果您不同意以下协议全部或任何条款约定,请您停止注册。您停止注册后将仅可以浏览我们的商品信息但无法享受我们的产品或服务。如您按照注册流程提示填写信息,阅读并点击同意上述协议且完成全部注册流程后,即表示您已充分阅读、理解并接受协议的全部内容,并表明您同意我们可以依据协议内容来处理您的个人信息,并同意我们将您的订单信息共享给为完成此订单所必须的第三方合作方(详情查看
</textarea>
<br>
<button class="btn" disabled>我已经阅读用户协议(12)</button>
<script>
// 1. 获取元素 button
let btn = document.querySelector('.btn')
// 2. 计算逻辑
// 2.1 我们需要一个变量 用来计数
let i = 12
// 2.2 开启定时器 间歇函数 timer 定时器的序号id
let timer = setInterval(function () {
i--
btn.innerHTML = `我已经阅读用户协议(${i})`
if (i === 0) {
// 不走了,清除定时器
clearInterval(timer)
// 开启按钮
btn.disabled = false
// 更换文字
btn.innerHTML = '我同意注册了'
}
}, 1000)
</script>
</body>
</html>
定时器函数基本使用
1.开启定时器
setInterval(函数,间隔时间)
作用:每隔一段时间调用这个函数
间隔时间单位:毫秒
function repeat(){
console.log(‘前端程序员,就是帅’)
}
//每隔一秒调用repeat函数
setInterval(repeat,1000)
2.关闭定时器
let 变量名 = setInterval(函数,间隔时间)
clearInterval(变量名)
一般不会刚创建就停止,而是满足一定条件再停止。
事件
事件监听
事件是在编程时系统内发生的动作或者发生的事情。比如用户在网页上单击一个按钮。
事件监听就是让程序检测是否有事件产生,一旦有事件触发,就立即调用一个函数做出响应,也称为 注册事件。
语法:
元素.addEventListener('事件',要执行的函数)
事件监听三要素:
1.事件源: 那个dom元素被事件触发了,要获取dom元素
2.事件: 用什么方式触发,比如鼠标单击 click、鼠标经过 mouseover 等
3.事件调用的函数: 要做什么事
//1.获取元素
let btn = document.querySelector(‘button’)
//1.事件监听(注册事件)
btn.addEventListener(‘click’,function(){
alert(‘被点击了’)
})
案例:淘宝点击关闭二维码
<!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/erweima.png" alt="">
<i class="close_btn">x</i>
</div>
<script>
// 1. 获取元素 事件源 i 关闭的 erweima
let close_btn = document.querySelector('.close_btn')
let erweima = document.querySelector('.erweima')
// 2. 事件监听
close_btn.addEventListener('click', function () {
// erweima 关闭 它是隐藏的
erweima.style.display = 'none'
})
</script>
</body>
</html>
案例:随机点名
需求:点击按钮之后,随机显示一个名字,如果没有显示则禁用按钮
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta 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: 200px;
height: 40px;
border: 1px solid pink;
text-align: center;
line-height: 40px;
}
</style>
</head>
<body>
<div>开始抽奖吧</div>
<button>点击点名</button>
<script>
// 1. 获取元素 div 和 button
let box = document.querySelector('div')
let btn = document.querySelector('button')
// 2. 随机函数
function getRandom(min, max) {
return Math.floor(Math.random() * (max - min + 1)) + min
}
// 声明一个数组
let arr = ['李小毛', '李中毛', '李大毛']
// 3. 事件监听
btn.addEventListener('click', function () {
// 随机的数字
let random = getRandom(0, arr.length - 1)
// console.log(arr[random])
box.innerHTML = arr[random]
// 删除数组里面的元素 splice(从哪里删, 删几个)
arr.splice(random, 1)
// 如果数组没有了 长度为0,就要禁用按钮
if (arr.length === 0) {
// console.log('最后一个了')
btn.disabled = true
btn.innerHTML = '已经点完'
}
})
</script>
</body>
</html>
拓展阅读 事件监听版本
DOM L0
事件源.on事件 = function() { }
DOM L2
事件源.addEventListener(事件, 事件处理函数)
发展史:
DOM L0 :是 DOM 的发展的第一个版本;
L:level
DOM L1:DOM级别1 于1998年10月1日成为W3C推荐标准。
DOM L2:使用addEventListener注册事件。
DOM L3:DOM3级事件模块在DOM2级事件的基础上重新定义了这些事件,也添加了一些新事件类型。
事件类型
鼠标事件:
click 鼠标点击
mouseenter 鼠标经过
mouseleave 鼠标离开
焦点事件:
focus 获得焦点
blur 失去焦点
键盘事件:
Keydown 键盘按下触发
Keyup 键盘抬起触发
文本事件:
input 用户输入事件
案例:前端开发网搜索框案例
需求:当表单得到焦点,显示下拉菜单,失去焦点隐藏下来菜单
案例分析:
1.开始下拉菜单要进行隐藏。
2.表单获得焦点 focus,则显示下拉菜单,并且文本框变色(添加类)。
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>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
ul {
list-style: none;
}
.mi {
position: relative;
width: 223px;
margin: 100px auto;
}
.mi input {
width: 223px;
height: 48px;
padding: 0 10px;
font-size: 14px;
line-height: 48px;
border: 1px solid #e0e0e0;
outline: none;
transition: all .3s;
}
.mi .search {
border: 1px solid #6595f0;
}
.result-list {
display: none;
position: absolute;
left: 0;
top: 48px;
width: 223px;
border: 1px solid #6595f0;
border-top: 0;
background: #fff;
}
.result-list a {
display: block;
padding: 6px 15px;
font-size: 12px;
color: #424242;
text-decoration: none;
}
.result-list a:hover {
background-color: #eee;
}
</style>
</head>
<body>
<div class="mi">
<input type="search" placeholder="前端开发教程">
<ul class="result-list">
<li><a href="#">全部教程</a></li>
<li><a href="#">html教程</a></li>
<li><a href="#">css教程</a></li>
<li><a href="#">javascript教程</a></li>
<li><a href="#">webApi教程</a></li>
<li><a href="#">jquery教程</a></li>
<li><a href="#">vue教程</a></li>
</ul>
</div>
<script>
// 1. 获取元素 input
let search = document.querySelector('input')
let list = document.querySelector('.result-list')
// 2. 事件监听 获得光标事件 focus
search.addEventListener('focus', function () {
// 显示下拉菜单
list.style.display = 'block'
// 文本框变色
this.classList.add('search')
})
// 3. 事件监听 失去光标事件 blur
search.addEventListener('blur', function () {
// 隐藏下拉菜单
list.style.display = 'none'
// 文本框去色
this.classList.remove('search')
})
</script>
</body>
</html>
高阶函数
高阶函数可以被简单理解为函数的高级应用,JavaScript 中函数可以被当成【值】来对待,基于这个特性实现函数的高级应用。
【值】就是 JavaScript 中的数据,如数值、字符串、布尔、对象等。
函数表达式
函数表达式和普通函数并无本质上的区别:
//函数表达式与普通函数本质上是一样的
let counter = function(x,y){
return x+y
}
//调用函数
let result = counter (5,10)
console.log(result)
普通函数的声明与调用无顺序限制,推荐做法先声明再调用。
函数表达式必须要先声明再调用。
回调函数
如果将函数 A 做为参数传递给函数 B 时,我们称函数 A 为回调函数
简单理解: 当一个函数当做参数来传递给另外一个函数的时候,这个函数就是回调函数
常见的使用场景:
function fn(){
console.log(‘我是回调函数’)
}
//fn传递给了setInterval,fn就是回调函数
setInterval(fn,1000)
box.addEvemtListener(‘click’,function(){
console.log(‘我也是回调函数’)
}
环境对象
环境对象指的是函数内部特殊的变量 this ,它代表着当前函数运行时所处的环境。
作用:弄清楚this的指向,可以让我们代码更简洁。
函数的调用方式不同,this 指代的对象也不同。
【谁调用, this 就是谁】 是判断 this 指向的粗略规则。
直接调用函数,其实相当于是 window.函数,所以 this 指代 window。
<!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>this</title>
</head>
<body>
<button>点击</button>
<script>
// 环境对象 this 他就是个对象
function fn() {
console.log(this)
}
// fn()
window.fn()
let btn = document.querySelector('button')
btn.addEventListener('click', function () {
console.log(typeof this)
// 因为btn 调用了这个函数,所以 this 指向btn
})
</script>
</body>
</html>
编程思想
排他思想
当前元素为A状态,其他元素为B状态。
使用:
- 干掉所有人
使用for循环。 - 复活自己
通过this或者下标找到自己或者对应的元素。
<!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>排他思想</title>
<style>
.black {
background: black;
color: #fff;
}
</style>
</head>
<body>
<button>one</button><button>two</button><button>three</button>
<script>
let btns = document.querySelectorAll('button')
for (let i = 0; i < btns.length; i++) {
btns[i].addEventListener('click', function () {
// this.classList.add('pink')
// 干掉所有人
for (let j = 0; j < btns.length; j++) {
btns[j].classList.remove('black')
}
// 复活我自己
this.classList.add('black')
})
}
</script>
</body>
</html>
节点操作
DOM节点:DOM树里每一个内容都称之为节点。
节点类型
1.元素节点
所有的标签 比如 body、 div
html 是根节点
2.属性节点
所有的属性 比如 href
3.文本节点
所有的文本
节点关系
1.父节点
2.子节点
3.兄弟节点
1.父节点查找:
parentNode 属性
返回最近一级的父节点 找不到返回为null
子元素.parentNode
2.子节点查找:
childNodes
获得所有子节点、包括文本节点(空格、换行)、注释节点等
children (重点)
仅获得所有元素节点
返回的还是一个伪数组
父元素.children
3.兄弟关系查找:
1.下一个兄弟节点
nextElementSibling 属性
2.上一个兄弟节点
previousElementSibling 属性
增加节点
1.创建节点
即创造出一个新的网页元素,再添加到网页内,一般先创建节点,然后插入节点。
创建元素节点方法:
//创造一个新的元素节点
document.createElement(‘标签名’)
2.追加节点
要想在界面看到,还得插入到某个父元素中。
插入到父元素的最后一个子元素:
//插入到这个父元素的最后
父元素.appendChild(要插入的元素)
插入到父元素中某个子元素的前面
//插入到某个子元素的前面
父元素.insertBefore(要插入的元素,在哪个元素前面)
3.增加节点
克隆节点
//克隆一个已有的元素节点
元素.cloneNode(布尔值)
cloneNode会克隆出一个跟原标签一样的元素,括号内传入布尔值。
若为true,则代表克隆时会包含后代节点一起克隆
若为false,则代表克隆时不包含后代节点
默认为false
删除节点
在 JavaScript 原生DOM操作中,要删除元素必须通过父元素删除。
语法:
父元素.removeChild(要删除的元素)
注: 如不存在父子关系则删除不成功
删除节点和隐藏节点(display:none)
有区别的: 隐藏节点还是存在的,但是删除,则从html中删除节点。
时间对象
实例化
在代码中发现了 new 关键字时,一般将这个操作称为实例化。
创建一个时间对象并获取时间。
获得当前时间
let date = new Date()
获得指定时间
let date = new Date(‘2022-10-02’)
时间对象方法
因为时间对象返回的数据我们不能直接使用,所以需要转换为实际开发中常用的格式
方法 | 作用 | 说明 |
---|---|---|
getFullYear() | 获得年份 | 获取四位年份 |
getMonth() | 获得月份 | 取值为 0 ~ 11 |
getDate() | 获取月份中的每一天 | 不同月份取值也不相同 |
getDay() | 获取星期 | 取值为 0 ~ 6 |
getHours() | 获取小时 | 取值为 0 ~ 23 |
getMinutes() | 获取分钟 | 取值为 0 ~ 59 |
getSeconds() | 获取秒 | 取值为 0 ~ 59 |
时间戳
时间戳是指1970年01月01日00时00分00秒起至现在的毫秒数,它是一种特殊的计量时间的方式。
三种方式获取时间戳
1.使用 getTime() 方法
//1.实例化
let date = new Date()
//1.获取时间戳
console.log(date.getTime())
2.简写 +new Date()
console.log(+new Date())
3.使用 Date().now()
console.log(Date.now())
案例:下课倒计时
<!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>下课倒计时</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">今天是2022年5月7日</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">
现在是21:20:00
</p>
</div>
<script>
let hour = document.querySelector('#hour')
let minutes = document.querySelector('#minutes')
let scond = document.querySelector('#scond')
time()
setInterval(time, 1000)
function time() {
// 1. 得到现在的时间戳
let now = +new Date()
// 2. 得到指定时间的时间戳
let last = +new Date('2022-5-7 22:30:00')
// 3. (计算剩余的毫秒数) / 1000 === 剩余的秒数
let count = (last - now) / 1000
// console.log(count)
// 4. 转换为时分秒
// h = parseInt(总秒数 / 60 / 60 % 24) // 计算小时
let h = parseInt(count / 60 / 60 % 24)
h = h < 10 ? '0' + h : h
// m = parseInt(总秒数 / 60 % 60); // 计算分数
let m = parseInt(count / 60 % 60)
m = m < 10 ? '0' + m : m
// s = parseInt(总秒数 % 60); // 计算当前秒数
let s = parseInt(count % 60);
s = s < 10 ? '0' + s : s
// console.log(h, m, s)
hour.innerHTML = h
minutes.innerHTML = m
scond.innerHTML = s
}
</script>
</body>
</html>
重绘和回流
浏览器是如何进行界面渲染的
1.解析(Parser)HTML,生成DOM树(DOM Tree)。
2.同时解析(Parser) CSS,生成样式规则 (Style Rules)。
3.根据DOM树和样式规则,生成渲染树(Render Tree)。
4.进行布局 Layout(回流/重排):根据生成的渲染树,得到节点的几何信息(位置,大小)。
5.进行绘制 Painting(重绘): 根据计算和获取的信息进行整个页面的绘制。
6.Display: 展示在页面上。
重绘和回流(重排)
1.回流(重排)
当 Render Tree 中部分或者全部元素的尺寸、结构、布局等发生改变时,浏览器就会重新渲染部分或全部文档的过程称为 回流。
2.重绘
由于节点(元素)的样式的改变并不影响它在文档流中的位置和文档布局时(比如:color,background-color、outline等), 称为重绘。
备注:重绘不一定引起回流,而回流一定会引起重绘。
会导致回流(重排)的操作:
页面的首次刷新
浏览器的窗口大小发生改变
元素的大小或位置发生改变
改变字体的大小
内容的变化(如:input框的输入,图片的大小)
激活css伪类 (如::hover) 脚本操作DOM(添加或者删除可见的DOM元素)
简单理解影响到布局了,就会有回流。
事件对象
获取事件对象
事件对象也是个对象,这个对象里有事件触发时的相关信息。
例如:鼠标点击事件中,事件对象就存了鼠标点在哪个位置等信息。
如何获取事件对象?
在事件绑定的回调函数的第一个参数就是事件对象。
一般命名为event、ev、e
元素.addEventListener(‘click’,function(e)){
}
//e为事件对象
事件对象常用属性
部分常用属性
type:获取当前的事件类型。
clientX/clientY:获取光标相对于浏览器可见窗口左上角的位置。
offsetX/offsetY:获取光标相对于当前DOM元素左上角的位置。
key:用户按下的键盘键的值,现在不提倡使用keyCode。
事件流
事件流与两个阶段说明
事件流指的是事件完整执行过程中的流动路径。
说明:假设页面里有个div,当触发事件时,会经历两个阶段,分别是捕获阶段、冒泡阶段。
简单来说:捕获阶段是 从父到子 冒泡阶段是从子到父。
事件捕获和事件冒泡
事件冒泡:当一个元素的事件被触发时,同样的事件将会在该元素的所有祖先元素中依次被触发。这一过程被称为事件冒泡。
简单理解:当一个元素触发事件后,会依次向上调用所有父级元素的同名事件。
事件冒泡是默认存在的。
事件捕获:从DOM的根元素开始去执行对应的事件 (从外到里)。
事件捕获需要写对应代码才能看到效果。
代码:
DOM.addEventListener(事件类型,事件处理函数,是否使用捕获机制)
说明:
addEventListener第三个参数传入true代表是捕获阶段触发(很少使用)。
若传入false代表冒泡阶段触发,默认就是false。
若是用 L0 事件监听,则只有冒泡阶段,没有捕获。
阻止事件流动
因为默认就有冒泡模式的存在,所以容易导致事件影响到父级元素。
若想把事件就限制在当前元素内,就需要阻止事件流动。
阻止事件流动需要拿到事件对象。
语法:
事件对象.stopPropagetion()
此方法可以阻断事件流动传播,不光在冒泡阶段有效,捕获阶段也有效。
鼠标经过事件:
mouseover 和 mouseout 会有冒泡效果
mouseenter 和 mouseleave 没有冒泡效果(推荐)
阻止默认行为,比如链接点击不跳转,表单域的不提交。
语法:
e.preventDefault()
两种注册事件的区别:
传统on注册(L0)
同一个对象,后面注册的事件会覆盖前面注册(同一个事件)。
直接使用null覆盖偶就可以实现事件的解绑。
都是冒泡阶段执行的。
事件监听注册(L2)
语法: addEventListener(事件类型, 事件处理函数, 是否使用捕获)。
后面注册的事件不会覆盖前面注册的事件(同一个事件)。
可以通过第三个参数去确定是在冒泡或者捕获阶段执行。
必须使用removeEventListener(事件类型, 事件处理函数, 获取捕获或者冒泡阶段)。
匿名函数无法被解绑。
事件委托
事件委托是利用事件流的特征解决一些开发需求的知识技巧。
总结:
优点:给父级元素加事件(可以提高性能)。
原理:事件委托其实是利用事件冒泡的特点, 给父元素添加事件,子元素可以触发。
实现:事件对象.target 可以获得真正触发事件的元素。
滚动事件和加载事件
滚动事件
滚动事件:当页面进行滚动时触发的事件。
事件名:scroll
监听整个页面滚动:
//页面滚动事件
window.addEventListener(‘scroll’,function()){
//执行的操作
}
给 window 或 document 添加 scroll 事件。
监听某个元素的内部滚动直接给某个元素加即可。
加载事件
加载外部资源(如图片、外联CSS和JavaScript等)加载完毕时触发的事件。
事件名:load
监听页面所有资源加载完毕:
给 window 添加 load 事件
//页面加载事件
window.addEventListener(‘load’,function(){
//执行的操作
})
注意:不光可以监听整个页面资源加载完毕,也可以针对某个资源绑定load事件。
当初始的 HTML 文档被完全加载和解析完成之后,DOMContentLoaded 事件被触发,而无需等待样式表、图像等完全加载。
事件名:DOMContentLoaded
监听页面DOM加载完毕:
给 document 添加 DOMContentLoaded 事件。
document.addEventListener(‘DOMContentLoaded’,function(){
//执行的操作
})
元素大小和位置
scroll
获取宽高:
获取元素的内容总宽高(不包含滚动条)返回值不带单位。
scrollWidth和scrollHeight
获取位置:
获取元素内容往左、往上滚出去看不到的距离。
scrollLeft和scrollTop
这两个属性是可以修改的。
div.addEventListener(‘scroll’,function(){
console.log(this.scrollTop)
})
开发中,我们经常检测页面滚动的距离,比如页面滚动100像素,就可以显示一个元素,或者固定一个元素。
//页面滚动事件
window.addEventListener(‘scroll’,function(){
//document.documentElement.scrollTop 获得当前页面被卷去的头部
let num = document.documentElement.scrollTop
console.log(num)
})
注意:document.documentElement HTML 文档返回对象为HTML元素。
offset
获取宽高:
获取元素的自身宽高、包含元素自身设置的宽高、padding、border
offsetWidth和offsetHeight
获取位置:
获取元素距离自己定位父级元素的左、上距离
offsetLeft和offsetTop 注意是只读属性
client
获取宽高:
获取元素的可见部分宽高(不包含边框,滚动条等)
clientWidth和clientHeight
获取位置:
获取左边框和上边框宽度
clientLeft和clientTop 注意是只读属性
会在窗口尺寸改变的时候触发事件:resize
window.addEventListener(‘resize’,function(){
//执行的代码
})
检测屏幕宽度:
window.addEventListener(‘resize’,function(){
let w = document.documentElement.clientWidth
console.log(w)
})
Window对象
BOM(浏览器对象模型)
BOM(Browser Object Model ) 是浏览器对象模型。
window 是浏览器内置中的全局对象,我们所学习的所有 Web APIs 的知识内容都是基于 window 对象实现的。
window 对象下包含了 navigator、location、document、history、screen 5个属性,即所谓的 BOM (浏览器对象模型) 。
document 是实现 DOM 的基础,它其实是依附于 window 的属性。
注意:依附于 window 对象的所有属性和方法,使用时可以省略 window 。
定时器-延时函数
JavaScript 内置的一个用来让代码延迟执行的函数,叫 setTimeout
语法:
setTimeout(回调函数,等待的毫秒数)
setTimeout 仅仅只执行一次,所以可以理解为就是把一段代码延迟执行, 平时省略window 。
清除延时函数:
let timer = setTimeout (回调函数,等待的毫秒数)
clearTimeout(timer)
结合递归函数可以使用 setTimeout 实现 setInterval 一样的功能。
<div class="clock"> </div>
<script>
let clock = document.querySelector('.clock')
function myInterval( ) (
let d = new Date();
clock.innerText = d.toLocaleString();
//延时任务,自调用
setTimeout(myInterval,1000);
}
//启动定时任务
myInterval();
</script>
两种定时器对比:
setInterval 的特征是重复执行,首次执行会延时。
setTimeout 的特征是延时执行,只执行 1 次。
setTimeout 结合递归函数,能模拟。
setInterval 重复执行。
clearTimeout 清除由 setTimeout 创建的定时任务。
console.log(1111)
setTimeout(function (){
console.log(2222)
},1000)
console.log(3333)
//问输出的结果是什么?
console.log(1111)
setTimeout(function (){
console.log(2222)
},0)
console.log(3333)
//问输出的结果是什么?
//输出的结果都是:
//1111
//3333
//2222
JS执行机制
JS 是单线程
JavaScript 语言的一大特点就是单线程,也就是说,同一个时间只能做一件事。这是因为 Javascript 这门脚本语言诞生的使命所致——JavaScript 是为处理页面中用户的交互,以及操作 DOM 而诞生的。比如我们对某个 DOM 元素进行添加和删除操作,不能同时进行。 应该先进行添加,之后再删除。
单线程就意味着,所有任务需要排队,前一个任务结束,才会执行后一个任务。这样所导致的问
题是: 如果 JS 执行的时间过长,这样就会造成页面的渲染不连贯,导致页面渲染加载阻塞的感觉。
同步和异步
为了解决这个问题,利用多核 CPU 的计算能力,HTML5 提出 Web Worker 标准,允许
JavaScript 脚本创建多个线程。于是,JS 中出现了同步和异步。
同步
前一个任务结束后再执行后一个任务,程序的执行顺序与任务的排列顺序是一致的、同步的。比如做饭的同步。
做法:我们要烧水煮饭,等水开了(15分钟之后),再去切菜,炒菜。
异步
你在做一件事情时,因为这件事情会花费很长时间,在做这件事的同时,你还可以去处理其他事
情。比如做饭的异步做法,我们在烧水的同时,利用这15分钟,去切菜,炒菜。
同步和异步本质区别: 这条流水线上各个流程的执行顺序不同。
同步任务
同步任务都在主线程上执行,形成一个执行栈。
异步任务
JS 的异步是通过回调函数实现的。
一般而言,异步任务有以下三种类型:
1.普通事件,如 click、resize 等。
2.资源加载,如 load、error 等。
3.定时器,包括 setInterval、setTimeout等。
异步任务相关添加到任务队列中(任务队列也称为消息队列)。
JS 执行机制
1.先执行执行栈中的同步任务。
2.异步任务放入任务队列中。
3.一旦执行栈中的所有同步任务执行完毕,系统就会按次序读取任务队列中的异步任务,于是被读取的异步任务。
结束等待状态,进入执行栈,开始执行。
由于主线程不断的重复获得任务、执行任务、再获取任务、再执行,所以这种机制被称为事件循环( event loop)。
location对象
location 的数据类型是对象,它拆分并保存了 URL 地址的各个组成部分。
常用属性和方法:
href 属性获取完整的 URL 地址,对其赋值时用于地址的跳转。
//可以得到当前文件URL地址
console.log(location.href)
//可以通过js方式跳转到目标地址
location.href = 'http://www.qdkf.wang'
search 属性获取地址中携带的参数,符号 ?后面部分。
console.log(location.search)
hash 属性获取地址中的啥希值,符号 # 后面部分。
console.log(location.hash)
后期vue路由的铺垫,经常用于不刷新页面,显示不同页面,比如 网易云音乐
reload 方法用来刷新当前页面,传入参数 true 时表示强制刷新。
<button>点击刷新 </button>
<script>
let btn= doccument.querySelector('button')
btn.addEventListener('click',function(){
location.reload(true)
//强制刷新 类似ctrl+f5
})
</script>
navigator对象
navigator的数据类型是对象,该对象下记录了浏览器自身的相关信息
常用属性和方法:
通过 userAgent 检测浏览器的版本及平台:
// 检测 userAgent(浏览器信息)
!(function () {
const userAgent = navigator.userAgent
// 验证是否为Android或iPhone
const android = userAgent.match(/(Android);?[\s\/]+([\d.]+)?/)
const iphone = userAgent.match(/(iPhone\sOS)\s([\d_]+)/)
// 如果是Android或iPhone,则跳转至移动站点
if (android || iphone) {
location.href = 'http://qdkf.wang'
}
})()
histroy对象
history 的数据类型是对象,该对象与浏览器地址栏的操作相对应,如前进、后退、历史记录等。
常用属性和方法:
history对象方法 | 作用 |
---|---|
back() | 可以后退功能 |
forward() | 前进功能 |
go(参数) | 前进后退功能,参数如果是1,前进一个页面,如果是-1,则后退一个页面 |
history 对象一般在实际开发中比较少用,但是会在一些 OA 办公系统中见到。
swiper 插件
插件: 就是别人写好的一些代码,我们只需要复制对应的代码,就可以直接实现对应的效果
学习插件的基本过程:
熟悉官网,了解这个插件可以完成什么需求 https://www.swiper.com.cn/
看在线演示,找到符合自己需求的demo https://www.swiper.com.cn/demo/index.html
查看基本使用流程 https://www.swiper.com.cn/usage/index.html
查看APi文档,去配置自己的插件 https://www.swiper.com.cn/api/index.html
注意: 多个swiper同时使用的时候, 类名需要注意区分。
本地存储
本地存储特性
随着互联网的快速发展,基于网页的应用越来越普遍,同时也变的越来越复杂,为了满足各种各样的需求,会经常性在本地存储大量的数据,HTML5规范提出了相关解决方案。
1.数据存储在用户浏览器中。
2.设置、读取方便、甚至页面刷新不丢失数据。
3.容量较大,sessionStorage和localStorage约 5M 左右。
localStorage
1.生命周期永久生效,除非手动删除 否则关闭页面也会存在。
2.可以多窗口(页面)共享(同一浏览器可以共享)。
3.以键值对的形式存储使用。
存储数据:
localStorage.setItem(key, value)
获取数据:
localStorage.getItem(key)
删除数据:
localStorage.removeItem(key)
存储复杂数据类型存储
本地只能存储字符串,无法存储复杂数据类型.需要将复杂数据类型转换成JSON字符串,在存储到本地。
JSON.stringify(复杂数据类型)
将复杂数据转换成JSON字符串 存储 本地存储中
JSON.parse(JSON字符串)
将JSON字符串转换成对象 取出 时候使用
sessionStorage(了解)
1.生命周期为关闭浏览器窗口。
2.在同一个窗口(页面)下数据可以共享。
3.以键值对的形式存储使用。
4.用法跟localStorage 基本相同。
正则表达式
介绍
正则表达式(Regular Expression)是用于匹配字符串中字符组合的模式。在 JavaScript中,正则表达式也是对象。
通常用来查找、替换那些符合正则表达式的文本,许多语言都支持正则表达式。
正则表达式在 JavaScript中的使用场景:
例如验证表单:用户名表单只能输入英文字母、数字或者下划线, 昵称输入框中可以输入中文(匹配)。
比如用户名: /^[a-z0-9_-]{3,18}$/
过滤掉页面内容中的一些敏感词(替换),或从字符串中获取我们想要的特定部分(提取)等 。
语法
正则同样道理,我们分为两步:
1.定义规则
2.查找
比如:查找下面文本中是否包含字符串 '前端'
let str = ‘前端开发网,前端学习,大前端’
JavaScript 中定义正则表达式的语法有两种,我们先学习其中比较简单的方法:
1.定义正则表达式语法:
let 变量名=/表达式/
其中 / / 是正则表达式字面量。
比如:
let reg = /前端/
2.判断是否有符合规则的字符串:
test() 方法 用来查看正则表达式与指定的字符串是否匹配。
语法:
regObj.test(被检测的字符串)
比如:
let str = ‘前端开发网,前端学习,大前端’
let reg = /前端/
let re = reg.test(str)
console.log(re)//true
如果正则表达式与指定的字符串匹配 ,返回true,否则false 。
3.检索(查找)符合规则的字符串:
exec() 方法 在一个指定字符串中执行一个搜索匹配。
语法:
regObj.exec(被检测字符串)
let str = ‘前端开发网,前端学习,大前端’
let reg = /前端/
let re = reg.exec(str)
console.log(re)//返回的是个数组
如果匹配成功,exec() 方法返回一个数组,否则返回null
元字符
普通字符:
大多数的字符仅能够描述它们本身,这些字符称作普通字符,例如所有的字母和数字。
也就是说普通字符只能够匹配字符串中与它们相同的字符。
元字符(特殊字符)是一些具有特殊含义的字符,可以极大提高了灵活性和强大的匹配功能。
比如,规定用户只能输入英文26个英文字母,普通字符的话 abcdefghijklm…..
但是换成元字符写法: [a-z]
参考文档:
MDN:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Guide/Regular_Expressions
正则测试工具: http://tool.oschina.net/regex
为了方便记忆和学习,我们对众多的元字符进行了分类:
1.边界符(表示位置,开头和结尾,必须用什么开头,用什么结尾)
2.量词 (表示重复次数)
3.字符类 (比如 \d 表示 0~9)
1.边界符
正则表达式中的边界符(位置符)用来提示字符所处的位置,主要有两个字符
边界符 | 说明 |
---|---|
^ | 表示匹配行首的文本(以谁开始) |
$ | 表示匹配行尾的文本(以谁结束) |
如果 ^ 和 $ 在一起,表示必须是精确匹配。
案例:
console.log(/哈/.test('哈哈'))
console.log(/哈/.test('一起哈'))
// ^ 开头 $结尾
console.log(/^哈/.test('一起哈')) // false
console.log(/^哈/.test('大家一起哈哈大笑')) // false
console.log(/^哈$/.test('一起哈哈大笑')) // false
console.log(/^哈$/.test('哈哈哈哈哈哈')) // false
console.log(/^哈$/.test('哈')) // true 精确匹配
2.量词
量词用来 设定某个模式出现的次数。
量词 | 说明 |
---|---|
* | 重复0次,或者更多次 |
+ | 重复1次或更多次 |
? | 重复0次或更1次 |
{n} | 重复n次 |
{n,} | 重复n次或更多次 |
{n,m} | 重复n到m次 |
注意: 逗号左右两侧千万不要出现空格。
案例:
console.log(/a/.test('a')) //true
// // * 量词 n >= 0
console.log(/a*/.test(''))//true
console.log(/a*/.test('a'))//true
console.log(/a*/.test('aa'))//true
console.log(/a*/.test('aaaaaaaa'))//true
console.log(/a*/.test('b'))//true
// // + 量词 n >= 1
console.log(/a+/.test(''))//false
console.log(/a+/.test('a'))//true
console.log(/a+/.test('aa'))//true
console.log(/a+/.test('aaaaaaaa'))//true
console.log(/a+/.test('b'))//false
// ? 出现 0 || 1 true
console.log(/^a?$/.test(''))//true
console.log(/^a?$/.test('a'))//true
console.log(/^a?$/.test('aa'))//false
// {n} 只能出现 n次 符号之间不要加空格
console.log(/^a{3}$/.test('aa'))//false
console.log(/^a{3}$/.test('aaa'))//true
console.log(/^a{3}$/.test('aaaa'))//false
// {n,} >= n
console.log(/^a{3,}$/.test('aa'))//false
console.log(/^a{3,}$/.test('aaa'))//true
console.log(/^a{3,}$/.test('aaaa'))//true
// {n,m} >= n <= m
console.log(/^a{3,6}$/.test('aa'))//false
console.log(/^a{3,6}$/.test('aaa'))//true
console.log(/^a{3,6}$/.test('aaaa'))//true
console.log(/^a{3,6}$/.test('aaaaa'))//true
console.log(/^a{3,6}$/.test('aaaaaaaa'))//false
3.字符类:
(1.1) [ ] 匹配字符集合
后面的字符串只要包含 abc 中任意一个字符,都返回 true 。
//只要中括号里面的任意字符出现都返回为true
console.log(/[abc]/.test('and')) //true
console.log(/[abc]/.test('body')) //true
console.log(/[abc]/.test('cmd')) //true
console.log(/[abc]/.test('diy')) //true
(1.2) [ ] 里面加上 - 连字符
使用连字符 - 表示一个范围
console.log(/^[a-z]$/.test('c')) //true
比如:
[a-z] 表示 a 到 z 26个英文字母都可以
[a-zA-Z] 表示大小写都可以
[0-9] 表示 0~9 的数字都可以
(1.3) [ ] 里面加上 ^ 取反符号
比如:
[^a-z] 匹配除了小写字母以外的字符
注意要写到中括号里面
(2). 匹配除换行符之外的任何单个字符
(3) 预定义:指的是某些常见模式的简写方式。
预定类 | 说明 |
---|---|
\d | 匹配0-9之间的任一数字,相当于 [0-9 ][ ] |
\D | 匹配所有0-9以外的字符,相当于[^0-9] |
\w | 匹配任意的字母、数字和下划线,相当于 [A-Za-z0-9] |
\W | 除所有字母、数字和下划线以外的字符,相当于[^A-Za-z0-9] |
\s | 匹配空格(包括换行符、制表符、空格符等),相当于 [\t\r\n\v\f] |
\S | 匹配非空格的字符,相当于 [^\t\r\n\v\f] |
日期格式: ^\d{4}-\d{1,2}-\d{1,2}
修饰符
修饰符约束正则执行的某些细节行为,如是否区分大小写、是否支持多行匹配等。
语法:
/表达式/修饰符
i 是单词 ignore 的缩写,正则匹配时字母不区分大小写。
g 是单词 global 的缩写,匹配所有满足正则表达式的结果。
console.log(/a/i.test('a')) //true
console.log(/a/i.test('a')) //true
替换 replace 替换 语法:
字符串.replace(/正则表达式/,'替换的文本')