Web APIs
Web API 基本认知
作用和分类
- 作用:就是使用JS去操作html和浏览器
- 分类:DOM(文档对象模型)、BOM(浏览器对象模型)
DOM (文档对象模型)
DOM (Document Object Model——文档对象模型)是用来呈现以及与任意HTML或XML文档交互的API
白话文:DOM是浏览器提供的一套专门用来操作网页内容的功能
DOM树
DOM树是什么
- 将HTML文档以树状结构直观的表现出来,我们称之为文档树或DOM树
- 描述网页内容关系的名词
- 作用:文档树直观的体现了标签与标签之间的关系
DOM对象
DOM对象:浏览器根据html标签生成的JS对象
- 所有的标签属性都可以在这个对象上面找到
- 修改这个对象的属性会自动映射到标签身上
DOM的核心思想
- 把网页内容当做对象来处理
document对象
- 是DOM里提供的一个对象
- 所以它提供的属性和方法都是用来访问和操作网页内容的
- 例: document.write()
- 网页所有内容都在document里面
获取DOM对象
根据css选择器来获取DOM元素(重点)
选择匹配的第一个元素
语法:
document.querySelector('css选择器')
参数:
包含一个或多个有效的css选择器 字符串
返回值:
css选择器匹配的第一个元素一个HTMLElement对象。
如果没有匹配到,则返回null。
选择匹配的多个元素
语法
document.querySelector('css选择器')
参数:
包含一个或多个有效的css选择器 字符串
返回值:
css选择器匹配的NodeList对象集合
document.querySelectorAll('ul li')
querySelector()方法能直接操作修改
querySelectorAll()方法不可以直接操作修改,只能通过遍历的方式一次给里面的元素做修改
document.querySelectorAll('css选择器')
得到的是一个伪数组:
- 有长度有索引号的数组
- 但是没有pop() push()等数组方法
- 想要得到里面的每一个对象,则需要遍历( for)的方式获得。
注意:
- 哪怕只有一个元素,通过querySelectAll()获取过来的也是一个伪数组,里面只有一个元素而已
其他获取DOM元素方法
// 根据id获取一个元素
document.getElementById('nav')
// 根据标签获取一个元素 获取页面 所有div
document.getElementsByTagName('div')
// 根据类获取一个元素 获取页面 所有类为w的元素
document.getElementsByClassName('w')
设置/修改DOM元素内容
-
document.write()
-
只能将文本内容追加到前面的位置
-
document.write('<h3> 你好,世界! </h3>')
-
文本中包含的标签会被解析
-
-
元素.innerText属性
- 将文本内容添加/更新到任意标签位置文本中
- 包含的标签不会被解析
-
元素.innerHTML属性
- 将文本内容推荐/更新到任意标签位置
- 文本中包含的标签会被解析
// innerHTML 属性
box.innerHTML = '<h3>前端程序员<br>的头发都很多</h3>'
三者区别
- document.write()方法只能追加到body中
- 元素.innerText属性只识别内容,不能解析标签
- 元素.innerHTML属性―能够解析标签
- 如果还在纠结到底用谁,你可以选择innerHTML
案例 随机抽取的名字显示到指定的标签内部
需求:将名字放入span盒子内部
分析:
- 获取span元素
- 得到随机的名字
- 通过innerText或者innerHTML将名字写入元素内部
<!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 pink;
vertical-align: middle;
line-height: 30px;
}
</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 = ['小米','小吗','小是','小的','小发',
'小人','小他','小哦','小明']
// 生成一个随机数 作为数组的索引号
let random = getRandom(0,arr.length - 1)
// document.write(arr[random])
//3. 写入标签内部
box.innerHTML = arr[random]
// 之后删除这个名字
arr.splice(random,1 )
console.log(arr);
</script>
</body>
</html>
中间出现错误,将js写到div上面,导致随机姓名无法显示出来。
设置/修改DOM元素属性
常用属性
还可以通过JS设置/修改标签元素的样式属性,比如通过src更换图片
最常见的属性比如: href、title.src等
语法:
对象.属性 = 值
//1.获取元素
let pic = document.querySelector('img')
//2.操作元素
pic.src = './images/b02.jpg'
pic.title = '这是一个图片'
案例
需求:当我们刷新页面,页面中的图片随机显示不同的图片
分析:
- 随机显示,则需要用到随机函数
- 更换图片需要用到图片的 src属性,进行修改
核心思路:
- 获取图片元素
- 随机得到图片序号
- 图片.src =图片随机路径
<!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="../10327.gif" alt="#">
<!-- <img src="../案例/小学期/images/book1.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/book${num}.png`
</script>
</body>
</html>
样式属性
还可以通过JS设置/修改标签元素的样式属性。
- 比如通过轮播图小圆点自动更换颜色样式
- 点击按钮可以滚动图片,这是移动的图片的位置left 等等
学习路径:
- 通过style属性操作CSS
- 操作类名(className)操作cSs3.通过classList操作类控制CSS
- 通过classList操作类控制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>
div{
width: 300px;
height: 300px;
background-color: pink;
}
</style>
</head>
<body>
<div></div>
<script>
//1.获取元素
let box = document.querySelector('div')
//2.改变1背景颜色 样式 style
box.style.background = 'hotpink'
box.style.width = '400px'
box.style.marginTop = '100px'
</script>
</body>
</html>
注意:
- 修改样式通过style属性引出
- 如果属性有-连接符,需要转换为小驼峰命名法(marginTop)
- 赋值的时候,需要的时候不要忘记加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>
body{
background-image: url(../案例/xtx/images/sprites.png);
}
</style>
</head>
<body>
<script>
function getRandom(min,max) {
return Math.floor(Math.random() * ( max - min +1 )) +min
}
// 随机的值1-10
let num = getRandom(1,10)
// 修改背景图片
document.body.style.backgroundImage = `url(../aadada/ada${num}.jpg )`
// 图片路径
</script>
</body>
</html>
2.操作类名(className)操作CSS
如果修改的样式比较多,直接通过style属性修改比较繁琐,我们可以通过借助于css类名的形式。
语法:
//active是一个css类名
元素.className = 'active'
注意:
- 由于class是关键字,所以使用className去代替
- 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 http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<input type="text" value="请输入">
<button disabled>按钮</button>
<input type="checkbox" id="check">
<script>
//1.获取元素
let input = document.querySelector('input')
//2.取值或者设置值 得到input里面的值可以用value
console.log(input.value)
input.value = '小米手机'
input.type = 'password'
//2.启用按钮
let button = document.querySelector('button')
button.disabled = false
// false启用按钮,ture关闭按钮
//勾选复选框
let checkbox = document.querySelector('.check')
checkbox.checked = false
</script>
</body>
</html>
定时器-间歇函数
开启定时器
setInterval(函数,间歇时间)
作用:每隔一段时间调用这个函数
间隔时间单位是毫秒
function repeat() {
console.log('ajdahdajdpajpo')
}
//每间隔一秒调用repeat函数
srtInterval(repeat,1000)
注意:
-
函数名字不需要加括号
-
定时器返回的是一个id数字
关闭定时器
let 变量名 = setInterval(函数,间歇时间)
clearINterval(变量名)
<!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>
<script>
setInterval(function() {
console.log('高新就业');
},1000)
function show() {
console.log('月薪过万');
}
setInterval(show,1000)
// 清除定时器
clearInterval(cheakbox)
</script>
</body>
</html>
案例
倒计时效果
需求:按钮60秒之后才可以使用
分析:
- 开始先把按钮禁用( disabled属性)
- 一定要获取元素
- 函数内处理逻辑
- 秒数开始减减
- 按钮里面的文字跟着一起变化
- 如果秒数等于0停止定时器里面文字变为同意最后按钮可以点击
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<style>
.btn{
margin-left: 30px;
}
</style>
<body>
<textarea name="" id="" cols="30" rows="10">
用户注册协议
欢迎注册成为京东用户!在您注册过程中,您需要完成我们的注册流程【请您注意】
如果您不同意以下协议全部或任何条款约定,请您停止注;
</textarea>
<br>
<button class="btn" disabled>我已经阅读用户协议(3)</button>
<script>
//1.获取元素
let btn = document.querySelector('.btn')
//2.计算逻辑
//2.1需要一个变量,用来计数
let i = 3
//2.2 开启定时器 简歇一秒
let timer = setInterval(function() {
i--
// console.log(i);
btn.innerHTML = `我已经阅读用户协议(${i})`
if (i === 0) {
// 不走了,清除定时器
clearInterval(timer)
//开启按钮
btn.disabled = false
//更换文字
btn.innerHTML = '我已经阅读用户协议'
}
},1000)
</script>
</body>
</html>
网页轮播图
需求:每隔一秒钟切换一个图片
分析:
- 获取元素(图片和文字)
- 设置定时器函数
- 设置一个变量++
- 更改图片张数
- 更改文字信息
- 处理图片自动复原从头播放
- 如果图片播放到最后一张就是第9张
- 则把变量重置为0
- 注意逻辑代码写到图片和文字变化的前面
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div class="img-box">
<img src="../素材/images/b01.jpg" alt="">
<div class="tip">
<h3 class="text">挑战云歌单,欢迎你来</h3>
</div>
</div>
<script>
// 数据
let data = [
{
imgSrc: '../素材/images/b01.jpg',
title: '挑战云歌单,欢迎你来'
},
{
imgSrc: '../素材/images/b02.jpg',
title: '田园日记,上演上京记'
},
{
imgSrc: '../素材/images/b03.jpg',
title: '甜蜜攻势再次回归'
},
{
imgSrc: '../素材/images/b04.jpg',
title: '我为歌狂,生为歌王'
},
{
imgSrc: '../素材/images/b05.jpg',
title: '年度校园主题活动'
},
{
imgSrc: '../素材/images/b06.jpg',
title: 'pink老师新歌发布,5月10号正式推出'
},
{
imgSrc: '../素材/images/b07.jpg',
title: '动力火车来到西安'
},
{
imgSrc: '../素材/images/b08.jpg',
title: '钢铁侠3,英雄镇东风'
},
{
imgSrc: '../素材/images/b09.jpg',
title: '我用整颗心来等你'
},
]
//1.获取元素(图片和文字)
let pic = document.querySelector('.pic')
let text = document.querySelector('.text')
let i = 0
// 开定时器
setInterval(function(){
i++
//修改src属性
pic.src = data[i].imgSrc
text.innerHTML = data[i].title
//衔接
if(i === data.length - 1){
i= -1
//用-1是因为代码运行到上面就1要++,
// 使用用-1.然后++之后刚好为0
// i === 8? i = -1 : i
}
},1000)
</script>
</body>
</html>
事件
事件监听
-
事件是在编程时系统内发生的动作或者发生的事情
- 比如用户在网页上单击一个按钮
-
事件监听
- 就是让程序检测是否有事件产生,一旦有事件触发,就立即调用一个函数做出响应,也称为注册事件
-
语法
元素.addEVentListener('事件',要执行的函数)
//事件必须是字符串
- 事件监听三要素:
- 事件源:那个dom元素被事件触发了,要获取dom元素
- 事件:用什么方式触发,比如鼠标单击click、鼠标经过mouseover 等
- 事件调用的函数:要做什么事
//获取元素
let btn = document.querySelector('button')
//事件监听(注册事件)
btn.addEventListener('click',function() {
alert('被点击了')
})
注意:
- 事件类型要加引号
- 函数是点击之后再去执行,每次点击都会执行一次
事件类型
事件 | 内容 | 属性 |
---|---|---|
鼠标事件 | 鼠标触发 | click 鼠标点击 mouseenter 鼠标经过 mouseleave 鼠标离开 |
焦点事件 | 表单获得光标 | focus 获得焦点 blur 失去焦点 |
键盘事件 | 键盘触发 | keydown 键盘按下触发 keyup 键盘抬起触发 |
文本事件 | 表单输入触发 | input 用户输入触发 |
案例
高阶函数
高阶函数可以被简单理解为函数的高级应用,JavaScript中函数可以被当成【值】来对待,基于这个特性实现函数的高级应用。
【值】就是JavaScript中的数据,如数值、字符串、布尔、对象等。
回调函数
如果将函数A做为参数传递给函数B时,我们称函数A为回调函数
简单理解:当一个函数当做参数来传递给另外一个函数的时候,这个函数就是回调函数
常见使用场景
function fn() {
cinsole.log('我是回调函数。。。')
}
setInterval(fn,1000)
环境对象
环境对象指的是函数内部特殊的变量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>Document</title>
</head>
<body>
<button>点击</button>
<script>
// 环境对象 this 他就是个对象
function fn() {
console.log(this);
}
fn()
let btn = document.querySelector('button')
btn.addEventListener('click',function() {
console.log(typeof this);
})
//因为btn调用了这个函数,所以this指向谁
</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>
.pink{
background-color: pink;
}
</style>
</head>
<body>
<button class="pink">1</button><button>2</button>
<button>3</button><button>4</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('pink')
// }
// 我只需要找出那个唯一的pink类,删除
document.querySelector('.pink').classList.remove('pink')
// 复活我自己
this.classList.add('pink')
})
}
</script>
</body>
</html>
节点操作
DOM节点
- DOM节点
- DOM树里每一个内容都称之为节点节点类型
- 元素节点
- 所有的标签比如body.div
- html是根节点
- 属性节点
- 所有的属性比如href
- 文本节点
- 所有的文本其他
- 其他
查找节点
节点关系:
父节点
子节点
兄弟节点
父节点查找
- parentNode属性
- 返回最近的一级的父节点,找不到返回为null
子元素.parentNode
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div class="father">
<div class="son">儿子</div>
</div>
<script>
let son = document.querySelector('.son')
// 找爸爸 属性
// console.log(son.parentNode)
son.parentNode.style.dispaly = 'none'
</script>
</body>
</html>
子节点查找
childNodes
- 获得所有子节点、包括文本节点(空格、换行)、注释节点等
children(重点)
- 仅获得所有元素节点
- 返回的还是一个伪数组
父元素.children
<!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>
<script>
let btn = document.querySelector('button')
let ul = document.querySelector('ul')
btn.addEventListener('click',function() {
// console.log(ul.children)
for (let i = 0;i < ul.children.length; i++){
ul.children[i].style.color = 'red'
}
})
ul.children[0].style.color = 'green'
</script>
</body>
</html>
兄弟节点查找
- 下一个兄弟节点
- nextElementSibling属性
- 上一个兄弟节点
- previousElementSibling属性
<!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 class="two">第2个</li>
<li>第3个</li>
<li>第4个</li>
</ul>
<script>
let btn = document.querySelector('button')
let two = document.querySelector('.two')
btn.addEventListener('click',function(){
two.nextElementSibling.style.color = 'red'
two.previousElementSibling.style.color = 'green'
})
</script>
</body>
</html>
节点操作
很多情况下,我们需要在页面中增加元素
- 比如,点击发布按钮,可以新增一条信息
一般情况下,我们新增节点,按照如下操作:
- 创建一个新的节点
- 把创建的新的节点放入到指定的元素内部
创建节点
语法:
document.createElement('标签名')
<!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>
<script>
let div = document.createElement('div')
// 追加属性
div.className = 'current'
let li = document.createElement('li')
</script>
</body>
</html>
追加节点
- 要想在界面看到,还得插入到某个父元素中
- 插入到父元素的最后一个子元素
//插入到父元素的最后一个子元素
父元素.appendChild(子元素)
<!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>
<script>
// let div = document.createElement('div')
// 追加属性
// div.className = 'current'
let ul = document.querySelector('ul')
let li = document.createElement('li')
li.innerHTML = '我是li'
ul.appendChild(li)
</script>
</body>
</html>
- 插入到父元素中某个子元素前面
//插入到父元素中某个子元素前面
父元素.insertBefore(要出入的元素,在哪个元素前面)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<ul>
<li>我是孩子</li>
<li class="two">two</li>
</ul>
<script>
// let div = document.createElement('div')
// 追加属性
// div.className = 'current'
let ul = document.querySelector('ul')
let li = document.createElement('li')
li.innerHTML = '我是li'
// 2.追加节点 父元素.appendChild(子元素) 插入到父元素的最后一个子元素
// ul.appendChild(li)
// 3、追加节点 父元素.insertBefore(要出入的元素,在哪个元素前面)
// ul.children[1]获取ul中第二个li
ul.insertBefore(li,ul.children[1])
</script>
</body>
</html>
案例
需求:按照数据渲染页面分析:
①: 准备好空的ul结构
②: 根据数据的个数,创建一个新的空li
③: li里面添加内容img标题等
④:追加给ul
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>学成在线首页</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<!-- 4. box核心内容区域开始 -->
<div class="box w">
<div class="box-hd">
<h3>精品推荐</h3>
<a href="#">查看全部</a>
</div>
<div class="box-bd">
<ul class="clearfix">
<!-- <li>
<img src="./images/course01.png" alt="">
<h4>
Think PHP 5.0 博客系统实战项目演练
</h4>
<div class="info">
<span>高级</span> • <span> 1125</span>人在学习
</div>
</li> -->
</ul>
</div>
</div>
<script>
let data = [
{
src: 'images/course01.png',
title: 'Think PHP 5.0 博客系统实战项目演练',
num: 1125
},
{
src: 'images/course02.png',
title: 'Android 网络动态图片加载实战',
num: 357
},
{
src: 'images/course03.png',
title: 'Angular2 大前端商城实战项目演练',
num: 22250
},
{
src: 'images/course04.png',
title: 'Android APP 实战项目演练',
num: 389
},
{
src: 'images/course05.png',
title: 'UGUI 源码深度分析案例',
num: 124
},
{
src: 'images/course06.png',
title: 'Kami2首页界面切换效果实战演练',
num: 432
},
{
src: 'images/course07.png',
title: 'UNITY 从入门到精通实战案例',
num: 888
},
{
src: 'images/course08.png',
title: '我会变,你呢?',
num: 590
},
{
src: 'images/course08.png',
title: '我会变,你呢?',
num: 590
}
]
let ul = document.querySelector('ul')
// 1. 根据数据的个数,决定这小li的个数
for (let i = 0; i < data.length; i++) {
// 2. 创建小li
let li = document.createElement('li')
// console.log(li)
// 4. 先准备好内容,再追加
li.innerHTML = `
<img src=${data[i].src} alt="">
<h4>
${data[i].title}
</h4>
<div class="info">
<span>高级</span> • <span> ${data[i].num}</span>人在学习
</div>
`
// 3. 追加给ul 父元素.appendChild(子元素)
ul.appendChild(li)
}
</script>
</body>
</html>
克隆节点
特殊情况下,我们新增节点,按照如下操作:
复制一个原有的节点
把复制的节点放入到指定的元素内部
//克隆一个已有的元素节点
元素.cloneNode(布尔值)
cloneNode会克隆出一个跟原标签一样的元素,括号内传入布尔值
- 若为true,则代表克隆时会包含后代节点一起克隆
- 若为false,则代表克隆时不包含后代节点
- 默认为false
<!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>
let ul = document.querySelector('ul')
// 括号为空则,默认为false 若为false,则代表克隆时不包含后代节点
let newul = ul.cloneNode(true)
document.body.appendChild(newul)
</script>
</body>
</html>
删除节点
若一个节点在页面中已不需要时,可以删除它
在JavaScript 原生DOM操作中,要删除元素必须通过父元素删除
语法
父元素.removeChild(要删除的元素)
注:
如不存在父子关系则删除不成功
删除节点和隐藏节点(display.none)有区别的:隐藏节点还是存在的,但是删除,则从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>
</ul>
<script>
let btn = document.querySelector('button')
let ul =document.querySelector('ul')
btn.addEventListener('click',function(){
// 删除语法
ul.removeChild(ul.children[0])
})
</script>
</body>
</html>
时间对象
时间对象:用来表示时间的对象
作用:可以得到当前系统时间
实例化
在代码中发现了new关键字时,一般将这个操作称为实例化
创建一个时间对象并获取时间
获取当前时间
//获取当前时间
let date = new Date()
// 获取指定时间
let date = new Date('1949-10-09')
时间对象方法
因为时间对象返回的数据我们不能直接使用,所以需要转换为实际开发中常用的格式
方法 | 作用 | 说明 |
---|---|---|
getFullYear() | 获取年份 | 获取四位年份 |
getMonth() | 获取月份 | 取值为0~11 |
getDate() | 获取月份中的每一天 | 不同月份取值也不相同 |
getDay() | 获取星期 | 取值为0~6 |
getHours() | 获取小时 | 取值为0~23 |
getMinutes() | 获取分钟 | 取值为0~59 |
getSeconds() | 获取秒 | 取值为0~59 |
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div></div>
<script>
let arr = ['星期天','星期一','星期二','星期三','星期四','星期五','星期六']
getTime()
setInterval(getTime,1000)
function getTime() {
let date = new Date()
let year = date.getFullYear()
let month = date.getMonth() +1
let date1 = date.getDate()
let day = date.getDay()
let hour = date.getHours()
let min = date.getMinutes()
let sec = date.getSeconds()
let div = document.querySelector('div')
div.innerHTML = `今天是:${year}年${month}月${date1}日
${hour}:${min}:${sec} ${arr[day]}`
}
</script>
</body>
</html>
时间戳
什么是时间戳
是指1970年01月01日00时00分00秒起至现在的毫秒数,它是一种特殊的计量时间的方式
得到时间戳的三种方法
// 1.getTime()
let date = new Date()
console.log(date.getTime())
// 2.简写 + new Date() (推荐)
console.log(+new Date());
// 3.使用Date.now() 只能得到当前的
console.log(Date.now());
重绘和回流(面试)
浏览器是如何进行界面渲染的
- 解析( Parser)HTML,生成DOM树(DOM Tree)
- 同时解析( Parser ) css,生成样式规则(Style Rules)
- 根据DOM树和样式规则,生成渲染树(Render Tree)
- 进行布局Layout(回流/重排):根据生成的渲染树,得到节点的几何信息(位置,大小),在布局(大盒子)
- 进行绘制Painting(重绘):根据计算和获取的信息进行整个页面的绘制
- Display:展示在页面上
重绘和回流(重排)
回流(重排)
- 当Render Tree 中部分或者全部元素的尺寸、结构、布局等发生改变时,浏览器就会重新渲染部分或全部文档的过程称为回流。
重绘
- 由于节点(元素)的样式的改变并不影响它在文档流中的位置和文档布局时(比如: color、background-color,outline等),称为重绘。
重绘不一定引起回流,而回流一定会引起重绘。(面试重点)
- 会导致回流(重排)的操作:
- 页面的首次刷新
- 浏览器的窗口大小发生改变
- 元素的大小或位置发生改变
- 改变字体的大小
内容的变化(如: input框的输入,图片的大小) - 激活css伪类(如: :hover)
- 脚本操作DOM(添加或者删除可见的DOM元素)
- 简单理解影响到布局了,就会有回流
事件对象
获取事件对象
事件对象是什么
- 也是个对象,这个对象里有事件触发时的相关信息
- 例如:鼠标点击事件中,事件对象就存了鼠标点在哪个位置等信息
如何获取
- 在事件绑定的回调函数的第一个参数就是事件对象
- 一般命名为event、ev.e
元素.addEventListener('click',function(e) {}
<!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>
<script>
let btn = document.querySelector('button')
btn.addEventListener('mouseenter',function(e) {
console.log(e);
})
</script>
</body>
</html>
光标
部分常用属性
- type
- 获取当前的事件类型
- clientX/clientY
- 获取光标相对于浏览器可见窗口左上角的位置
- offsetX/offsetY
- 获取光标相对于当前DOM元素左上角的位置
- key
- 用户按下的键盘键的值
- 现在不提倡使用keycode
<!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>
<script>
document.addEventListener('mousemove',function(e){
// console.log(11);
// pageX 和 pageY 跟文档坐标有关系
// console.log(e);
console.log('clinetx:' + e.clientX,'clientY:' + e.clientY)
console.log('pageX:' + e.pageX,'pageY:' + e.pageY)
console.log('offsetx:' + e.offsetX,'offsetY:' + e.offsetY)
})
</script>
</body>
</html>
案例
图片跟着鼠标走
分析:
①:鼠标在页面中移动,用到mousemove事件
②:不断把鼠标在页面中的坐标位置给图片left和top值即可
<!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{
position: absolute ; /*定位 */
top: 0;
left: 0;
}
</style>
</head>
<body>
<img src="./tianshi.gif" alt="">
<script>
let pic = document.querySelector('img')
document.addEventListener('mousemove',function(e) {
// 不断获取当前鼠标坐标
console.log(e.pageX)
console.log(e.pageY)
//把坐标给图片
pic.style.left = e.pageX -40 + 'px'
pic.style.top = e.pageY - 40 + 'px'
})
</script>
</body>
</html>
回车发布微博
需求:按下回车键盘,可以发布信息
需求1∶检测用户输入字数
-
注册input事件
-
将文本的内容的长度赋值给对应的数值
-
表单的maxlength属性可以直接限制在200个数之间
需求2:输入不能为空
- 判断如果内容为空,则提示不能输入为空,并且直接return 不能为空
- 防止输入无意义空格,使用字符串.trim()去掉首尾空格
- 并将表单的value值设置为空字符串
- 同时下面红色为设置为0
需求3:新增留言
- 创建一个小li,然后里面通过innerHTML追加数据
- 随机获取数据数组里面的内容,替换newNode的图片和名字以及留言内容
- 利用时间对象将时间动态化new Date().toLocaleString()
- 追加给ul
事件流
事件流指的是事件完整执行过程中的流动路径
- 说明:假设页面里有个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>
.father {
margin: 100px auto;
width: 400px;
height: 400px;
background-color: pink;
}
.son {
margin: 100px auto;
width: 200px;
height: 200px;
background-color: red;
}
</style>
</head>
<body>
<div class="father">
<div class="son"></div>
</div>
<script>
let fa = document.querySelector('.father')
let son = document.querySelector('.son')
fa.addEventListener('click', function() {
alert('我是爸爸')
})
son.addEventListener('click', function() {
alert('我是儿子')
})
</script>
</body>
</html>
事件捕获
事件捕获概念:
从DOM的根元素开始去执行对应的事件(从外到里)
事件捕获需要写对应代码才能看到效果
代码
son.addEventListener(事件类型,事件处理函数,是否使用捕获机制)
说明:
- addEventListener第三个参数传入true代表是捕获阶段触发(很少使用)
- 若传入false代表冒泡阶段触发,默认就是false
- 若是用LO事件监听,则只有冒泡阶段,没有捕获
<!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 {
margin: 100px auto;
width: 400px;
height: 400px;
background-color: pink;
}
.son {
margin: 100px auto;
width: 200px;
height: 200px;
background-color: red;
}
</style>
</head>
<body>
<div class="father">
<div class="son"></div>
</div>
<script>
let fa = document.querySelector('.father')
let son = document.querySelector('.son')
fa.addEventListener('click', function() {
alert('我是爸爸')
},true)
son.addEventListener('click', function() {
alert('我是儿子')
},ture)
</script>
</body>
</html>
阻止事件流动
因为默认就有冒泡模式的存在,所以容易导致事件影响到父级元素
若想把事件就限制在当前元素内,就需要阻止事件流动
阻止事件流动需要拿到事件对象
语法:
事件对象.stopPropagation()
此方法可以阻断事件流动传播,不光在冒泡阶段有效,捕获阶段也有效
<!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 {
margin: 100px auto;
width: 400px;
height: 400px;
background-color: pink;
}
.son {
margin: 100px auto;
width: 200px;
height: 200px;
background-color: red;
}
</style>
</head>
<body>
<div class="father">
<div class="son"></div>
</div>
<script>
let fa = document.querySelector('.father')
let son = document.querySelector('.son')
fa.addEventListener('click', function() {
alert('我是爸爸')
})
son.addEventListener('click', function(e) {
alert('我是儿子')
// 阻止事件流动
e.stopPropagation()
})
</script>
</body>
</html>
鼠标经过事件:
mouseover和mouseout会有冒泡效果
mouseenter 和mouseleave没有冒泡效果(推荐)
<!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 {
margin: 100px auto;
width: 400px;
height: 400px;
background-color: pink;
}
.son {
margin: 100px auto;
width: 200px;
height: 200px;
background-color: red;
}
</style>
</head>
<body>
<div class="father">
<div class="son"></div>
</div>
<script>
let fa = document.querySelector('.father')
let son = document.querySelector('.son')
fa.addEventListener('mouseenter',function() {
console.log(111);
})
fa.addEventListener('click', function() {
alert('我是爸爸')
})
son.addEventListener('click', function(e) {
alert('我是儿子')
// 阻止事件流动
e.stopPropagation()
})
</script>
</body>
</html>
阻止默认行为,比如链接点击不跳转,表单域的跳转
语法:
e.preventDefault()
- 两种注册事件的区别:
- 传统gn注册(LO)
- 同一个对象,后面注册的事件会覆盖前面注册(同一个事件)
- 直接使用null覆盖偶就可以实现事件的解绑
- 都是冒泡阶段执行的
- 事件监听注册(L2)
- 语法: addEventListener(事件类型,事件处理函数,是否使用捕获)
- 后面注册的事件不会覆盖前面注册的事件(同一个事件)
- 可以通过第三个参数去确定是在冒泡或者捕获阶段执行
- 必须使用removeEventListener(事件类型,事件处理函数,获取捕获或者冒泡阶段)
- 匿名函数无法被解绑
事件委托
事件委托是利用事件流的特征解决一些开发需求的知识技巧
总结:
- 优点:给父级元素加事件(可以提高性能)
- 原理:事件委托其实是利用事件冒泡的特点,给父元素添加事件,子元素可以触发
- 实现:事件对象.target可以获得真正触发事件的元素
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<ul>
<li>我是第一个小li</li>
<li>我是第二个小li</li>
<li>我是第三个小li</li>
<li>我是第四个小li</li>
<li>我是第五个小li</li>
</ul>
<script>
//不要每个小Li注册事件了而是把事件委托给他的爸爸
// 事件委托是给父级添加事件而不是孩子添加事件
let ul = document.querySelector('ul')
ul.addEventListener('click',function(e) {
// alert('我点击了')
// 得到当前元素
// console.log(e.target)
e.target.style.color = 'red'
})
</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>
ul {
list-style: none;
}
* {
margin: 0;
padding: 0;
}
div {
width: 1200px;
height: 400px;
margin: 50px auto;
border: 1px solid red;
overflow: hidden;
}
div li {
width: 240px;
height: 400px;
float: left;
/* 过渡 */
transition: all 500ms;
}
div ul {
width: 1200px;
}
</style>
</head>
<body>
<div id="box">
<ul>
<li>
<a href="#">
<img src='../手风琴images/1.jpg' alt="">
</a>
</li>
<li>
<a href="#">
<img src='../手风琴images/2.jpg' alt="">
</a>
</li>
<li>
<a href="#">
<img src='../手风琴images/3.jpg' alt="">
</a>
</li>
<li>
<a href="#">
<img src='../手风琴images/4.jpg' alt="">
</a>
</li>
<li>
<a href="#">
<img src="../手风琴images/5.jpg" alt="">
</a>
</li>
</ul>
</div>
<script>
// 1.li默认有个宽度是240像素
// 2.当我们鼠标经过,当前的小i 宽度变大 800px其余的小Li 变为100px
// 3.·鼠标离开事件,所有的小Li都要复原宽度为240px
// (1)获取元素
let lis = document.querySelectorAll('li')
// (2)绑定鼠标经过和离开事件
for (let i = 0; i < lis.length; i++) {
// 鼠标经过事件
lis[i].addEventListener('mouseenter',function() {
// 排他思想干掉所有人108px,复活我自己800px
for ( j = 0; j < lis.length; j++) {
lis[j].style.width = '100px'
}
this.style.width = "800px"
})
// 鼠标离开
lis[i].addEventListener('mouseleave',function() {
// 排他思想干掉所有人108px,复活我自己800px
for ( j = 0; j < lis.length; j++) {
lis[j].style.width = '240px'
}
})
}
</script>
</body>
</html>
list is not defined at HTMLLIElement.
期间出现这个报错是因为在将所有宽度变成100px中的循环中的lis.length我写成了list.length。
滚动和加载事件
滚动事件
- 当页面进行滚动时触发的事件
- 为什么要学?
- 很多网页需要检测用户把页面滚动到某个区域后做一些处理,比如固定导航栏,比如返回顶部
- 事件名: scroll
- 监听整个页面滚动:
window.addEventListener('scroll',function(){
})
给window 或 document添加scroll事件
- 监听某个元素的内部滚动直接给某个元素加即可
<!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>
body{
height: 3000px;
}
div{
overflow:auto ;
width: 200px;
height: 50px;
background-color: pink;
}
</style>
</head>
<body>
<div>
文字
文字
文字
文字
文字
文字
文字
文字
文字
文字
文字
文字
文字
文字
文字
文字
文字
文字
文字
文字
文字
文字
文字
文字
文字
文字
文字
文字
文字
文字
文字
</div>
<script>
let div = document.querySelector('div')
// window.addEventListener('scroll',function(){
// console.log(111);
// })
div.addEventListener('scroll',function(){
console.log(111)
})
</script>
</body>
</html>
加载事件
加载外部资源(如图片、外联CSS和JavaScript等)加载完毕时触发的事件
为什么要学?
- 有些时候需要等页面资源全部处理完了做一些事情
- 老代码喜欢把script 写在 head 中,这时候直接找dom元素找不到
事件名:load
监听页面所有资源加载完毕:
- 给window添加load事件
window.addEventListener('load',function(){}
- 注意:不光可以监听整个页面资源加载完毕,也可以针对某个资源绑定load事件
当初始的HTML文档被完全加载和解析完成之后,DOMContentLoaded事件被触发,而无需等待样式表、图像等完全加载
事件名:DOMcontentLoaded
监听页面DOM加载完毕:
- 给document添加DOMContentLoaded事件
document.addEventListener('DOMcontentLoaded',function(){}
元素大小和位置
scroll 家族
使用场景:
我们想要页面滚动一段距离,比如100px,就让某些元素显示隐藏,那我们怎么知道,页面滚动了100像素呢?
就可以使用scroll来检测页面滚动的距离
- 获取宽高
- 获取元素的内容总宽高(不包含滚动条)返回值不带单位
- scrollwidth和scrollHeight
<!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: 150px;
height: 150px;
background-color: pink;
overflow: auto;
}
</style>
</head>
<body>
<div>
我有很多很多的内容哦
我有很多很多的内容哦
我有很多很多的内容哦
我有很多很多的内容哦
我有很多很多的内容哦
我有很多很多的内容哦
我有很多很多的内容哦
我有很多很多的内容哦
我有很多很多的内容哦
我有很多很多的内容哦
我有很多很多的内容哦
我有很多很多的内容哦
我有很多很多的内容哦
我有很多很多的内容哦
我有很多很多的内容哦
我有很多很多的内容哦
</div>
<script>
// scrollwidth和scrollHeight 内容的大小(了解)
let div = document.querySelector('div')
console.log(div.scrollWidth)
console.log(div.scrollHeight)
</script>
</body>
</html>
- 获取位置
- 获取元素内容往左、往上滚出去看不到的距离
- scrollLeft和scrollTop
- 这两个属性是可以修改的
div.addEventListener('scroll',function() {
console.log(this.scrollLeft)
开发中,我们经常检测页面滚动的距离,比如页面滚动100像素,就可以显示一个元素,或者固定一个元素
案例
页面滚动显示返回顶部按钮
需求:当页面滚动500像素,就显示返回顶部按钮,否则隐藏,同时点击按钮,则返回顶部
分析:
①:用到页面滚动事件
②:检测页面滚动大于等于100像素,则显示按钮
③:点击按钮,则让页面的scrollTop重置为0
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
.content {
height: 3000px;
width: 1000px;
background-color: pink;
margin: auto;
}
.backtop {
display: none;
width: 50px;
left: 50%;
margin: 0 0 0 505px;
position: fixed;
bottom: 60px;
z-index: 100;
}
.backtop a {
height: 50px;
width: 50px;
background: url(../素材/images/bg2.png) 0 -600px no-repeat;
opacity: 0.35;
overflow: hidden;
display: block;
text-indent: -999em;
cursor: pointer;
}
</style>
</head>
<body>
<div class="content"></div>
<div class="backtop">
<img src="../素材/images/close2.png" alt="">
<a href="javascript:;"></a>
</div>
<script>
var i = 500
let backtop = document.querySelector('.backtop')
// 页面滚动事件
window.addEventListener('scroll', function() {
// 检测滚动距离
let num = document.documentElement.scrollTop
// 进行判断和隐藏
if (num >= i) {
// 显示返回顶部
backtop.style.display = 'block'
} else {
// 或者隐藏元素
backtop.style.display = 'none'
}
})
// 点击返回顶部
backtop.children[1].addEventListener('click',function() {
document.documentElement.scrollTop = 0
})
let img = document.querySelector('img')
img.addEventListener('click',function() {
backtop.style.display = 'none'
// function addi () {
// i += 500
// }
// // console.log(i)
})
</script>
</body>
</html>
存在改进,想法是点了×之后,增加500,不出现回到顶部的图案,思路是利用局部变量 i 改变全局变量 i
offset 家族
使用场景:
前面案例滚动多少距离,都是我们自己算的,最好是页面滚动到某个元素,就可以做某些事。
简单说,就是通过js的方式,得到元素在页面中的位置这样我们可以做,页面滚动到这个位置,就可以返回顶部的小盒子显示…
获取宽高
- 获取元素的自身宽高、包含元素自身设置的宽高、padding. border
- offsetHeight和offsetWidth
获取位置
- 获取元素距离自己定位父级元素的左、上距离
- 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
- BOM(Browser Object Model)是浏览器对象模型
- window是浏览器内置中的全局对象,我们所学习的所有WebAPls 的知识内容都是基于window对象实现的
- window对象下包含了navigator、location、document、history、screen 5个属性,即所谓的BOM(浏览器对象模型)
- document是实现DOM的基础,它其实是依附于window的属性。
定时器 - 延时函数
JavaScript内置的一个用来让代码延迟执行的函数,叫setTimeout
语法:
setTimeout(回调函数,等待的毫秒数)
setTimeout仅仅只执行一次,所以可以理解为就是把一段代码延迟执行,平时省略window
let timer = setTimeout(回调函数,等待的毫秒数)
clearTimeout(timer)
<!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>
<script>
// 只能使用一次
let timer = setTimeout(function(){
console.log(111)
},3000)
let btn = document.querySelector('button')
btn.addEventListener('click',function(){
clearTimeout(timer)
})
</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>
</head>
<body>
<script>
// 所以要加一个退出条件,使得递归不死
let num = 0
// 死递归
function fn() {
num++
console.log(111)
if (num>= 100){
return
}
fn()
}
fn()
</script>
</body>
</html>
案例:利用递归实现setInterval
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div></div>
<script>
let div = document.querySelector('div')
function fn() {
div.innerHTML = new Date().toLocaleDateString()
setTimeout(fn,1000)
}
fn()
</script>
</body>
</html>
两个定时器对比
- setInterval的特征是重复执行,首次执行会延时
- setTimeout 的特征是延时热行,只执行1次
- setTimeout结合递归函数,能模拟setlnterval重复执行
- clearTimeout清除由setTimeout 创建的定时任务
JS执行机制
经典面试题
console.log(111)
setTimeout(function() {
console.log(222)
},1000)
console.log(333)
//结果111 333 222
console.log(111)
setTimeout(function() {
console.log(222)
},0)
console.log(333)
//结果还是111 333 222
JS是单线程
JavaScript语言的一大特点就是单线程,也就是说,同一个时间只能做一件事。这是因为Javascript这门脚本语言诞生的使命所致——JavaScript 是为处理页面中用户的交互,以及操作DOM而诞生的。比如我们对某个DOM元素进行添加和删除操作,不能同时进行。应该先进行添加,之后再删除。
单线程就意味着,所有任务需要排队,前一个任务结束,才会执行后一个任务。这样所导致的问题是:如果JS执行的时间过长,这样就会造成页面的渲染不连贯,导致页面渲染加载阻塞的感觉。
同步和异步
为了解决这个问题,利用多核CPU的计算能力,HTML5提出 web worker标准,允许JavaScript脚本创建多个线程。于是,JS中出现了同步和异步。
同步
前一个任务结束后再执行后一个任务,程序的执行顺序与任务的排列顺序是一致的、同步的。比如做饭的同步做法:我们要烧水煮饭,等水开了(10分钟之后),再去切菜,炒菜。
异步
你在做一件事情时,因为这件事情会花费很长时间,在做这件事的同时,你还可以去处理其他事情。比如做饭的异步做法,我们在烧水的同时,利用这10分钟,去切菜,炒菜。
他们的本质区别:这条流水线上各个流程的执行顺序不同。
同步任务
同步任务都在主线程上执行,形成一个执行栈。
异步任务
JS的异步是通过回调函数实现的。
一般而言,异步任务有以下三种类型:
-
普通事件,如click、resize等
-
资源加载,如 load、error 等
-
定时器,包括setlnterval、 setTimeout等
JS执行机制
异步任务相关添加到任务队列中(任务队列也称为消息队列)。
-
先执行执行栈中的同步任务。
-
异步任务放入任务队列中。
-
一旦执行栈中的所有同步任务执行完毕,系统就会按次序读取任务队列中的异步任务,于是被读取的异步任务结束等待状态,进入执行栈,开始执行。
由于主线程不断的重复获得任务、执行任务、再获取任务、再执行,所以这种机制被称为事件循环(event loop)。
location 对象
location 对象
location的数据类型是对象,它拆分并保存了URL地址的各个组成部分
常用属性和方法:
-
href属性获取完整的URL地址,对其赋值时用于地址的跳转
// 可以得到当前文件url地址 console.log(location.href) // 可以通过js方式跳转到目标地址 location.href = 'http://www.baidu.com'
案例
5秒钟之后跳转的页面
需求:用户点击可以跳转,如果不点击,则5秒之后自动跳转,要求里面有秒数倒计时分析:
①:目标元素是链接
②:利用定时器设置数字倒计时③:时间到了,自动跳转到新的页面
支付成功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> span{ color: red; } </style> </head> <body> <a href="http://www.baidu.com">支付成功,<span>5</span>秒之后跳转首页</a> <script> let a = document.querySelector('a') let num = 5 let timer = setInterval(function() { num-- a.innerHTML = `支付成功,<span>${num}</span>秒之后跳转首页` if(num === 0) { clearTimeout(timer) location.href = 'https://www.bilibili.com/' } },1000) </script> </body> </html>
-
search 属性获取地址中携带的参数,符号?后面部分
console.log(loaction.search)
<!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> <form action="target.html"> <input type="text" name="username"> <button>提交</button> </form> </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> <script> console.log(location.search) </script> </body> </html>
-
hash 属性获取地址中的啥希值,符号#后面部分
console.log(location.hash)
后期vue路由的铺垫,经常用于不刷新页面,显示不同页面,比如网易云音乐
-
reload方法用来刷新当前页面,传入参数true时表示强制刷新
<button>点击刷新</button> <script> let btn = document.querySelector('button') btn.addEventListener('click', function() { //刷新方法 有本地缓存 强制刷新ctrl + f5 直接更新最新内容从网上拉去,不走本地缓存 location.reload(true) //强制刷新 CTRL+f5 }) </script>
navigator对象
通过userAgent检测浏览器的版本及平台
histroy对象
history的数据类型是对象,该对象与浏览器地址栏的操作相对应,如前进、后退、历史记录等
常用属性和方法
history对象方法 | 作用 |
---|---|
back() | 可以后退功能 |
forward() | 前进功能 |
go(参数) | 前进后退功能 参数如果是1前景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同时使用的时候,类名需要注意区分
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<link rel="stylesheet" href="./css/swiper-bundle.min.css">
<style>
.box {
width: 600px;
height: 350px;
background-color: pink;
margin: 100px auto;
}
html,
body {
position: relative;
height: 100%;
}
body {
background: #eee;
font-family: Helvetica Neue, Helvetica, Arial, sans-serif;
font-size: 14px;
color: #000;
margin: 0;
padding: 0;
}
.swiper-container {
width: 100%;
height: 100%;
margin-left: auto;
margin-right: auto;
}
.swiper-slide {
text-align: center;
font-size: 18px;
background: #fff;
/* Center slide text vertically */
display: -webkit-box;
display: -ms-flexbox;
display: -webkit-flex;
display: flex;
-webkit-box-pack: center;
-ms-flex-pack: center;
-webkit-justify-content: center;
justify-content: center;
-webkit-box-align: center;
-ms-flex-align: center;
-webkit-align-items: center;
align-items: center;
}
.swiper-slide img {
width: 100%;
height: 350px;
}
.swiper-pagination-bullet {
width: 12px;
height: 12px;
}
.swiper-pagination-bullet-active {
background-color: #fff;
}
</style>
</head>
<body>
<div class="box">
<!-- Swiper -->
<div class="swiper-container one">
<div class="swiper-wrapper">
<div class="swiper-slide">
<a href="#">
<img src="./images/b_01.jpg" alt="">
</a>
</div>
<div class="swiper-slide">
<a href="#">
<img src="./images/b_02.jpg" alt="">
</a>
</div>
<div class="swiper-slide">
<a href="#">
<img src="./images/b_03.jpg" alt="">
</a>
</div>
<div class="swiper-slide">
<a href="#">
<img src="./images/b_04.jpg" alt="">
</a>
</div>
<div class="swiper-slide">
<a href="#">
<img src="./images/b_05.jpg" alt="">
</a>
</div>
</div>
<!-- Add Pagination -->
<div class="swiper-pagination"></div>
<!-- Add Arrows -->
<div class="swiper-button-next"></div>
<div class="swiper-button-prev"></div>
</div>
</div>
<div class="box">
<!-- Swiper -->
<div class="swiper-container two">
<div class="swiper-wrapper">
<div class="swiper-slide">
<a href="#">
<img src="./images/b_01.jpg" alt="">
</a>
</div>
<div class="swiper-slide">
<a href="#">
<img src="./images/b_02.jpg" alt="">
</a>
</div>
<div class="swiper-slide">
<a href="#">
<img src="./images/b_03.jpg" alt="">
</a>
</div>
<div class="swiper-slide">
<a href="#">
<img src="./images/b_04.jpg" alt="">
</a>
</div>
<div class="swiper-slide">
<a href="#">
<img src="./images/b_05.jpg" alt="">
</a>
</div>
</div>
<!-- Add Pagination -->
<div class="swiper-pagination"></div>
<!-- Add Arrows -->
<div class="swiper-button-next"></div>
<div class="swiper-button-prev"></div>
</div>
</div>
<script src="./js/swiper-bundle.min.js"></script>
<!-- 要放到插件的下面 -->
<!-- Initialize Swiper -->
<script>
var swiper = new Swiper('.one', {
slidesPerView: 1,
autoplay: {
delay: 3000,
stopOnLastSlide: false,
disableOnInteraction: true,
},
spaceBetween: 0,
loop: true,
pagination: {
el: '.swiper-pagination',
clickable: true,
},
navigation: {
nextEl: '.swiper-button-next',
prevEl: '.swiper-button-prev',
},
keyboard: true,
});
var swiper = new Swiper('.two', {
slidesPerView: 1,
autoplay: {
delay: 5000,
stopOnLastSlide: false,
disableOnInteraction: true,
},
spaceBetween: 0,
loop: true,
pagination: {
el: '.swiper-pagination',
clickable: true,
},
navigation: {
nextEl: '.swiper-button-next',
prevEl: '.swiper-button-prev',
},
keyboard: true,
});
</script>
</body>
</html>
本地存储
随着互联网的快速发展,基于网页的应用越来越普遍,同时也变的越来越复杂,为了满足各种各样的需求,会经常性在本地存储大量的数据,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字符串转换成对象 取出 时候使用
<!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>
<script>
// 存储数据 localStorage.setItem(键,值)
// localStorage.setItem('uname','孙悟空')
// localStorage.setItem('age',18)
// 获取数据 localStorage.getItem(key)
// localStorage.getItem('uname')
// 删除数据
// localStorage.removeItem('uname')
// 调用复杂类型
let obj = {
uname : '老八' ,
age : 18 ,
address : '试吃员'
}
// 复杂数据类型一定要转换为json字符串在进行存储
localStorage.setItem('obj' ,JSON.stringify(obj))
// 取数据可以使用JSON.parseo将json字符串转换为对系
JSON.parse(localStorage.getItem('obj'))
// // json字符串 属性和值都是双引号进行包含
// let ob = {
// "uname" : "老八" ,
// "age" : "18 ",
// "address" : "试吃员"
// }
let object = {
age : 18
}
//本地存储只能存储字符串所以我要转换转换为JSON格式的字符串
localStorage.setItem('key',JSON.stringify(object))
// //获取的过来的值是字符串,不是对象了没有办法直接使用,因此我们首先吧字符串转换为对象
// JSON.parse()
console.log(JSON.parse(localStorage.getItem('key')));
</script>
</body>
</html>
正则表达式
- 正则表达式 (Regular Expression)是用于匹配字符串中字符组合的模式。在JavaScript中,正则表达式也是对象
- 通常用来查找、替换那些符合正则表达式的文本,许多语言都支持正则表达式。
正则表达式作用:
- 表单验证(匹配)
- 过滤敏感词(替换)
- 字符串中提取我们想要的部分(提取)
语法步骤:
-
定义规则
-
语法:
let 变量名 = /表达式/
-
其中/ /是正则表达式字面量
-
例如
let reg = /前端/
-
-
判断是否有符合规则的字符串:
test()方法用来查看正则表达式与指定的字符串是否匹配-
语法(重点)
regObj.test(被检测的字符串)
-
如果正则表达式与指定的字符串匹配,返回true,否则false
-
-
检索(查找)符合规则的字符串:
exec()方法在一个指定字符串中执行一个搜索匹配-
语法
regObj.exec(被检测的字符串)
如果匹配成功,exec()方法返回一个数组,否则返回null
-
元字符
● 普通字符:
大多数的字符仅能够描述它们本身,这些字符称作普通字符,例如所有的字母和数字。也就是说普通字符只能够匹配字符串中与它们相同的字符。
● 元字符(特殊字符)
是一些具有特殊含义的字符,可以极大提高了灵活性和强大的匹配功能。
- 比如,规定用户只能输入英文26个英文字母,普通字符的话abcdefghijklm…
- 但是换成元字符写法:[a-z]
参考文档:
- MDN: https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Guide/Regular_Expressions
- 正则测试工具 http:// tool.oschina.net/regex
边界符
正则表达式中的边界符(位置符)用来提示字符所处的位置,主要有两个字符
边界符 | 说明 |
---|---|
^ | 表示匹配行首文本(以睡开始) |
$ | 表示匹配行尾的文本(以谁结束) |
<!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>
<script>
console.log(/哈/.test('哈哈哈'))
//^开头
console.log(/^哈/.test('二哈哈'))
console.log(/^哈$/.test('二哈哈'))
console.log(/^哈$/.test('哈'))
</script>
</body>
</html>
量词
量词用来设定某个模式出现的次数
量词 | 说明 |
---|---|
* | 重复零次或更多次 |
+ | 重复一次或更多次 |
? | 重复零次或一次 |
{n} | 重复n次 |
{n,} | 重复n次或更多次 |
{n,m} | 重复n次到m次 |
注意:逗号左右两侧千万不要出现空格
字符类
(1)[] 匹配字符串集合
使用连字符–表示一个范围
// 只要中括号里面的任意字符出现都返回为true
console.log(/[abc]/.test('andy')) //true
console.log(/[abc]/.test('bady')) //true
console.log(/[abc]/.test('cry')) //true
console.log(/[abc]/.test('die')) //false
比如:
- [a-z]表示 a到z26个英文字母都可以
- [a-zA-Z] 表示大小写都可以
- [0-9]表示0~9的数字都可以
(2)[]里面加上^取反符号
比如:
- [ ^a-z]匹配除了小写字母以外的字符
- 注意要写到中括号里面
(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}
\d{4}0-9出现4次即年,后面是出现一次或者两次即09-11或者9-11