DOM和BOM笔记
@description:DOM和BOM操作的整合
@author:liuwy
@date:2023.4.2
Ⅰ、DOM
一、DOM操作
1.根据css选择器来获取DOM元素
选择匹配的第一个元素
//document.querySelector('css选择器')
<body>
<div class="box"></div>
<script>
const box = document.querySelector('.box')//css选择器匹配的第一个元素,返回值为一个HTMLElement对象
//或const box = document.querySelector('div')
box.style.color = 'blue'//可以直接做修改
console.log(box)
</script>
</body>
选择匹配的多个元素
document.querySelectorAll('css选择器')
<body>
<ul>
<li>测试1</li>
<li>测试2</li>
<li>测试3</li>
</ul>
<script>
const lis = document.querySelectorAll('ul li')//返回值为NodeList对象集合
//不能直接做修改,只能通过遍历的方式一次给里面的元素做修改
console.log(lis)
</script>
</body>
document.querySelectorAll(‘css选择器’)得到的是一个伪数组
- 有长度有索引号的数组
- 但是没有pop() push()等数组方法
想要得到里面的每一个对象,则需要遍历(for)的方式获得
2.其他获取DOM元素的方法
//根据id获取一个元素
document.getElementById('nav')//id选择
//根据类名获取元素 获取页面 所有类名为 w 的元素
document.getElementsByClassName('w')//类选择
//根据标签获取一类元素 获取页面中所有div
document.getElementsByTagName('div')//标签选择
3.操作元素内容
对象.innerText 属性
<body>
<div class="box">我是文字内容</div>
<script>
const box = document.querySelector('.box')
box.innerText = '我是一个盒子'
</script>
</body>
- 将文本内容添加/更新到任意标签位置
- 显示纯文本,不解析标签
对象.innerHTML 属性
<body>
<div class="box">我是文字内容</div>
<script>
const box = document.querySelector('.box')
box.innerHTML = '<strong>我是一个盒子</strong>'
</script>
</body>
- 将文本内容添加/更新到任意标签位置
- 会解析标签,多标签建议使用模板字符
4.操作元素属性
<body>
<div class="box"></div>
<script>
const box = document.querySelector('.box')
box.属性 = "新的属性"
</script>
</body>
5.操作元素样式属性
对象.style.样式属性 = '值'
<head>
<style>
.box{
width: 200px;
height: 200px;
background-color: pink;
}
</style>
</head>
<body>
<div class="box"></div>
<script>
const box = document.querySelector('.box')
box.style.width = '300px'
box.style.backgroundColor = 'hotpink'//属性中多组单词的,采用驼峰命名法可以有效解决
box.style.border = '2px solid blue'//可以给对象添加属性
//修改样式较少的情况下有优势 生成的是行内样式表,权重比较高
document.body.style.backgroundImage = `改变属性${}`
//body不需要获取,可以直接调用document.body来进行操作
</script>
</body>
6.通过classList修改样式
<head>
<style>
.active{
width: 200px;
height: 200px;
background-color: pink;
}
</style>
</head>
<body>
<div class="box"></div>
<script>
const box = document.querySelector('.box')
box.classList.add('active')//追加类 add() 类名不加点,并且是字符串
box.classList.remove('box')//移除类 remove() 类名不加点,并且是字符串
box.classList.toggle('active')//切换类 toggle() 有就删掉,没有就加上,开关
//classList是追加和删除 不影响以前的类名
</script>
</body>
7.操作表单元素属性
<body>
<input type="checkbox" value="电脑">
<script>
const ipt = document.querySelector('input')
console.log(ipt.checked)// false 布尔值 不选中为false
ipt.checked = true
</script>
</body>
8.自定义属性
<div data-id="5">1</div>
<div>2</div>
<div>3</div>
<div>4</div>
<div>5</div>
<script>
const one = document.querySelector('div')
console.log(one.dataset)//DOMStringMap {id: '5'} id : "5"
console.log(one.dataset.id)//5
</script>
9.定时器 - 间歇函数
1.开启定时器
//setInterval(函数,间隔时间) 间隔时间单位为毫秒
setInterval(function(){
console.log('一秒执行一次')
}, 1000)
function fn() {
console.log('一秒执行一次')
}
setInterval(fn, 1000)//有名函数第一个参数写函数名,不需要加小括号
每个定时器都会有自己的编号
2.关闭定时器
let 变量名 = setInterval(函数,间隔时间)
clearInterval(变量名)
一般不会刚创建就停止,而是满足一定条件再停止
二、DOM事件
1.事件监听
就是让程序检测是否有事件产生,一旦有事件触发,就立即调用一个函数做出响应,也称为绑定事件或者注册事件
2.addEventListener与on区别
为某元素设定事件触发函数时,
addEventListener除了可以设置元素触发顺序外,还能多次绑定事件
on 不能多次绑定,否则的话会出现覆盖。即后绑定的on方法覆盖之前绑定的on方法,导致之前绑定的on方法失效
3.事件
鼠标事件 | 焦点事件 | 键盘事件 | 文本事件 |
---|---|---|---|
鼠标触发 | 表单获得光标 | 键盘触发 | 表单输入触发 |
click 鼠标点击 | focus 获得焦点 | keydown 键盘按下触发 | input 用户输入事件 |
mouseenter 鼠标经过 | blus 失去焦点 | keyup 键盘抬起触发 | |
mouseleave 鼠标离开 |
//鼠标事件
document.querySelector('.class').addEventListener("click", function(){
console.log("鼠标点击");
});
document.querySelector('.class').addEventListener("click", function(){
console.log("鼠标经过");
});
document.querySelector('.class').addEventListener("click", function(){
console.log("鼠标离开");
});
//焦点事件
document.querySelector('.class').addEventListener("focus", function(){
console.log("获得焦点");
});
document.querySelector('.class').addEventListener("blur", function(){
console.log("失去焦点");
});
案例:小米搜索框
<div class="mi">
<input type="search" placeholder="小米笔记本">
<ul class="result-list">
<li><a href="#">全部商品</a></li>
<li><a href="#">小米11</a></li>
<li><a href="#">小米10S</a></li>
<li><a href="#">小米笔记本</a></li>
<li><a href="#">小米手机</a></li>
<li><a href="#">黑鲨4</a></li>
<li><a href="#">空调</a></li>
</ul>
</div>
<script>
// 1. 获取元素
const input = document.querySelector('[type=search]')//css属性选择器
const ul = document.querySelector('.result-list')
// console.log(input)
// 2. 监听事件 获得焦点
input.addEventListener('focus', function () {
// ul显示
ul.style.display = 'block'
// 添加一个带有颜色边框的类名
input.classList.add('search')
})
// 3. 监听事件 失去焦点
input.addEventListener('blur', function () {
ul.style.display = 'none'
input.classList.remove('search')
})
</script>
const input = document.querySelector('input')
//键盘事件
input.addEventListener('keydown', function () {
console.log('键盘按下了')
})
input.addEventListener('keyup', function () {
console.log('键盘弹起了')
})
//用户输入文本事件 input
input.addEventListener('input', function () {
console.log(input.value)
})
4.事件对象及其位置
事件对象也是一个对象,在事件绑定的回调函数的第一个参数就是事件对象
事件对象中有很多属性
const input = document.querySelector('input')
input.addEventListener('keyup', function (e) {
if (e.key === 'Enter') {//key就是事件对象的一个属性,表示事件的按键输入为回车
console.log('我按下了回车键')
}
})
5事件对象中的常用属性
属性 | 描述 |
---|---|
type | 获取当前的事件类型 |
clientX/clientY | 获取光标相对于浏览器可见窗口左上角的位置 |
offsetX/offsetY | 获取光标相对于当前DOM元素左上角的位置 |
key | 用户按下的键盘键的值 现在不提倡使用keyCode |
6.trim()去除字符串左右的空格
<textarea name="" id="" cols="30" rows="10"></textarea>
<script>
const str = ' im a teacher '
// console.log(str.trim()) // 去除字符串左右的空格
const tx = document.querySelector('textarea')
tx.addEventListener('keyup', function (e) {
// console.log(tx.value)
if (e.key === 'Enter') {
// console.log(tx.value)
console.log(tx.value.trim() === '')
}
})
</script>
7.环境对象
环境对象this,谁调用,this就是谁
<button>点击</button>
<script>
// 每个函数里面都有this 环境对象 普通函数里面this指向的是window
// function fn() {
// console.log(this)
// }
// window.fn()
const btn = document.querySelector('button')
btn.addEventListener('click', function () {
// console.log(this) // btn 对象
// btn.style.color = 'red'
this.style.color = 'red'
})
</script>
8.回调函数
// 调用定时器,匿名函数做为参数
setInterval(function () {
console.log('我是回调函数...');
}, 1000);
结论:
- 回调函数本质还是函数,只不过把它当成参数使用
- 使用匿名函数做为回调函数比较常见
9.捕获和冒泡
<body>
<h3>事件流</h3>
<p>事件流是事件在执行时的底层机制,主要体现在父子盒子之间事件的执行上。</p>
<div class="outer">
<div class="inner">
<div class="child"></div>
</div>
</div>
<script>
// 获取嵌套的3个节点
const outer = document.querySelector('.outer');
const inner = document.querySelector('.inner');
const child = document.querySelector('.child');
// html 元素添加事件
document.documentElement.addEventListener('click', function () {
console.log('html...')
})
// body 元素添加事件
document.body.addEventListener('click', function () {
console.log('body...')
})
// 外层的盒子添加事件
outer.addEventListener('click', function () {
console.log('outer...')
})
// 中间的盒子添加事件
outer.addEventListener('click', function () {
console.log('inner...')
})
// 内层的盒子添加事件
outer.addEventListener('click', function () {
console.log('child...')
})
</script>
</body>
执行上述代码后发现,当单击事件触发时,其祖先元素的单击事件也【相继触发】,这是为什么呢?
结合事件流的特征,我们知道当某个元素的事件被触发时,事件总是会先经过其祖先才能到达当前元素,然后再由当前元素向祖先传递,事件在流动的过程中遇到相同的事件便会被触发。
再来关注一个细节就是事件相继触发的【执行顺序】,事件的执行顺序是可控制的,即可以在捕获阶段被执行,也可以在冒泡阶段被执行。
如果事件是在冒泡阶段执行的,我们称为冒泡模式,它会先执行子盒子事件再去执行父盒子事件,默认是冒泡模式。
如果事件是在捕获阶段执行的,我们称为捕获模式,它会先执行父盒子事件再去执行子盒子事件。
<body>
<h3>事件流</h3>
<p>事件流是事件在执行时的底层机制,主要体现在父子盒子之间事件的执行上。</p>
<div class="outer">
<div class="inner"></div>
</div>
<script>
// 获取嵌套的3个节点
const outer = document.querySelector('.outer')
const inner = document.querySelector('.inner')
// 外层的盒子
outer.addEventListener('click', function () {
console.log('outer...')
}, true) // true 表示在捕获阶段执行事件
// 中间的盒子
outer.addEventListener('click', function () {
console.log('inner...')
}, true)
</script>
</body>
结论:
addEventListener
第3个参数决定了事件是在捕获阶段触发还是在冒泡阶段触发addEventListener
第3个参数为true
表示捕获阶段触发,false
表示冒泡阶段触发,默认值为false
- 事件流只会在父子元素具有相同事件类型时才会产生影响
- 绝大部分场景都采用默认的冒泡模式(其中一个原因是早期 IE 不支持捕获)
10.阻止冒泡
阻止冒泡是指阻断事件的流动,保证事件只在当前元素被执行,而不再去影响到其对应的祖先元素。
<body>
<h3>阻止冒泡</h3>
<p>阻止冒泡是指阻断事件的流动,保证事件只在当前元素被执行,而不再去影响到其对应的祖先元素。</p>
<div class="outer">
<div class="inner">
<div class="child"></div>
</div>
</div>
<script>
// 获取嵌套的3个节点
const outer = document.querySelector('.outer')
const inner = document.querySelector('.inner')
const child = document.querySelector('.child')
// 外层的盒子
outer.addEventListener('click', function () {
console.log('outer...')
})
// 中间的盒子
inner.addEventListener('click', function (ev) {
console.log('inner...')
// 阻止事件冒泡
ev.stopPropagation()
})
// 内层的盒子
child.addEventListener('click', function (ev) {
console.log('child...')
// 借助事件对象,阻止事件向上冒泡
ev.stopPropagation()
})
</script>
</body>
结论:事件对象中的
ev.stopPropagation
方法,专门用来阻止事件冒泡。
鼠标经过事件:
mouseover 和 mouseout 会有冒泡效果
mouseenter 和 mouseleave 没有冒泡效果 (推荐)
三、事件委托
事件委托是利用事件流的特征解决一些现实开发需求的知识技巧,主要的作用是提升程序效率。
大量的事件监听是比较耗费性能的,如下代码所示
<script>
// 假设页面中有 10000 个 button 元素
const buttons = document.querySelectorAll('table button');
for(let i = 0; i <= buttons.length; i++) {
// 为 10000 个 button 元素添加了事件
buttons.addEventListener('click', function () {
// 省略具体执行逻辑...
})
}
</script>
利用事件流的特征,可以对上述的代码进行优化,事件的的冒泡模式总是会将事件流向其父元素的,如果父元素监听了相同的事件类型,那么父元素的事件就会被触发并执行,正是利用这一特征对上述代码进行优化,如下代码所示:
<script>
// 假设页面中有 10000 个 button 元素
let buttons = document.querySelectorAll('table button');
// 假设上述的 10000 个 buttom 元素共同的祖先元素是 table
let parents = document.querySelector('table');
parents.addEventListener('click', function () {
console.log('点击任意子元素都会触发事件...');
})
</script>
我们的最终目的是保证只有点击 button 子元素才去执行事件的回调函数,如何判断用户点击是哪一个子元素呢?
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DsPpE6qf-1683785897061)(assets\event.png)]
事件对象中的属性
target
或srcElement
属性表示真正触发事件的元素,它是一个元素类型的节点。
<script>
// 假设页面中有 10000 个 button 元素
const buttons = document.querySelectorAll('table button')
// 假设上述的 10000 个 buttom 元素共同的祖先元素是 table
const parents = document.querySelector('table')
parents.addEventListener('click', function (ev) {
// console.log(ev.target);
// 只有 button 元素才会真正去执行逻辑
if(ev.target.tagName === 'BUTTON') {
// 执行的逻辑
}
})
</script>
四、其他事件
1.页面加载事件
加载外部资源(如图片、外联CSS和JavaScript等)加载完毕时触发的事件
有些时候需要等页面资源全部处理完了做一些事情
事件名:load
监听页面所有资源加载完毕:
window.addEventListener('load', function() {
// xxxxx
})
2.元素滚动事件
滚动条在滚动的时候持续触发的事件
window.addEventListener('scroll', function() {
// xxxxx
})
3.页面尺寸事件
会在窗口尺寸改变的时候触发事件:
window.addEventListener('resize', function() {
// xxxxx
})
五、日期对象
掌握 Date 日期对象的使用,动态获取当前计算机的时间。
ECMAScript 中内置了获取系统时间的对象 Date,使用 Date 时与之前学习的内置对象 console 和 Math 不同,它需要借助 new 关键字才能使用。
1.实例化
// 1. 实例化
// const date = new Date(); // 系统默认时间
const date = new Date('2020-05-01') // 指定时间
// date 变量即所谓的时间对象
console.log(typeof date)
2.方法
// 1. 实例化
const date = new Date();
// 2. 调用时间对象方法
// 通过方法分别获取年、月、日,时、分、秒
const year = date.getFullYear(); // 四位年份
const month = date.getMonth(); // 0 ~ 11
getFullYear 获取四位年份
getMonth 获取月份,取值为 0 ~ 11
getDate 获取月份中的每一天,不同月份取值也不相同
getDay 获取星期,取值为 0 ~ 6
getHours 获取小时,取值为 0 ~ 23
getMinutes 获取分钟,取值为 0 ~ 59
getSeconds 获取秒,取值为 0 ~ 59
3.时间戳
时间戳是指1970年01月01日00时00分00秒起至现在的总秒数或毫秒数,它是一种特殊的计量时间的方式。
注:ECMAScript 中时间戳是以毫秒计的。
// 1. 实例化
const date = new Date()
// 2. 获取时间戳
console.log(date.getTime())
// 还有一种获取时间戳的方法
console.log(+new Date())
// 还有一种获取时间戳的方法
console.log(Date.now())
获取时间戳的方法,分别为 getTime 和 Date.now 和 +new Date()
六、DOM 节点
掌握元素节点创建、复制、插入、删除等操作的方法,能够依据元素节点的结构关系查找节点
回顾之前 DOM 的操作都是针对元素节点的属性或文本的,除此之外也有专门针对元素节点本身的操作,如插入、复制、删除、替换等。
1.插入节点
在已有的 DOM 节点中插入新的 DOM 节点时,需要关注两个关键因素:首先要得到新的 DOM 节点,其次在哪个位置插入这个节点。
如下代码演示:
<body>
<h3>插入节点</h3>
<p>在现有 dom 结构基础上插入新的元素节点</p>
<hr>
<!-- 普通盒子 -->
<div class="box"></div>
<!-- 点击按钮向 box 盒子插入节点 -->
<button class="btn">插入节点</button>
<script>
// 点击按钮,在网页中插入节点
const btn = document.querySelector('.btn')
btn.addEventListener('click', function () {
// 1. 获得一个 DOM 元素节点
const p = document.createElement('p')
p.innerText = '创建的新的p标签'
p.className = 'info'
// 复制原有的 DOM 节点
const p2 = document.querySelector('p').cloneNode(true)
p2.style.color = 'red'
// 2. 插入盒子 box 盒子
document.querySelector('.box').appendChild(p)
document.querySelector('.box').appendChild(p2)
})
</script>
</body>
结论:
-
createElement
动态创建任意 DOM 节点 -
cloneNode
复制现有的 DOM 节点,传入参数 true 会复制所有子节点 -
appendChild
在末尾(结束标签前)插入节点
再来看另一种情形的代码演示:
<body>
<h3>插入节点</h3>
<p>在现有 dom 结构基础上插入新的元素节点</p>
<hr>
<button class="btn1">在任意节点前插入</button>
<ul>
<li>HTML</li>
<li>CSS</li>
<li>JavaScript</li>
</ul>
<script>
// 点击按钮,在已有 DOM 中插入新节点
const btn1 = document.querySelector('.btn1')
btn1.addEventListener('click', function () {
// 第 2 个 li 元素
const relative = document.querySelector('li:nth-child(2)')
// 1. 动态创建新的节点
const li1 = document.createElement('li')
li1.style.color = 'red'
li1.innerText = 'Web APIs'
// 复制现有的节点
const li2 = document.querySelector('li:first-child').cloneNode(true)
li2.style.color = 'blue'
// 2. 在 relative 节点前插入
document.querySelector('ul').insertBefore(li1, relative)
document.querySelector('ul').insertBefore(li2, relative)
})
</script>
</body>
结论:
-
createElement
动态创建任意 DOM 节点 -
cloneNode
复制现有的 DOM 节点,传入参数 true 会复制所有子节点 -
insertBefore
在父节点中任意子节点之前插入新节点
2.删除节点
删除现有的 DOM 节点,也需要关注两个因素:首先由父节点删除子节点,其次是要删除哪个子节点。
<body>
<!-- 点击按钮删除节点 -->
<button>删除节点</button>
<ul>
<li>HTML</li>
<li>CSS</li>
<li>Web APIs</li>
</ul>
<script>
const btn = document.querySelector('button')
btn.addEventListener('click', function () {
// 获取 ul 父节点
let ul = document.querySelector('ul')
// 待删除的子节点
let lis = document.querySelectorAll('li')
// 删除节点
ul.removeChild(lis[0])
})
</script>
</body>
结论:removeChild
删除节点时一定是由父子关系。
3.查找节点
DOM 树中的任意节点都不是孤立存在的,它们要么是父子关系,要么是兄弟关系,不仅如此,我们可以依据节点之间的关系查找节点。
1.父子关系
<body>
<button class="btn1">所有的子节点</button>
<!-- 获取 ul 的子节点 -->
<ul>
<li>HTML</li>
<li>CSS</li>
<li>JavaScript 基础</li>
<li>Web APIs</li>
</ul>
<script>
const btn1 = document.querySelector('.btn1')
btn1.addEventListener('click', function () {
// 父节点
const ul = document.querySelector('ul')
// 所有的子节点
console.log(ul.childNodes)
// 只包含元素子节点
console.log(ul.children)
})
</script>
</body>
结论:
childNodes
获取全部的子节点,回车换行会被认为是空白文本节点children
只获取元素类型节点
<body>
<table>
<tr>
<td width="60">序号</td>
<td>课程名</td>
<td>难度</td>
<td width="80">操作</td>
</tr>
<tr>
<td>1</td>
<td><span>HTML</span></td>
<td>初级</td>
<td><button>变色</button></td>
</tr>
<tr>
<td>2</td>
<td><span>CSS</span></td>
<td>初级</td>
<td><button>变色</button></td>
</tr>
<tr>
<td>3</td>
<td><span>Web APIs</span></td>
<td>中级</td>
<td><button>变色</button></td>
</tr>
</table>
<script>
// 获取所有 button 节点,并添加事件监听
const buttons = document.querySelectorAll('table button')
for(let i = 0; i < buttons.length; i++) {
buttons[i].addEventListener('click', function () {
// console.log(this.parentNode); // 父节点 td
// console.log(this.parentNode.parentNode); // 爷爷节点 tr
this.parentNode.parentNode.style.color = 'red'
})
}
</script>
</body>
结论:parentNode
获取父节点,以相对位置查找节点,实际应用中非常灵活。
2.兄弟关系
<body>
<ul>
<li>HTML</li>
<li>CSS</li>
<li>JavaScript 基础</li>
<li>Web APIs</li>
</ul>
<script>
// 获取所有 li 节点
const lis = document.querySelectorAll('ul li')
// 对所有的 li 节点添加事件监听
for(let i = 0; i < lis.length; i++) {
lis[i].addEventListener('click', function () {
// 前一个节点
console.log(this.previousSibling)
// 下一下节点
console.log(this.nextSibling)
})
}
</script>
</body>
结论:
previousSibling
获取前一个节点,以相对位置查找节点,实际应用中非常灵活。nextSibling
获取后一个节点,以相对位置查找节点,实际应用中非常灵活。
Ⅱ、BOM
一、window对象
BOM (Browser Object Model ) 是浏览器对象模型
- window对象是一个全局对象,也可以说是JavaScript中的顶级对象
- 像document、alert()、console.log()这些都是window的属性,基本BOM的属性和方法都是window的
- 所有通过var定义在全局作用域中的变量、函数都会变成window对象的属性和方法
- window对象下的属性和方法调用的时候可以省略window
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uBVQLiRj-1683785897062)(assets/1676047436362.png)]
二、定时器-延迟函数
JavaScript 内置的一个用来让代码延迟执行的函数,叫 setTimeout
语法:
setTimeout(回调函数, 延迟时间)
setTimeout 仅仅只执行一次,所以可以理解为就是把一段代码延迟执行, 平时省略window
间歇函数 setInterval : 每隔一段时间就执行一次, , 平时省略window
清除延时函数:
clearTimeout(timerId)
注意点
- 延时函数需要等待,所以后面的代码先执行
- 返回值是一个正整数,表示定时器的编号
<body>
<script>
// 定时器之延迟函数
// 1. 开启延迟函数
let timerId = setTimeout(function () {
console.log('我只执行一次')
}, 3000)
// 1.1 延迟函数返回的还是一个正整数数字,表示延迟函数的编号
console.log(timerId)
// 1.2 延迟函数需要等待时间,所以下面的代码优先执行
// 2. 关闭延迟函数
clearTimeout(timerId)
</script>
</body>
三、location对象
location (地址) 它拆分并保存了 URL 地址的各个组成部分, 它是一个对象
属性/方法 | 说明 |
---|---|
href | 属性,获取完整的 URL 地址,赋值时用于地址的跳转 |
search | 属性,获取地址中携带的参数,符号 ?后面部分 |
hash | 属性,获取地址中的啥希值,符号 # 后面部分 |
reload() | 方法,用来刷新当前页面,传入参数 true 时表示强制刷新 |
<body>
<form>
<input type="text" name="search"> <button>搜索</button>
</form>
<a href="#/music">音乐</a>
<a href="#/download">下载</a>
<button class="reload">刷新页面</button>
<script>
// location 对象
// 1. href属性 (重点) 得到完整地址,赋值则是跳转到新地址
console.log(location.href)
// location.href = 'http://www.itcast.cn'
// 2. search属性 得到 ? 后面的地址
console.log(location.search) // ?search=笔记本
// 3. hash属性 得到 # 后面的地址
console.log(location.hash)
// 4. reload 方法 刷新页面
const btn = document.querySelector('.reload')
btn.addEventListener('click', function () {
// location.reload() // 页面刷新
location.reload(true) // 强制页面刷新 ctrl+f5
})
</script>
</body>
四、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://m.itcast.cn'
}})();
五、histroy对象
history (历史)是对象,主要管理历史记录, 该对象与浏览器地址栏的操作相对应,如前进、后退等
使用场景
history对象一般在实际开发中比较少用,但是会在一些OA 办公系统中见到。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qJJUdtBv-1683785897063)(D:/web前端/资料/web/web APIs第五天/04-笔记/assets/1676047834796.png)]
常见方法:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-O7QlMomD-1683785897063)(assets/1676047846593.png)]
<body>
<button class="back">←后退</button>
<button class="forward">前进→</button>
<script>
// histroy对象
// 1.前进
const forward = document.querySelector('.forward')
forward.addEventListener('click', function () {
// history.forward()
history.go(1)
})
// 2.后退
const back = document.querySelector('.back')
back.addEventListener('click', function () {
// history.back()
history.go(-1)
})
</script>
</body>
六、本地存储(重点)
本地存储:将数据存储在本地浏览器中
常见的使用场景:
https://todomvc.com/examples/vanilla-es6/ 页面刷新数据不丢失
好处:
1、页面刷新或者关闭不丢失数据,实现数据持久化
2、容量较大,sessionStorage和 localStorage 约 5M 左右
1.localStorage(重点)
作用: 数据可以长期保留在本地浏览器中,刷新页面和关闭页面,数据也不会丢失
**特性:**以键值对的形式存储,并且存储的是字符串, 省略了window
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-sMARsQoU-1683785897063)(assets/1676049635087.png)]
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>本地存储-localstorage</title>
</head>
<body>
<script>
// 本地存储 - localstorage 存储的是字符串
// 1. 存储
localStorage.setItem('age', 18)
// 2. 获取
console.log(typeof localStorage.getItem('age'))
// 3. 删除
localStorage.removeItem('age')
</script>
</body>
</html>
2.sessionStorage(了解)
特性:
- 用法跟localStorage基本相同
- 区别是:当页面浏览器被关闭时,存储在 sessionStorage 的数据会被清除
存储:sessionStorage.setItem(key,value)
获取:sessionStorage.getItem(key)
删除:sessionStorage.removeItem(key)
3.localStorage 存储复杂数据类型
**问题:**本地只能存储字符串,无法存储复杂数据类型.
**解决:**需要将复杂数据类型转换成 JSON字符串,在存储到本地
**语法:**JSON.stringify(复杂数据类型)
JSON字符串:
- 首先是1个字符串
- 属性名使用双引号引起来,不能单引号
- 属性值如果是字符串型也必须双引号
<body>
<script>
// 本地存储复杂数据类型
const goods = {
name: '小米',
price: 1999
}
// localStorage.setItem('goods', goods)
// console.log(localStorage.getItem('goods'))
// 1. 把对象转换为JSON字符串 JSON.stringify
localStorage.setItem('goods', JSON.stringify(goods))
// console.log(typeof localStorage.getItem('goods'))
</script>
</body>
**问题:**因为本地存储里面取出来的是字符串,不是对象,无法直接使用
**解决: **把取出来的字符串转换为对象
**语法:**JSON.parse(JSON字符串)
<body>
<script>
// 本地存储复杂数据类型
const goods = {
name: '小米',
price: 1999
}
// localStorage.setItem('goods', goods)
// console.log(localStorage.getItem('goods'))
// 1. 把对象转换为JSON字符串 JSON.stringify
localStorage.setItem('goods', JSON.stringify(goods))
// console.log(typeof localStorage.getItem('goods'))
// 2. 把JSON字符串转换为对象 JSON.parse
console.log(JSON.parse(localStorage.getItem('goods')))
</script>
</body>
七、综合案例
1.数组map 方法
使用场景:
map 可以遍历数组处理数据,并且返回新的数组
语法:
<body>
<script>
const arr = ['red', 'blue', 'pink']
// 1. 数组 map方法 处理数据并且 返回一个数组
const newArr = arr.map(function (ele, index) {
// console.log(ele) // 数组元素
// console.log(index) // 索引号
return ele + '颜色'
})
console.log(newArr)
</script>
</body>
map 也称为映射。映射是个术语,指两个元素的集之间元素相互“对应”的关系。
map重点在于有返回值,forEach没有返回值(undefined)
2.数组join方法
**作用:**join() 方法用于把数组中的所有元素转换一个字符串
语法:
<body>
<script>
const arr = ['red', 'blue', 'pink']
// 1. 数组 map方法 处理数据并且 返回一个数组
const newArr = arr.map(function (ele, index) {
// console.log(ele) // 数组元素
// console.log(index) // 索引号
return ele + '颜色'
})
console.log(newArr)
// 2. 数组join方法 把数组转换为字符串
// 小括号为空则逗号分割
console.log(newArr.join()) // red颜色,blue颜色,pink颜色
// 小括号是空字符串,则元素之间没有分隔符
console.log(newArr.join('')) //red颜色blue颜色pink颜色
console.log(newArr.join('|')) //red颜色|blue颜色|pink颜色
</script>
</body>
Ⅲ、正则表达式
正则表达式(Regular Expression)是一种字符串匹配的模式(规则)
使用场景:
- 例如验证表单:手机号表单要求用户只能输入11位的数字 (匹配)
- 过滤掉页面内容中的一些敏感词(替换),或从字符串中获取我们想要的特定部分(提取)等
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-63yM8vSj-1683785897064)(assets/1676079666366.png)]
一、正则基本使用
-
定义规则
const reg = /表达式/
- 其中
/ /
是正则表达式字面量 - 正则表达式也是
对象
- 其中
-
使用正则
test()方法
用来查看正则表达式与指定的字符串是否匹配- 如果正则表达式与指定的字符串匹配 ,返回
true
,否则false
<body>
<script>
// 正则表达式的基本使用
const str = 'web前端开发'
// 1. 定义规则
const reg = /web/
// 2. 使用正则 test()
console.log(reg.test(str)) // true 如果符合规则匹配上则返回true
console.log(reg.test('java开发')) // false 如果不符合规则匹配上则返回 false
</script>
</body>
二、元字符
- 普通字符:
- 大多数的字符仅能够描述它们本身,这些字符称作普通字符,例如所有的字母和数字。
- 普通字符只能够匹配字符串中与它们相同的字符。
- 比如,规定用户只能输入英文26个英文字母,普通字符的话 /[abcdefghijklmnopqrstuvwxyz]/
- 元字符(特殊字符)
- 是一些具有特殊含义的字符,可以极大提高了灵活性和强大的匹配功能。
- 比如,规定用户只能输入英文26个英文字母,换成元字符写法: /[a-z]/
1.边界符
正则表达式中的边界符(位置符)用来提示字符所处的位置,主要有两个字符
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Kynswx9e-1683785897064)(assets/1676080081650.png)]
如果 ^ 和 $ 在一起,表示必须是精确匹配
<body>
<script>
// 元字符之边界符
// 1. 匹配开头的位置 ^
const reg = /^web/
console.log(reg.test('web前端')) // true
console.log(reg.test('前端web')) // false
console.log(reg.test('前端web学习')) // false
console.log(reg.test('we')) // false
// 2. 匹配结束的位置 $
const reg1 = /web$/
console.log(reg1.test('web前端')) // false
console.log(reg1.test('前端web')) // true
console.log(reg1.test('前端web学习')) // false
console.log(reg1.test('we')) // false
// 3. 精确匹配 ^ $
const reg2 = /^web$/
console.log(reg2.test('web前端')) // false
console.log(reg2.test('前端web')) // false
console.log(reg2.test('前端web学习')) // false
console.log(reg2.test('we')) // false
console.log(reg2.test('web')) // true
console.log(reg2.test('webweb')) // flase
</script>
</body>
2.量词
量词用来设定某个模式重复次数
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-f7RA72uj-1683785897064)(assets/1676080185383.png)]
注意: 逗号左右两侧千万不要出现空格
<body>
<script>
// 元字符之量词
// 1. * 重复次数 >= 0 次
const reg1 = /^w*$/
console.log(reg1.test('')) // true
console.log(reg1.test('w')) // true
console.log(reg1.test('ww')) // true
console.log('-----------------------')
// 2. + 重复次数 >= 1 次
const reg2 = /^w+$/
console.log(reg2.test('')) // false
console.log(reg2.test('w')) // true
console.log(reg2.test('ww')) // true
console.log('-----------------------')
// 3. ? 重复次数 0 || 1
const reg3 = /^w?$/
console.log(reg3.test('')) // true
console.log(reg3.test('w')) // true
console.log(reg3.test('ww')) // false
console.log('-----------------------')
// 4. {n} 重复 n 次
const reg4 = /^w{3}$/
console.log(reg4.test('')) // false
console.log(reg4.test('w')) // flase
console.log(reg4.test('ww')) // false
console.log(reg4.test('www')) // true
console.log(reg4.test('wwww')) // false
console.log('-----------------------')
// 5. {n,} 重复次数 >= n
const reg5 = /^w{2,}$/
console.log(reg5.test('')) // false
console.log(reg5.test('w')) // false
console.log(reg5.test('ww')) // true
console.log(reg5.test('www')) // true
console.log('-----------------------')
// 6. {n,m} n =< 重复次数 <= m
const reg6 = /^w{2,4}$/
console.log(reg6.test('w')) // false
console.log(reg6.test('ww')) // true
console.log(reg6.test('www')) // true
console.log(reg6.test('wwww')) // true
console.log(reg6.test('wwwww')) // false
// 7. 注意事项: 逗号两侧千万不要加空格否则会匹配失败
</script>
3.范围
表示字符的范围,定义的规则限定在某个范围,比如只能是英文字母,或者数字等等,用表示范围
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-b2Pz5eCI-1683785897065)(assets/1676080296168.png)]
<body>
<script>
// 元字符之范围 []
// 1. [abc] 匹配包含的单个字符, 多选1
const reg1 = /^[abc]$/
console.log(reg1.test('a')) // true
console.log(reg1.test('b')) // true
console.log(reg1.test('c')) // true
console.log(reg1.test('d')) // false
console.log(reg1.test('ab')) // false
// 2. [a-z] 连字符 单个
const reg2 = /^[a-z]$/
console.log(reg2.test('a')) // true
console.log(reg2.test('p')) // true
console.log(reg2.test('0')) // false
console.log(reg2.test('A')) // false
// 想要包含小写字母,大写字母 ,数字
const reg3 = /^[a-zA-Z0-9]$/
console.log(reg3.test('B')) // true
console.log(reg3.test('b')) // true
console.log(reg3.test(9)) // true
console.log(reg3.test(',')) // flase
// 用户名可以输入英文字母,数字,可以加下划线,要求 6~16位
const reg4 = /^[a-zA-Z0-9_]{6,16}$/
console.log(reg4.test('abcd1')) // false
console.log(reg4.test('abcd12')) // true
console.log(reg4.test('ABcd12')) // true
console.log(reg4.test('ABcd12_')) // true
// 3. [^a-z] 取反符
const reg5 = /^[^a-z]$/
console.log(reg5.test('a')) // false
console.log(reg5.test('A')) // true
console.log(reg5.test(8)) // true
</script>
</body>
4.字符类
某些常见模式的简写方式,区分字母和数字
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ztY1kdcQ-1683785897065)(assets/1676080353637.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7QqOp57u-1683785897065)(assets/1676080372325.png)]
三、替换和修饰符
replace 替换方法,可以完成字符的替换
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wviixYXn-1683785897066)(assets/1676080437160.png)]
<body>
<script>
// 替换和修饰符
const str = '欢迎大家学习前端,相信大家一定能学好前端,都成为前端大神'
// 1. 替换 replace 需求:把前端替换为 web
// 1.1 replace 返回值是替换完毕的字符串
// const strEnd = str.replace(/前端/, 'web') 只能替换一个
</script>
</body>
修饰符约束正则执行的某些细节行为,如是否区分大小写、是否支持多行匹配等
- i 是单词 ignore 的缩写,正则匹配时字母不区分大小写
- g 是单词 global 的缩写,匹配所有满足正则表达式的结果
<body>
<script>
// 替换和修饰符
const str = '欢迎大家学习前端,相信大家一定能学好前端,都成为前端大神'
// 1. 替换 replace 需求:把前端替换为 web
// 1.1 replace 返回值是替换完毕的字符串
// const strEnd = str.replace(/前端/, 'web') 只能替换一个
// 2. 修饰符 g 全部替换
const strEnd = str.replace(/前端/g, 'web')
console.log(strEnd)
</script>
</body>
1.change 事件
给input注册 change 事件,值被修改并且失去焦点后触发
2.判断是否有类
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-U8xhAF4C-1683785897066)(assets\1676080618794.png)]
元素.classList.contains() 看看有没有包含某个类,如果有则返回true,么有则返回false
= /1{6,16}$/
console.log(reg4.test(‘abcd1’)) // false
console.log(reg4.test(‘abcd12’)) // true
console.log(reg4.test(‘ABcd12’)) // true
console.log(reg4.test(‘ABcd12_’)) // true
// 3. [^a-z] 取反符
const reg5 = /^[^a-z]$/
console.log(reg5.test('a')) // false
console.log(reg5.test('A')) // true
console.log(reg5.test(8)) // true
~~~
4.字符类
某些常见模式的简写方式,区分字母和数字
[外链图片转存中…(img-ztY1kdcQ-1683785897065)]
[外链图片转存中…(img-7QqOp57u-1683785897065)]
三、替换和修饰符
replace 替换方法,可以完成字符的替换
[外链图片转存中…(img-wviixYXn-1683785897066)]
<body>
<script>
// 替换和修饰符
const str = '欢迎大家学习前端,相信大家一定能学好前端,都成为前端大神'
// 1. 替换 replace 需求:把前端替换为 web
// 1.1 replace 返回值是替换完毕的字符串
// const strEnd = str.replace(/前端/, 'web') 只能替换一个
</script>
</body>
修饰符约束正则执行的某些细节行为,如是否区分大小写、是否支持多行匹配等
- i 是单词 ignore 的缩写,正则匹配时字母不区分大小写
- g 是单词 global 的缩写,匹配所有满足正则表达式的结果
<body>
<script>
// 替换和修饰符
const str = '欢迎大家学习前端,相信大家一定能学好前端,都成为前端大神'
// 1. 替换 replace 需求:把前端替换为 web
// 1.1 replace 返回值是替换完毕的字符串
// const strEnd = str.replace(/前端/, 'web') 只能替换一个
// 2. 修饰符 g 全部替换
const strEnd = str.replace(/前端/g, 'web')
console.log(strEnd)
</script>
</body>
1.change 事件
给input注册 change 事件,值被修改并且失去焦点后触发
2.判断是否有类
[外链图片转存中…(img-U8xhAF4C-1683785897066)]
元素.classList.contains() 看看有没有包含某个类,如果有则返回true,么有则返回false
a-zA-Z0-9_ ↩︎