Web API(1~3)
Day1
课程安排
第一天:DOM-获取元素(获取元素、修改属性)
第二天:DOM-事件基础(注册事件、tab栏切换)
第三天:DOM-事件进阶(事件对象、事件委托)
第四天:DOM-节点操作(节点的增删改查)
第五天:BOM-操作游览器(BOM、插件、本地存储)
第六天:正则表达式(正则表达式、综合案例)
第七天:实战(小兔鲜个人实战)
Web API基本认知
变量声明:var(淘汰)、let、const(优先)
复杂数据类型用const也可以改值,因为在栈里的地址没变
建议数组和对象使用const声明
作用和分类
作用:JS操作HTML和游览器
分类:DOM、BOM
什么是DOM
是文档对象模型,操作网页内容
DOM树
将HTML文档以树状结构直观表现,称为文档树或DOM树
作用:直观体现标签与标签间关系
DOM对象
游览器根据HTML标签生成的JS对象
DOM核心思想:把网页内容当作对象处理
document对象:DOM提供的一个对象
提供的属性和方法是用来访问和操作网页内容的
网页所有内容都在document里
获取DOM对象
根据CSS选择器来获取DOM元素
选择匹配的第一个元素:
document.querySelector('CSS选择器')
选择匹配多个元素:
document.querySelectorAll('CSS选择器')
返回一个伪数组,有长度有索引,但没方法,要得对象需遍历
其他获取DOM元素方法(了解即可)
根据id获取一个元素:
document.getElementById('nav')
根据标签获取一类元素:
document.getElementsByTagName('div')
根据类名获取元素:
document.getElementsByClassName('w')
操作元素内容
目标:能改元素的文本更换内容
对象.innerText
属性将文本内容添加/更新到任意标签位置,显示纯文本,不解析标签
对象.innerHTML
属性将文本内容添加/更新到任意标签位置,会解析标签,多标签建议使用模板字符
练习--年会抽奖
//声明数组
const personArr = ['小明','小红','小刚']
//随机数 数组的下标
const random=Math.floor(Math.random()*personArr.length)
//获得one元素(一等奖)
const one=document.querySelector('#one')
//把名字给one
one.innerHTML=personArr[random]
//删除这个名字
personArr.splice(random,1)
操作元素属性
操作元素常用属性
对象.属性=值
练习--页面刷新,图片随机更换
funtion getRandom(N,M) {
return Math.floor(Math.random()*(M-N+1))+N
}
//获取图片对象
const img=document.querySelector('img')
//随机得到序号
const random=getRandom(1,6)
//更换路径
img.src=`./images/${random}.webp`
操作元素样式属性
通过style属性操作CSS:
对象.style.样式属性=值
(多组单词小驼峰命名)练习--页面刷新,页面随机更换背景图片
<head>
<style>
body {
background: url(./images/desktop_1.jpg) no-respeat top center cover;
}
</style>
</head>
<body>
<script>
funtion getRandom(N,M) {
return Math.floor(Math.random()*(M-N+1))+N
}
const random=getRandom(1,10)
document.body.style.backgroundImage=`url(./images/desktop_${random}.jpg)`
</script>
</body>
操作类名(className)操作CSS
元素.className='CSS类名'
className是新值换旧值,若要添加一个类,需保留之前的类名
通过classList操作类控制CSS
为解决className覆盖以前类名,可用classList方式追加和删除类名
追加一个类:
元素.classList.add('类名')
删除一个类:
元素.classList.remove('类名')
切换一个类:
元素.classList.toggle('类名')
练习--轮播图随机版
const sliderData=[{...},{...},{...}]//初始数据
//需要一个随机数
const random=parseInt(Math.random()*sliderData.length)
//获取图片
const img=document.querySelector('.slider-wrapper img')
//修改图片路径 对象.url
img.src=sliderData[random].url
//修改文字内容
const p=document.querySelector('.slider-wrapper img') //获取
p.innerHTML=sliderData[random].title //修改
// 修改背景颜色
const footer=document.querySelector('.slider-footer')
footer.style.backgroundColer=sliderData[random].color
//小圆点
const li=document.querySelector(`.slider-indicator li:nth-child(${random+1})`)
//让当前li添加active类(实现高亮)
li.classList.add('active')
操作表单元素属性
获取:DOM对象.属性名
设置:DOM对象.属性名=新值
表单属性添加、移除效果,一律用布尔值表示
比如:disabled、checked、selected
<input type="checked" name="" id="">
<button>点击</button>
<script>
const ipt=document.querySelector('input')
ipt.checked=true //选中
const button=document.querySelector('button')
button.disabled=true //禁用
</script>
自定义属性
标准属性、自定义属性
HTML5出了专门的data-自定义属性
标签一律以data-开头,在DOM对象上一律以dataset对象方式获取
定时器-间歇函数
定时器函数介绍
开启定时器:
setInterval(函数,间隔时间)
(间隔时间单位是毫秒)函数名字不需要加括号
定时器返回的是一个id数字,独一无二
关闭定时器:
let 变量名=setInterval(函数,间隔时间)
clearInterval(变量名)
练习--阅读用户协议
<body>
<textarea ...>
文本
</textarea>
<br>
<button class="btn" disabled>我已阅(5)</button>
<script>
const btn=document.querySelector('.btn')
let i = 5
let n=setInterval(funtion() {
i--
btn.innerHTML=`我已阅(${i})`
if(i===0) {
clearInterval(n)
btn.disabled=false //开按钮
btn.innerHTML='同意'
}
},1000)
</script>
</body>
定时器函数基本使用
综合案例--轮播图定时器版
需求:每隔一秒切换图片
//初始化 略
//获取元素
const img=document.querySelector('.slider-wrapper img')
const p=document.querySelector('.slider-footer p')
let i=0
//开定时器
setInterval(funtion(){
i++
//最后一张之后的无缝衔接
if(i>=sliderData.length) {
i=0
}
//更换图片路径
img.src=sliderData[i].url
//把字写到p里
p.innerHTML=sliderData[i].title
//小圆点
//先删以前的active
document.querySelector('.slider-indicator .active').classList.remove('active')
//只让当前li添加active
document.querySelector(`.slider-indicator li:nth-child(${i+1})`).classList.add('active')
},1000)
Day2
事件监听(绑定)
事件监听
元素对象.addEventListener('事件类型',要执行的函数)
三要素:事件源、事件类型、事件调用函数
练习
<button>点击</button>
<script>
const btn=document.querySelector('button')
btn.addEventListener('click',funtion() {
alert('你好')
})
</script>
练习--关闭广告
<style>
.box1 {... cursor: pointer} //广告的叉掉标识
</style>
<script>
//获取事件源
const box1=document.querySelector('.box1')
//关闭的是大盒子
const box=document.querySelector('.box')
//事件监听
box1.addEventListerner('click',funtion() {
box.style.display='none'
})
</script>
练习--随机点名案例
<script>
//数据数组
const arr=['马超','黄忠','赵云','关羽','张飞']
//1.开始按钮转换
const qs=document.querySelector('.qs')
let timeId=0 //定时器全局变量
let random=0 // 随机号要全局变量
//1.1获取开始按钮对象
const start=document.querySelector('.start')
//1.2添加点击事件
start.addEventListener('click',funtion() {
timerId.setInterval(funtion() {
//随机数
random=parseInt(Math.random()*arr.length)
qs.InnerHTML=arr[random]
},35)
//如果数组里只有一个值,不需抽取,让两个按钮禁用
if(arr.length===1) {
start.disabled=end.disabled=true
}
})
//2.关闭按钮模块
const end=document.querySelector('.end')
end.addEventListener('click',funtion() {
clearInterval(timeId)
//结束一轮就删掉当前抽到的
arr.splice(random,1)
})
</script>
拓展阅读-事件监听版本
DOM L0:事件源.on事件=function() {}
DOM L2:事件源.addEventListener(事件,事件处理函数)
区别:on方式会被覆盖,addEventListener方式可绑定多次,推荐
事件类型
鼠标事件(鼠标触发)
click鼠标点击
mouseenter鼠标经过
mouseleave鼠标离开
练习--轮播图点击切换
<script>
//获取元素
const img=document.querySelcetor('.slider-wrapper img')
const p=document.querySelector('.slider-footer p')
const footer=document.querySelector('.slider-footer')
//右侧按钮业务
//1.1获取右侧按钮
const next=document.querySelector('.next')
let i=0 //信号量,控制播放图片张数
//1.2注册点击事件
next.addEventListener('click',funtion() {
i++
//1.6判断条件,实现衔接
i= i>=data.length? 0 : i
//1.3得到对应对象
//调用函数
toggle()
})
//左侧按钮业务
//2.1获取左侧按钮
const prev=document.querySelector('.prev')
//2.2注册点击事件
prev.addEventListener('click',funtion() {
i--
//2.6判断条件,实现衔接
i= i<0? data.length-1 : i
//2.3得到对应对象
//调用函数
toggle()
//声明一个渲染函数作为复用
function toggle() {
//1.4渲染对应数量
img.src=data[i].url
p.innerHTML=data[i].title
footer.style.background=data[i].color
//1.5更换小圆点 先移除,再添加
document.querySelector(`.slider-indicator .active`).classList.remove('active')
document.querySelector(`.slider-indicator li:nth-child(${i+1})`).classList.add('active')
}
})
//3.自动播放模块
let timeId=setInterval(function(){
//利用JS自动调用点击事件
next.click()
},1000)
//4.鼠标经过大盒子停止定时器
const slider=document.querySqlqctor('.slider')
//注册事件
slider.addEventListener('mouseenter',function() {
//停止定时器
clearInterval(timeId)
})
//5.鼠标离开大盒子开启定时器
//注册事件
slider.addEventListener('mouseleave',function() {
//停止定时器 (好习惯,先关再开)
clearInterval(timeId)
//开启定时器
timeId=setInterval(function(){
//利用JS自动调用点击事件
next.click()
},1000)
})
</script>
焦点事件(表单获得光标)
focus获得焦点
blur失去焦点
<input type="text">
<script>
const input=document.querySelector('input')
input.addEventListener('focus',function() {
console.log('有焦点触发')
})
input.addEventListener('blur',function() {
console.log('无焦点触发')
})
</script>
练习--小米搜索框
<div class="mi">
<input type="search" placeholder="小米笔记本">
<ul class="result-list">
<li><a href="#">全部商品</li>
<li><a href="#">小米笔记本</li>
<li><a href="#">小米蓝牙</li>
<li><a href="#">小米手机</li>
<ul>
</div>
<script>
const input=document.querySelector('[type-search]')//属性选择器
input.addEvenListener('focus',function(){
ul.style.display='block'
imput.classList.add('search')
})
input.addEvenListener('blur',function(){
ul.style.display='none'
imput.classList.remove('search')
})
</script>
键盘事件(键盘触发)
Keydown键盘按下触发
Keyup键盘抬起触发
文本事件(表单输入触发)
input用户输入事件
练习--评论字数统计
<style>
input {
width: 200px;
transition: all .3s;
}
input:focus { //focus伪类选择器,获得焦点
width: 300px;
}
</style>
<script>
const tx=document.querySelector('#tx')
const total=document.querySelector('.total')
//文本获得焦点,就让total显示
tx.addEventListener('focus',function() {
total.style.opacity=1
})
//文本失去焦点,就让total隐藏
tx.addEventListener('blur',function() {
total.style.opacity=0
})
//检测用户输入
tx.addEventListener('input',function() {
total.innerHTML=`${tx.value.length}/200字`
})
</script>
事件对象
获取事件对象:元素.addEventListener('click',function(e) {})
事件对象常用属性
type
获取当前的事件类型
clientX/clientY
获取光标相对于游览器可见窗口左上角的位置
offsetX/offsetY
获取光标相对于当前DOM元素左上角的位置
key
用户按下的键盘键的值
现在不提倡使用keyCode
练习--评论回车发布
//接上一例
const item=document.querySelector('.item')
const text=document.querySelector('.text')
//按下回车发布评论
tx.addEventListener('keyup',function(e) {
//只有回车键才触发
if(e.key==='Enter') {
//用户输入不为空就显示和打印
if(tx.value.trim()) {
item.style.display='block'
text.innerHTML=tx.value
}
//回车后清空文本域
tx.value=''
//回车后把字符统计复原
total.innerHTML='0/200字'
}
})
环境对象
特殊变量this,代表当前函数运行时所处环境
每个函数都有this,普通函数的this指向window
函数调用方式不同,this指向对象不同。谁调用,this指谁(粗略规则)
回调函数
将函数A作为参数传给函数B时,称函数A为回调函数
回头调用
使用匿名函数作为回调函数较常见
综合案例--Tab栏切换
const as=document.querySelectorAll('.tab-nav a')
for(let i=0;i<as.length;i++) {
//要给几个链接绑定鼠标经过事件
as[i].addEventListener('mouseenter',function(){
//排他思想
document.querySelector('.tab-nav .active').classList.remove('active')
this.classList.add('active')
//下部大盒子一一对应
document.querySelector('.tab-content .active').classList.remove('active')
document.querySelector('.tab-content .item:nth-child(${i+1})').classList.add('active')
})
}
Day3
案例--全选文本框
<script>
//1.获取大复选框
const checkAll=document.querySelector('#checkAll')
//2.获取小复选框
const cks=document.querySelectorAll('.ck')
//3.点击大复选框,注册事件
checkAll.addEventListener('click',function() {
//得到当前大复选框选中状态
//console.log(checkAll.checked) //得到true或false
4.遍历所有小复选框 让小的checked=大的checked
for(let i=0; i<cks.length; i++) {
cks.[i].checked=checkAll.checked
}
})
//5.小复选框控制大
for(let i=0;i<cks.length;i++) {
//5.1给所以小添加点击事件
cks[i].addEventListener('click',function() {
//判断选中小的个数是不是等于总的小个数
checkAll.checked= document.querySelectorAll('.ck:checked').length==cks.length
})
}
</script>
事件流
事件流与两个阶段说明
是事件完整执行过程中的流动路径
捕获阶段(父到子)
冒泡阶段(子到父)(实际工作冒泡为主)
事件捕获
概念:从DOM元素的根元素开始去执行对应的时间(从外到里)
DOM.addEventListener(事件类型,事件处理函数,是否使用捕获机制)
事件冒泡
概念:一个元素触发事件后,依次向上调用所以父级元素的同名事件
默认存在。第三个参数是false,或默认都是冒泡
阻止冒泡
问题:容易影响父级元素
需求:把事件限制在当前元素内
前提:阻止冒泡需拿到事件对象
语法:
事件对象.stopPropagation()
此方法可以阻断事件流动传播,不光在冒泡,捕获阶段也有效
阻止默认行为:
e.preventDefault()
解绑事件
on事件方法,直接用null覆盖
//绑定事件
btn.onclick=function() {
alert('点击了')
}
//解绑事件
btn.onclick=null
addEventListener方式必须用:
removeEventListener(事件类型,事件处理函数[,获取捕获或者冒泡阶段])
function fn() {
alert('点击了')
}
//绑定事件
btn.addEventListener('click',fn)
//解绑事件
btn.removeEventListener('click',fn)
鼠标经过事件的区别
mouseover和mouseout会有冒泡效果
mouseenter和mouseleave没有冒泡效果(推荐)
事件委托
是利用事件流的特征解决一些开发需求的知识技巧
优点:减少注册次数,提高程序性能
原理:利用事件冒泡特点
给父元素注册事件,触发子元素时会冒泡到父元素身上,从而触发父元素
实现:
事件对象.target.tagName
可获得真正触发事件的元素练习--tab栏切换改造
其他事件
页面加载事件
load事件
有时需等页面全处理完再做事情。老代码把script写在head,直接找dom元素找不到
监听页面所有资源加载完毕
window.addEventListener('load',function(){...})
//给window添加load
DOMContentLoaded
当初始HTML加载解析完后,DOMContentLoaded触发,无需等完全加载
监听页面DOM加载完毕
document.addEventListener('DOMContentLoaded',function(){...})
元素滚动事件
滚动条滚动时触发
给window或document添加scroll事件
获取位置:scrollLeft和scrollTop,可读写,数字型,不带单位
滚动到哪出现或消失
<script>
const div=document.querySelector('div')
window.addEventListener('scroll',function() {
const n=document.documentElement.scrollTop
if(n>=100) {
div.style.display='block'
}else{
div.style.display='none' //opacity有淡出淡入效果
}
})
</script>
点击返回页面顶部
const backTop=document.querySelector('#backTop')
backTop.addEventListener('click',function() {
document.documentElement.scrollTop=0
})
滚动到指定坐标
元素.scrollTo(x,y)
页面尺寸事件
会在窗口尺寸改变时触发事件
window.addEventListener('resize',function() {...})
检测屏幕宽度
window.addEventListener('resize',function() {
let w=document.documentElement.clientWidth
console.log(w)
})
获得宽高:clientWidth、clientHeight。(不含边框、margin、滚动条)
元素尺寸与位置
通过JS得到元素在页面中的位置
获得宽高:offsetWidth、offsetHeight,包含元素padding、border
结果是数值
注:获取的是可视的,若隐藏,结果为0
获取位置:offsetLeft、offsetTop。(只读属性)
获取元素距离自己定位父级元素的左、上距离
大于某盒子的某位置就隐藏或消失
elevator.style.opacity= n>=entry.offsetTop?1:0
练习--模仿京东固定导航栏
<script>
const sk=document.querySelector('.sk')
const header=document.querySelector('.header')
window.addEventListener('scroll',function() {
const n=document.documentElement.scrollTop
header.style.top=n>=sk.offsetTop?0:'-80px'
})
</script>
练习--实现bilibili点击小滑块移动效果
.line {
position: absolute;
...
transition: all .3s; 过渡效果
}
<script>
//获取父元素,添加事件委托
const list=document.querySelector('.tabs-list')
const line=document.querySelector('.line')
//给a注册事件
list.addEventListener('click',function(e) {
//判断点击的是a
if(e.target.tagName==='A') {
//得到当前链接offsetLeft
//让line盒子进行移动
line.style.transform=`translateX(${e.target.offsetLeft}px)`
}
})
</script>
获取位置2:
element.getBoundingClientRect()
返回元素的大小及其相对于视口的位置
综合案例--电梯导航
//以下在CSS里写
//让页面丝滑滚动
html {
scroll-behavior: smooth;
}
//以下在script里写
//第一大模块,页面滑动可以显示和隐藏
(function() {...})();
//第二第三放在另外一个执行函数里(防止污染)
(function() {
//2.点击页面可以滑动
const list=document.querySelector('.xtx-elevator-list')
list.addEventListener('click',function(e) {
if(e.target.tagName==='A' && e.target.dataset.name) {
//排他思想
const old=document.querySelector('.xtx-elevator-list .active')
if(old) old.classList.remove('active')
e.target.classList.add('active')
//获取对应大盒子的offsetTop
const top=document.querySelector(`.xtx_goods_${e.target.dataset.name}`).offsetTop
//让页面滚动到对应位置
document.documentElement.scrollTop=top
}
})
//3.页面滑动,可以根据大盒子选小盒子添加active类
window.addEventListener('scroll',function() {
//3.1 先移除类
const old=document.querySelector('.xtx-elevator-list .active')
if(old) old.classList.remove('active')
//3.2判断页面当前滑动位置,选择小盒子
//获取四个大盒子
const news=document.querySelector('.xtx_goods_new')
const popular=document.querySelector('.xtx_goods_new')
const brand=document.querySelector('.xtx_goods_new')
const topic=document.querySelector('.xtx_goods_new')
const n=document.documentElement.scrollTop
if(n>=news.offsetTop&&n<popular.offsetTop) {
document.querySelector('[data-name=new]').classList.add('active')
}else if(n>=popular.offsetTop&&n<brand.offsetTop) {
document.querySelector('[data-name=popular]').classList.add('active')
}else if(n>=brand.offsetTop&&n<topic.offsetTop) {
document.querySelector('[data-name=brand]').classList.add('active')
}else if(n>=topic.offsetTop) {
document.querySelector('[data-name=topic]').classList.add('active')
}
})
})();
属性选择器
[ ]
自定义属性集合
dataset
dataset.name