Web APIs
Web APIs
Web APIs
什么是DOM
文档对象 操作网页的内容 实现用户交互
DOM树
标签与标签的关系
DOM对象
把网页内容当对象 , 它提供的属性和方法都是访问和操作网页内容 , 网页所有内容都是document
获取DOM对象
//选择匹配的第一个元素 document.querySelector('css选择器 或 标签');
- 如果没有找到,返回null
//选择匹配的多个元素 document.querySelectorAll('css选择器 或 标签')
- 返回对象集合 ,没有找到也返回集合
- 会得到伪数组 有长度 有索引号 但没有方法
修改样式
//修改css样式 对象.style.属性 = '属性值';
- 如果属性有 - 符号 把 - 去掉 把后面的首字母大写
- 例: background-color 改成 backgroundColor
其他获取方法
//根据ID获取 document.getElementById('id'); //根据标签获取 document.getElementsByTagName('div'); //根据类名获取 document.getElementsByClassName('box');
操作类
对象.className = '类名';
- 在css里面写样式
- 类名需要加上之前的类 不然会覆盖
//单纯的加一个类 对象.classList.add('类名'); //删除一个类 对象.classList.remove('类名');//返回伪数组 //原来有这个类删除 没有添加 对象.classList.toggle('类名'); //返回伪数组
操作表单元素
// 获取input 的属性 const input = document.querySelector('input') // 对象.属性 = '属性值' input.type = 'password' console.log(input);
定时器
function name() { console.log('giao') } //值1 函数不用加括号 值2 时间 毫秒 setInterval(name, 1000); //方法二 setInterval(function (){console.log('giao')}, 1000);
- 隔多少秒调用函数
停止计时器
clearInterval(计时器ID); //获取计时器ID let timerId = setInterval(......);
倒计时效果
<input type="button" class="btn" value="已阅读用户协议(5)" id="btn" disabled> <script type="text/javascript"> let btn = document.querySelector('.btn'); let i = 5; let timeId = setInterval(function () { i -- ; btn.value = `已阅读用户协议(${i})`; if (i == 0) { clearInterval(timeId); btn.disabled = false ; btn.value = '已阅读用户协议'; } }, 1000); </script>
修改元素的内容
对象.innerText = ''
- 只能获取文本
对象.innerHTML = ''
- 可以获取所有内容 包括标签 空格
- 会自动解析标签
保留原内容
- 对象.innerHTML = '对象.innerHTML + '新内容' '
- 对象.innerText = '对象.innerText + '新内容' '
事件监听
事件监听定义
监听网页有没有发生这些事情,如果发生了就给一个对应的函数来处理
监听三要素
事件源
- 发生事情的元素
事件类型
- 具体发生了什么 是被双击还是鼠标经过...
响应程序
- 就是函数,事件发生后调用函数
监听语法
标签对象.addEventListener('事件类型',函数);
- 事件类型需要加引号 函数不用加括号
随机点名
- 步骤:
-
- 找对应标签(div,开始按钮,结束按钮)
- 给开始按钮加点击事件,开启一个定时器,间隔不断的随机出一个下标,再根据下标取出数组里的值,然后把值显示到div里
-
- 给结束按钮加点击事件,需要停止定时器,声明一个全局变量保存定时器的id,在结束里就可以停止定时器了
- 要完成点一个少一个,所以需要把随机出来的下标也保存起来,所以把它升级成全局变量,然后在结束的点击事件里根据下标删除数组元素
-
- 在开始的点击事件里一开始就做判断,如果数组长度为1了,就没必要随机了,而是直接取出下标0的值显示到页面,并且把开始和停止两个按钮禁用即可,再return,让后面代码不执行了(不开定时器了)
-
bug1:
-
- 连续先点好几下
结束
按钮,会直接把数组删光 - 解决办法:判断有定时器才删除,所以就是判断定时器id是否为null,不为null才删除
- 连续先点好几下
-
- 但是此时会有新bug,只要开一个定时器后,还是能再删数组,所以停止定时器后,需要立即把timerId改为空即可
-
bug2:
-
- 点击多次开始按钮,这个时候点击结束按钮,结束不了
- 原因:多次点击开始,会产生多个定时器,而定时器id只能保存最后一个,所以点击结束时无法全部停掉
-
- 解决办法:点击多次开始也只让它产生一个定时器,也就是开启新的定时器之前,先把上一个关掉
<!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; } h2 { text-align: center; } .box { width: 600px; margin: 50px auto; display: flex; font-size: 25px; line-height: 40px; } .qs { width: 450px; height: 40px; color: red; } .btns { text-align: center; } .btns button { width: 120px; height: 35px; margin: 0 50px; } </style> </head> <body> <h2>随机点名</h2> <div class="box"> <span>名字是:</span> <div class="qs">这里显示姓名</div> </div> <div class="btns"> <button class="start">开始</button> <button class="end">结束</button> </div> <script> // 数据数组 let arr = ['马超', '黄忠', '赵云', '关羽', '张飞'] function getRandom(min, max) { return Math.floor(Math.random() * (max - min + 1)) + min } // 找到三个元素 let qs = document.querySelector('.qs') let start = document.querySelector('.start') let end = document.querySelector('.end') // 全局变量timerId:记录定时器的id let timerId = null // 全局变量idx:记录当前被点名的下标 let idx = 0 // 给开始加点击事件 start.addEventListener('click', function () { // 点击开始时要做判断 // 判断数组元素数量是否只有1个了,如果只有一个了,就不要开定时器 // 把按钮给禁用了 if (arr.length == 1) { // 把最后这个名字直接显示到页面 qs.innerText = arr[0] // 让开始和停止两个按钮的disabled都为true start.disabled = end.disabled = true return // 后面代码不执行了 } // 每次开新的定时器之前需要把上一次的定时器给停止掉 clearInterval(timerId) // 把产生随机名字的代码,放到定时器里 timerId = setInterval(function () { // 产生一个随机下标 idx = getRandom(0, arr.length - 1) // 根据随机下标取出数组里的数据赋值给qs去显示 qs.innerText = arr[idx] }, 25) }) // 给结束按钮加点击事件 end.addEventListener('click', function () { // 有定时器才停止定时器,并删除数组 if (timerId != null) { // 停止定时器 clearInterval(timerId) // 停止定时器后,马上把定时器id改为null // 避免下次还能再点 timerId = null // 点一个少一个,也就是删掉数组里出现的元素 arr.splice(idx, 1) } }) </script> </body> </html>
监听事件
- 事件源.on事件 = function () {}
- 写两个一样的会覆盖
- 事件源.addEventListener(事件,函数)
- 写两个一样的不会覆盖
事件类型
鼠标事件
- click 鼠标单击
- mouseenter 鼠标经过
- mouseleave 鼠标离开
焦点事件
- focus 获取焦点
- blur 失去焦点
键盘事件
- Keydown 键盘按下触发
- Keyup 键盘抬起触发
表单输入
- input 用户输入 一边输入 一遍触发
高阶函数
函数表达式
let fn = function (){ consolg.log('giao'); }; //表达式名 + () 调用方法 fn();
回调函数
function fn1(fn2){ console.log(fn2); } function fn2(){ console.log('giao'); } //fn2 就是回调函数 把函数当数据传给传递 //函数当值的时候不用加() fn1(fn2);
环境对象 - this
- 指函数里的this
- 谁调用的函数this就是谁
节点
节点简介
- 元素节点:指的标签
- 属性节点:指的属性
- 文本节点:指的文本
- 其他节点:注释,document
父节点与子节点
- 父节点:包括别的节点
- 子节点:被包含的节点
查找父节点
元素.parentNode
- 找到父元素
查找子节点与子元素
子节点
元素.childNodes
- 找的节点:包括标签,文本,注释
子元素
元素.children
- 找的标签
注意:找到的都属伪数组
查找兄弟节点与元素
上一个兄弟
元素.previousSibling
- 上一个节点
- 找的节点:包括标签,文本,注释
元素.previousElementSibling
- 找到上一个标签
下一个兄弟
元素.nextSibling
- 下一个节点
- 找的节点:包括标签,文本,注释
元素.nextElementSibling
- 找到下一个标签
创建元素
let 名字 = document.createElement('标签名'); // 只能是标签名 //元素默认看不到,变成被人的子元素 名字.innerText = '内容'; //在父元素的最后添加名字 父元素.appendChild(名字);
添加元素
//在元素最后添加 父元素.appendChild(名字); //在指定的位置添加 //如果第二个参数传入的是null或者undefined,那也是添加到最后 父元素.insertBefore(要添加的元素, 在哪个子元素的前面); //插入到最前面 父元素.insertBefore( 要添加的元素, 父元素.children[0] ) 例如:ul.insertBefore(li, ul.children[0])
克隆元素
元素.cloneNode();
- 克隆出元素
- 浅克隆
- 只会克隆所有的行内属性,但不会克隆出内容
元素.cloneNode(true);
- 克隆出元素
- 深克隆
- 克隆出所有的内容
两种克隆都不会包含元素的事件监听
行内事件
<div onclick="alert('123')"> 盒子 </div>
- 克隆会包含行内事件,因为行内事件相当于行内属性
删除元素
父元素.removeChild(删除的子元素);
- 常用的方法
删除的元素.remove();
- 新浏览器可以调用remove
去除两端空格
元素.trim();
重绘和重排(回流)
- 解析HTML生成DOM树
- 同时解析CSS生成样式规则
- 根据DOM树和样式规则生成渲染树
- 进行重排得到几何信息(位置,大小)
- 进行绘制进行整个页面的绘制
- 展示页面
重排(回流)
- 当渲染树发生尺寸,结构,布局改变的时候会进行重排
重绘
- 当节点元素的样式改变,并不影响在文档流中的位置就会重绘
导致重排的一些操作
-
页面的首次刷新
-
浏览器的窗口大小发生改变
-
元素的大小或位置发生改变
-
改变字体的大小
-
内容的变化(如:input框的输入,图片的大小)
-
激活css伪类 (如::hover)
-
脚本操作DOM(添加或者删除可见的DOM元素)
-
总结:影响到布局的会有重排
导致重绘的一些操作
-
背景颜色改变
-
字体颜色改变
-
......
-
总而言之:如果只是不影响布局的,那就只有
重绘
没有重排
事件对象
事件对象与获取
触发事件时,浏览器自动帮我们产生一个对象
-
如何拿到
对象.addEventListener('click',function (形参){ //这个形参就是事件对象 })
事件对象常用的属性
type
- 获取事件类型 比如会得到 click dblckick
pageX / pageY
- 获取元素到页面文档左上角的x,y距离
clientX / clientY
- 获取元素到可视区域左上角的x,y距离
offsetX / offsetY
- 获取鼠标位置到触发元素自身左上角的x,y距离
key
- 按下按键时获取键盘按钮
事件流
事件流三大阶段
- 捕获阶段:从document开始一级一级往下
- 目标阶段:触发事件的元素
- 冒泡阶段:从触发事件的元素一级一级往上返
为什么会流动
因为当一个div被点击,其实最早并不是由div先发现的,而是先由浏览器发现的,所以需要一级一级往下找到真正触发事件元素,再处理事件,处理完再一级一级往上依次反馈
事件冒泡
当一个元素的事件出发后,会一级一级往上调用父级元素的同名事件,直到document
事件捕获
元素.addEventListener('事件类型', 回调函数, true)
-
默认看不到,必须写上面代码
要想看到事件捕获,必须用 L2 事件注册语法,且第三个参数要传true
L0只有冒泡没有捕获
阻止流动
事件对象(函数里的参数).stopPropagation()
- 一定要获取事件对象
- 不光能阻止冒泡还能阻止捕获
mouseover与mouseout
- 鼠标移入和移出(不推荐)
- 他从父到子也会触发移入移出,效率不高
mouseenter与mouseleave
- 鼠标移入移出
- 不会叠加冒泡
阻止事件默认行为
例如a标签点击之后不跳转
-
事件对象.perventDefault()
事件委托
冒泡默认存在,所有不管哪个子元素都会触发父元素
很多时候不希望所有子元素都触发,所有在父元素上判断
事件元素.target 获取真正触发的元素 事件元素.target.tagName 获取的都是大写
滚动事件
滚动事件
scroll 只要滚动就会触发 window对象,代表浏览器 ,如果要监听浏览器滚动,就要给window加scroll事件
window.addEventListener('scroll', function () { // 页面资源加载完毕才调用 }) //也可以给元素加 谁有滚动给谁加 div.addEventListener('scroll', function () { // 页面资源加载完毕才调用 })
页面加载事件
当页面所有资源加载完毕之后调用
window.addEventListener('load', function () { // 页面资源加载完毕才调用 })
dom加载事件
等dom加载完毕就调用
document.addEventListener('DOMContentLoaded', function () { // dom加载完毕调用 })
scroll家族
-
scrollWidth 和 scrollHeight
获得 内容 + padding + 溢出 就是元素的宽高
-
scrollLeft 和 scrollTop
○ 是内容往左边滚出去看不到的距离(scrollLeft)
○ 是内容往上边滚出去看不到的距离(scrollTop)
○ 这两个属性可以改,改了就代表设置滚动条滚出去的距离
○ 可以把scrollLeft和scrollTop设置的超出它最大的滚动距离,那样也只是帮你滚到最后
○ 所以如何让垂直滚动条能滚到最后?元素.scrollTop = 元素.scrollHeight
页面滚出去的距离
document.documentElement
- 获取html
document.documentElement.scrollTop
- 获取HTML向上的距离 可以赋值
offset家族
- offsetWdith 和 offsetHeight 获取的是盒子
实际占用
的宽度
和高度
- offsetLeft 和 offsetTop 获取的是盒子到定位自己的父级 左或上 距离
client家族
-
clientWidth 和 clientHeight
获得的是边框里面的内容
可视区
-
作用:方便根据视口大小做响应式开发
JS执行
定时器-延时执行
setTimeout(function(){},1000)
- 1秒之后执行一次,只一次
递归函数
函数自己调用自己 , 一级一级递过去,又一级一级归来
JS执行机制
同步与异步
-
同步:
-
- 就像在超市结账,只有一个收银口,大家依次排队,上一个结算完了再结算下一个
- 所谓同步:就是从上往下依次执行(像排队一样)
-
异步:
-
- 就像在超市结账,只有一个收银口,其中有个人结账时对质量不满意,那么就先把这个人带去跟部门经理沟通,收银口继续对下一个客户进行结算,等部门经理沟通完了,这个人再来排队买单
- 像这种情况在代码中有一个专业名词叫
异步
-
- JS中,异步任务一般是通过
回调函数
实现的,一般可能需要耗时的代码都是异步代码
- JS中,异步任务一般是通过
-
-
- 例如:定时器可能要耗时,例如事件可能要耗时
- 异步代码是通过
回调函数
来实现的
-
-
setInterval(回调函数) // 异步代码 setTimeout(回调函数) // 异步代码 btn.addEventListener('click', 回调函数) // 异步代码 // 包括后面要学的ajax(发网络请求,网络可能会耗时,所以它也是异步代码)
执行图
- 异步进入Event Table(事件表)区分异步 然后进入 Event Queue(事件队列),主线程执行完毕就会去Event Queue(事件队列)读取异步函数,会重复不断执行,也就是Event Loop(事件循环)
window对象
- navigator 对象
- location 对象
- document 对象
- history 对象
- screen 对象
location对象
- 代表浏览器的地址栏
- 属性
-
- href
-
- 可以获取当前浏览器的网址
- 也可以设置网址
- search
-
- 获取浏览器上 ?+后面的部分内容(获取查询)
- 例如 ?.sht
- hash
-
- 获取浏览器上 #+后面的内容
- 例如 #23th
navigator对象
- 检查浏览器信息 判断PC还是移动
// 检测 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://m.itcast.cn' } })()
history对象
-
代表浏览器的历史记录
-
history.forward(); 前进
-
history.back(); 后退
-
go(number);
-
- 正数代表前进,负数代表后退
- 正1:代表前进1个,正2,代表前进2个,以此类推
-
- 负1:代表后退1个,负2,代表后退2个,以此类推
JSON字符串
本质是一种字符串
-
作用:前后端传递数据
-
规则:
-
- 用
[]
表示的是数组,{}
表示的是对象
- 用
-
- 如果用
{}
表示对象,那么键必须用双引号
包起来
- 如果用
-
- 字符串最外层要么是
[]
要么是{}
- 字符串最外层要么是
-
把json字符串转换为JS
-
- JSON.parse( json字符串 );
- JSON.stringify( js数据 )
localStorage
本地储存 , 把数据储存到浏览器,永久储存 , 只要不删就一直存在
是按域名保存的,域名A下域名A自己的数据,域名B的网站是访问不了域名的A的数据的,同样域名A也访问不了域名B的数据
setltem
localStorage.setItem(参数1(key),参数2(值);
- 保存数据
- 如果保存相同的key,后面的覆盖前面的
getItem
localStorage.getItem(参数(key));
- 获取参数
- 如果数据不存在,得到null
removeItem
localStorage.removeItem(参数(key));
- 删除数据
clear
localStorage.clear();
在浏览器找到 localStorage
保存的数据
-
localStorage只能保存字符串数据,如果你传入了非字符串数据,那它也强制把数据转成了字符串再保存的
-
如何保存复杂类型?(对象、数组那些)
-
- 把复杂类型转成JSON格式的字符串保存起来
- 然后取出来的时候,再把它按JSON字符串转成JS数据
sessionStorage
会话存储 ,只要页面关闭数据就没了
其他属性和localStorage一样
自定义属性
-
一种是系统属性 系统自带 例如 href target等等
-
自定义属性就是自己添加的,原本没有
-
区分自定义属性
-
- h5后新增规范
-
-
一般在定义属性前 data-自定义名字
-
可以用 元素.dataset 操作属性
-
// html元素 <textarea id="address" data-name="yyy" data-role="xxx"></textarea> let dom = document.querySelector("#address") // 获取元素节点的所有 data-* 属性 console.log(dom.dataset) // {name: 'yyy', role: 'xxx'} // 删除 data-name 属性 delete dom.dataset.name // 添加/修改 data-test 属性 dom.dataset.名字 = '值' -
-
-
自定义属性,在
js
中无法通过点语法
直接操作的 -
如果要操作属性
-
-
元素.getAttribute('属性');
获取元素
-
元素.setAttribute('属性','属性值');
设置属性
-
元素.removeAttribute('属性');
删除属性
-
window对象是JS里的顶级对象
所有
window的属性
可以理解为是全局变量
<script> function fn () { window.age = 999 // 相当于是全局变量 console.log(age) // 999 } fn() // 也可以完整写成 window.fn,因为这相当于是window的方法 console.log(age) // 999 </script>
正则
正则表达式
- 描述字符串的特征
查找字符串有没有'字符'
/字符/.test(字符串范围(例如:input.value));
- 判断字符串范围有没有字符
- 有 返回 true
- 没有 返回 false
元字符-边界符
- ^ 以什么内容开头
- $ 以什么内容结尾
/^内容/ // 内容XXX /内容$/ // XXX内容
- 结合在一起就是精确匹配 必须是 内容
元字符-量词
量词 | 说明 |
---|---|
* | 出现0或多次 |
+ | 出现1次或多次 |
? | 出现0次或1次 |
出现n次 | |
出现至少n次 | |
出现至少n次,最大m次 |
- 这些量词只修饰它左边的那一个字符,所以要修饰整体,记得内容加小括号包起来
元字符-字符类
-
| 要么左 要么右
-
- a | b | c 要么a 要么b 要么c 任意一个
-
[]
-
- 匹配字符集合 括号中任意一个都可以
- [abc123] 要么a 要么b 要么c 要么1 要么2 要么3
-
[-]
-
-
表示范围 [起点-终点]
-
[a-z] // a-z中的任意一个 [0-9] // 0-9中的任意一个 [A-Z] // A-Z中的任意一个 [a-zA-Z0-9] // 代表任意一个大小写字母或者任意一个数字
-
-
[^]
-
- 表示非
- [^0-9] // 除了0-9 的任意一个
-
.
-
- 除了\r\n 以外的任意数
注意 : 不加严格匹配代表只要有即可 加了严格匹配代表只能是某个格式
匹配中文
/[\u4e00-\u9fa5]/
-
\u4e00 就是第一个汉字
-
\u9fa5 就是最后一个汉字
元字符-预定义类
- 预定义类:就是正则里用特殊符号来标识它属于哪一类数据
预定义类 | 说明 |
---|---|
\d\d | 匹配数字 |
\D | 匹配非数字 |
\w | 匹配文本字符,也就是任意字母、数字、下划线 |
\W | 匹配非文本字符,也就是除了字母、数字、下划线 |
\s | 匹配不可见字符 |
\S | 匹配可见字符 |
正则修饰符
/正则内容/修饰符 例如 /[a-z]/ig 忽略大小写全局匹配
- i 忽略大小写
- g 全局匹配 可以找到所有匹配的内容
- 两个一起写 代表 既忽略大小写,也全局匹配
替换
- 内容.replace(表达式,要替换的内容)
str.replace(正则表达式, 要替换的内容) // 例 let str = 'oooOOO哈哈哈OOOooo' str = str.replace(/o/ig, '') // 把所有的o不区分大小写全部替换成空字符串 console.log(str) // 哈哈
正则本质
- 正则本质上就是一个对象,
/规则/
这种写法是字面量表示法 - 也可以用构造函数创建出一个正则
- 传两个参数 规则(必须有),修饰符(可不写)
let 对象名 = new RegExp('规则', '修饰符')
let reg = new RegExp('sb', 'ig') // 代表忽略大小写而且全局的找sb // 如果要找字母数字下划线怎么写? 字面量:/\w/ let reg2 = new RegExp('\\w', '修饰符')
- 注意:如果要写预定义类,要多加一个\,例如
\\w
和\\d
,因为\
在js字符串中是转义的意思,所以要写\
就必须写\\
如何用敏感词库
- 先把敏感词库的数组转成字符串(用
|
) - 再然后用
new RegExp
来创建正则对象
let words = ['sb', '激情', '政府', '警察' ] let str = words.join('|') let reg = new RegExp(str, 'ig') console.log( "今天大家都很sb,也很有激情,大家要爱护警察,支持政府!".replace(reg, '**') )
正则的exec方法(了解)
- 正则对象除了
test
方法,还有一个方法叫exec
,就是用来做提取内容的
/哈哈/.exec('你好啊,哈哈');
- 得到数字
邮箱验证
- 前一段是允许字母,数字,下划线 至少1位最多18位
- 后面接一个@
- @后面接 字母数字,至少1位
- 后面接一个 .
- 点后面接英文字母,至少2位,最多4位
- .com或.cn 可能出现多次,但至少要一次
- 正则如下
/^\w{1,18}@[a-z0-9]+(\.[a-z]{2,4})+$/i
- 点前面的 \ 是转义因为 . 有特殊含义
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步