基础介绍
书写位置
基本语法
函数使用
匿名函数--函数表达式
匿名函数--立即执行
立即执行函数的特点:立即执行,避免代码污染
再解释一下立即执行函数方式1,为什么可以这样写
(function(){ })();
前面一个括号里写的是一个具体的函数,{}里写的是函数的内容
而最后那个括号实际上是对函数的调用
值得一提的是,立即执行函数间需要加; 否则可能出现混乱
对象
对象是什么
有点像不用实例化的结构体
访问里面的元素有两种写法。
但如果是“字符串”的话就只能用第二种
对象使用
注意!k是字符串
DOM
基础介绍
根据CSS选择器来获取DOM元素
当然了,还有别的方法
通过DOM修改元素内容
<body>
<div>
<h1>一等奖:<span id="first">???</span></h1>
<h2>二等奖:<span id="second">???</span></h2>
<h3>三等奖:<span id="third">???</span></h3>
</div>
<script>
const person = ['刘德华', '张学友', '黎明']
for (let i = 0; i < person.length; i++) {
if (i == 0) {
const fi = document.querySelector('#first')
fi.innerHTML = person[i]
}
else if (i == 1) {
const se = document.querySelector('#second')
se.innerHTML = person[i]
}
else {
const th = document.querySelector('#third')
th.innerHTML = person[i]
}
}
</script>
</body>
通过DOM操作元素属性和类(style,class)
例如,想要标签div的样式变成box里的一样,如果用上一种方式就要写很多行代码。
那我们可以把想要样式封装到一个css类里面(box),然后再让div的类等于box即可。
这样的话就不用写<div class = ""box>
再按f12到网页源代码里看,div的css类就是box
但className是用新值“覆盖”旧值,如果想保留原来的css类就这么写
这个是最常用的,比className好用
补充:setInterval
函数
setInterval
是 JavaScript 中用来周期性地执行代码的方法。它接受两个参数:一个是要周期执行的函数,另一个是执行的时间间隔(以毫秒为单位)。基本语法:
setInterval(callback, delay);
callback
是一个函数,它将周期性地被调用。delay
是以毫秒为单位的时间间隔,表示每隔多少时间调用一次callback
函数。示例:
function sayHello() { console.log('Hello, world!'); } // 每隔 2 秒执行一次 sayHello 函数 setInterval(sayHello, 2000);
在这个例子中,
sayHello
函数会每隔 2 秒输出一次'Hello, world!'
。停止执行:
如果想要停止
setInterval
执行,可以使用clearInterval
方法,并传入setInterval
返回的定时器 ID。let intervalId = setInterval(sayHello, 2000); // 5 秒后停止执行 setInterval setTimeout(() => { clearInterval(intervalId); console.log('Interval stopped.'); }, 5000);
在这个例子中,
clearInterval(intervalId)
会停止之前设定的setInterval
。注意事项:
setInterval
不会等待上一次callback
函数执行完毕,如果执行时间超过delay
,则会导致多个callback
函数同时执行。因此,在callback
函数内部,如果需要确保一次执行完成后再执行下一次,请谨慎处理。- 尽量避免使用过短的时间间隔,因为过于频繁的函数调用可能会影响性能。
使用
setInterval
可以实现很多周期性执行的需求,比如定时更新页面内容、轮播图片等。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div>
<textarea name="t" id="">用户规则</textarea>
<button class="bth" disabled>我已阅读用户协议</button>
</div>
<script>
const bth = document.querySelector('.bth')
let i = 5
let n = setInterval(function () {
i--
bth.innerHTML = `我已阅读用户协议(${i})`
if (i == 0) {
clearInterval(n)
bth.disable = false
bth.innerHTML = '同意'
}
}, 1000)
</script>
</body>
</html>
事件的使用
事件监听
<!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>
</style>
</head>
<body>
<div>
<span>你抽到的是:</span>
<div class="qs"></div>
<div>
<button class="begin">开始</button>
<button class="end">结束</button>
</div>
</div>
<script>
let arr = ["关羽", "刘备", "张飞"]
const begin = document.querySelector('.begin')
const end = document.querySelector('.end')
const qs = document.querySelector('.qs')
let random = 0
begin.addEventListener('click', function () {
timerId = setInterval(function () {
random = parseInt(Math.random() * arr.length)
qs.innerHTML = arr[random]
}, 35)
if (arr.length == 1) {
begin.disabled = true
end.disabled = true
}
})
end.addEventListener('click', function () {
clearInterval(timerId)
arr.splice(random, 1)
})
</script>
</body>
</html>
事件类型
焦点指的是鼠标的光标
<body>
<input type="text">
<script>
let input = document.querySelector('input')
input.addEventListener('focus', function () {
console.log('焦点触发')
})
input.addEventListener('blur', function () {
console.log('焦点消失')
})
</script>
</body>
<body>
<input type="text">
<script>
let input = document.querySelector('input')
input.addEventListener('keydown', function () {
console.log('键盘按下了')
})
input.addEventListener('keyup', function () {
console.log('键盘弹起了')
})
</script>
</body>
<body>
<input type="text">
<script>
let input = document.querySelector('input')
input.addEventListener('input', function () {
console.log(input.value)
})
</script>
</body>
评论案例
<!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>
input {
width: 200px;
transition: all .3s;
}
input:focus {
width: 300px;
}
.total {
opacity: 0;
}
</style>
</head>
<body>
<div>
<textarea name="" id="tx" placeholder="请输入一条友善的评论"></textarea>
<div>
<span class="total">0/200字</span>
</div>
</div>
<script>
let total = document.querySelector('.total')
let tx = document.querySelector('#tx')
tx.addEventListener('focus', function () {
total.style.opacity = 1
})
tx.addEventListener('blur', function () {
total.style.opacity = 0
})
tx.addEventListener('input', function () {
total.innerHTML = `${tx.value.length}/200字`
})
</script>
</body>
</html>
事件对象
什么是事件对象
事件对象,存的是时间触发时的相关信息
在 JavaScript 中,事件对象是一个特殊的对象,它包含了与特定事件相关的信息,比如事件的类型、目标元素、事件触发时鼠标或键盘的状态等。事件对象通常在事件处理函数中自动传递给该函数,使得函数可以访问这些信息。
以下是事件对象的一些常见属性和方法:
type
:事件的类型,比如"click"
、"mouseover"
等。
target
或srcElement
:触发事件的元素。在 DOM 级别 0 中使用srcElement
,而在 DOM 级别 2 和现代浏览器中使用target
。
currentTarget
:事件监听器绑定的元素,与target
不同,currentTarget
是事件处理函数实际上附着的那个元素。
eventPhase
:事件当前所处的阶段(捕获或冒泡)。
bubbles
:一个布尔值,表示事件是否冒泡。
cancelable
:一个布尔值,表示事件是否可以被取消。
defaultPrevented
:如果事件的默认行为已经被取消,则为true
。
isTrusted
:如果事件是用户操作生成的,则为true
。
timeStamp
:事件被创建时的时间戳。
preventDefault()
:调用此方法可以取消事件的默认行为。
stopPropagation()
:调用此方法可以阻止事件继续传播到其他元素。
stopImmediatePropagation()
:调用此方法不仅阻止事件传播,还会阻止在同一元素上注册的其他事件监听器被调用。事件对象的使用示例:
element.addEventListener('click', function(event) { console.log(event.type); // "click" console.log(event.target); // 点击的元素 event.preventDefault(); // 阻止默认行为 event.stopPropagation(); // 阻止事件冒泡 });
在事件处理函数中,
event
参数通常被命名为event
,但你也可以使用其他任何有效的变量名。这个参数包含了所有与事件相关的信息,允许你在函数内部访问这些信息。复制再试一次分享
获取事件对象属性
<body>
<input type="text">
<script>
let input = document.querySelector('input')
input.addEventListener('keydown', function (event) {
console.log(event)
})
</script>
</body>
例如,我此时按下了s和回车键,打印出来的信息可以看到都被记录在事件对象里了
环境对象this
<body>
<button>按钮</button>
<script>
function fn() {
console.log(this)
}
fn()//其实是windows.fn()
let btn = document.querySelector('button')
btn.addEventListener('click', function () {
console.log(this)
})
</script>
</body>
回调函数
案例巩固
水果案例
<!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>
.active {
background: gainsboro;
}
</style>
</head>
<body>
<div class="table">
<div class="table_head">
<h3>今日特价</h3>
<ul>
<li><a href="javascript:void(0);" class="active">苹果</a></li>
<li><a href="javascript:void(0);">香蕉</a></li>
<li><a href="javascript:void(0);">梨</a></li>
<li><a href="javascript:void(0);">火龙果</a></li>
</ul>
</div>
<div class="table_content">
<div class="item"><img src="./apple.jpg" alt="苹果"></div>
<div class="item" style="display: none;"><img src="./banana.jpg" alt="香蕉"></div>
<div class="item" style="display: none;"><img src="./pear.jpg" alt="梨"></div>
<div class="item" style="display: none;"><img src="./dragon_fruit.jpg" alt="火龙果"></div>
</div>
</div>
<script>
let head = document.querySelectorAll('.table_head a');
let content = document.querySelectorAll('.table_content .item');
for (let i = 0; i < head.length; i++) {
head[i].addEventListener('mouseenter', function () {
// 移除所有链接的 'active' 类
head.forEach(h => h.classList.remove('active'));
this.classList.add('active');
// 隐藏所有内容
content.forEach(c => c.style.display = 'none');
// 显示对应的内容区
content[i].style.display = 'block';
});
}
</script>
</body>
</html>
全选文本框案例
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div>
<div><input type="checkbox" class="checkAll">全选</div>
<div><input type="checkbox" class="option">苹果</div>
<div><input type="checkbox" class="option">香蕉</div>
<div><input type="checkbox" class="option">梨</div>
</div>
<script>
let checkAll = document.querySelector('.checkAll')
let option = document.querySelectorAll('.option')
checkAll.addEventListener('click', function () {
option.forEach(c => {
c.checked = checkAll.checked
});
})
for (let i = 0; i < option.length; i++) {
option[i].addEventListener('click', function () {
let cnt = document.querySelectorAll('.option:checked').length
if (cnt == option.length) {
checkAll.checked = true
}
})
}
</script>
</body>
</html>
事件流
事件捕获
事件捕获很少用到
事件冒泡
<!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>
.father {
width: 400px;
height: 400px;
background-color: red;
}
.son {
width: 200px;
height: 200px;
background-color: blue;
}
</style>
</head>
<body>
<div class="father">
<div class="son"></div>
</div>
<script>
let father = document.querySelector('.father')
let son = document.querySelector('.son')
document.addEventListener('click', function () {
alert('祖宗')
})
father.addEventListener('click', function () {
alert('父亲')
})
son.addEventListener('click', function () {
alert('儿子')
})
</script>
</body>
</html>
举个例子。
如果只点击空白,则显示祖宗
点击红色,显示父亲->祖宗
点击蓝色,显示儿子->父亲->祖宗
一层一层由低到高,这就是事件冒泡
阻止冒泡
组织冒泡只要加上以上代码就行。
那么此时点蓝色,只会显示儿子
<!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>
.father {
width: 400px;
height: 400px;
background-color: red;
}
.son {
width: 200px;
height: 200px;
background-color: blue;
}
</style>
</head>
<body>
<div class="father">
<div class="son"></div>
</div>
<script>
let father = document.querySelector('.father')
let son = document.querySelector('.son')
document.addEventListener('click', function () {
alert('祖宗')
})
father.addEventListener('click', function () {
alert('父亲')
})
son.addEventListener('click', function (e) {
e.stopPropagation();
alert('儿子')
})
</script>
</body>
</html>
解绑事件
上面这个方法比较原始。因为绑定事件一般用监听器
事件委托
利用了事件冒泡的特性
比如说有一个表格ul,里面有很多个li,那么我们想实现触发li的时候出现某种效果。如果给每个li都添加监听器就太麻烦了。鉴于这些li的父元素是ul,触发子元素的时候会冒泡到父元素身上,那么只需要对父元素添加监听器来统一管理即可。
<!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>
</style>
</head>
<body>
<ul>
<li>第1个子元素</li>
<li>第2个子元素</li>
<li>第3个子元素</li>
<li>第4个子元素</li>
<li>第5个子元素</li>
<p>这是一个p</p>
</ul>
<script>
let ul = document.querySelector('ul')
ul.addEventListener('click', function (e) {
if (e.target.tagName === 'LI') {
e.target.style.color = 'red'
}
})
</script>
</body>
</html>
阻止冒泡(阻止默认行为)
页面加载事件
页面滚动事件
<!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>
body {
height: 1000px;
}
div {
display: none;
width: 300px;
height: 300px;
background-color: red;
}
</style>
</head>
<body>
<div></div>
<script>
let div = document.querySelector('div')
document.documentElement.scrollTop = 80
//可赋值
window.addEventListener('scroll', function () {
let n = document.documentElement.scrollTop
if (n >= 50) {
div.style.display = 'block'
} else {
div.style.display = 'none'
}
})
</script>
</body>
</html>
页面尺寸事件
<!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>
.line {
background: red;
height: 2px;
width: 10px;
position: absolute;
top: 0;
left: 0;
transition: transform 0.3s ease;
}
.table {
position: relative;
}
.list {
display: flex;
}
.list a {
padding: 10px;
margin-right: 10px;
text-decoration: none;
color: black;
}
</style>
</head>
<body>
<div class="table">
<div class="list">
<a href="#">1</a>
<a href="#">2</a>
<a href="#">3</a>
<a href="#">4</a>
<a href="#">5</a>
</div>
<div class="line"></div>
</div>
<script>
let tab = document.querySelector('.list'); // 修正选择器为 .list
let line = document.querySelector('.line');
tab.addEventListener('click', function (e) {
if (e.target.tagName === 'A') {
let offsetLeft = e.target.offsetLeft; // 获取点击元素相对于其父元素 .list 的左偏移量
let tableOffsetLeft = tab.offsetLeft; // 获取 .list 相对于其父元素 .table 的左偏移量
line.style.transform = `translateX(${offsetLeft + tableOffsetLeft}px)`; // 计算实际的 transform 值
}
});
</script>
</body>
</html>
日期对象
<body>
<div></div>
<script>
let div = document.querySelector('div')
setInterval(function () {
let date = new Date()
div.innerHTML = date
}, 1000)
</script>
</body>
<!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>
</style>
</head>
<body>
<div id="goal"></div>
<div id="count"></div>
<script>
let s = '2024-8-7 12:05:00'
function getCount() {
let goal = document.querySelector('#goal')
let count = document.querySelector('#count')
goal.innerHTML = '距离' + s + '还有'
let cur = +new Date()
let future = new Date(s)
let span = future - cur
span /= 1000
let hour = parseInt(span / 60 / 60 % 24)
hour = hour < 10 ? '0' + hour : hour
let min = parseInt(span / 60 % 60)
min = min < 10 ? '0' + min : min
let second = parseInt(span % 60)
if (second < 0) hour = '00', min = '00', second = '0'
second = second < 10 ? '0' + second : second
count.innerHTML = hour + ':' + min + ':' + second
}
getCount()
setInterval(getCount, 1000)
</script>
</body>
</html>
节点
查找节点
注意,一个节点可以有多个子节点,但只有一个父节点。
所以父节点查找只返回一个元素,而子节点查找是返回一个伪数组
增加节点
<body>
<ul></ul>
<script>
let p1 = document.createElement('li')
p1.innerHTML = '第一个'
let p2 = document.createElement('li')
p2.innerHTML = '第二个'
let ul = document.querySelector('ul')
ul.appendChild(p1)
ul.append(p2, ul.children[0])
</script>
</body>
如果这里的克隆填false,那么li里面的内容“1”就不会被克隆过来
删除节点
补充了解
所以bom是比dom大的
js同步和异步
输出结果都是132,为什么呢?
Window对象
location对象
网页直接跳转到百度
经常用href 利用js的方法去跳转页面
<body>
<script>
location.href = 'http://www.baidu.com'
</script>
</body>
<!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>
</style>
</head>
<body>
<form action="">
<input type="text" name="username" placeholder="请输入用户名"><br>
<input type="password" name="pwd" placeholder="请输入密码"><br>
<button type="submit">提交</button>
</form>
<script>
console.log(location.search)
</script>
</body>
</html>
<!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>
</style>
</head>
<body>
<a href="#/my">我的</a>
<a href="#/follow">关注</a>
<a href="#/download">下载</a>
<script>
window.addEventListener('click', function () {
console.log(location.hash)
})
</script>
</body>
</html>
navigator对象
history对象
本地存储localStorage
之前写的页面,点一下刷新页面就会全部刷新,之前在这个页面填写的信息全没了。为了解决这个问题,学习本地存储。
<body>
<script>
//增。本地存储只能存字符串类型!这个很重要!
localStorage.setItem('name', 'lmm')
//查
console.log(localStorage.getItem('name'))
//改。如果该键已经有值,再setItem就是改了
localStorage.setItem('name', 'lpp')
//删
localStorage.removeItem('name')
</script>
</body>
如果不用remove的情况下,再运行同样的网页,键值也不会消失,会存在用户的电脑中
下面这个先作为了解,用法和localstorage基本一样
上面那种是一个元素一个元素存,是存储简单数据类型。
如果想存像结构体那样的信息,就是存复杂数据类型。
<body>
<script>
//这是复杂数据类型
const obj = {
name: 'lmm',
age: '21'
}
localStorage.setItem('obj', obj)
console.log(localStorage.getItem('obj'))
</script>
</body>
如果直接这样存,就看不到obj里面存的是什么了,因为存储的信息会被 转换成字符串
因此需要数据类型转换
取出的时候不能直接取出,因为直接取出的是字符串,应该要转换成对象才能使用
正确写法
<body>
<script>
//这是复杂数据类型
const obj = {
name: 'lmm',
age: '21'
}
//存入的时候转换成复杂数据类型
localStorage.setItem('obj', JSON.stringify(obj))
//取出的时候转换成对象
console.log(JSON.parse(localStorage.getItem('obj')))
</script>
</body>
map和join方法
map方法
map重点在于有返回值,会返回一个数组!!!
<body>
<script>
let arr = ['红', '蓝', '绿']
const newArr = arr.map(function (ele, index) {
return ele + '色'
})
console.log(newArr)
</script>
</body>
join方法
map+join渲染页面
<!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>
</style>
</head>
<body>
<table>
<tbody>
</tbody>
</table>
<script>
const initData = [{
stuId: 1,
uname: '迪丽热巴',
age: 22,
gender: '女',
salary: '12000',
city: '北京',
time: '2099-09-09 08:08:08'
}];
// 确保在浏览器控制台中运行这段代码之前已经执行了下面的代码
// localStorage.setItem('data', JSON.stringify(initData));
const arr = JSON.parse(localStorage.getItem('data'));
const tbody = document.querySelector('tbody');
function render() {
const trArr = arr.map(function (ele) {
return `
<tr>
<td>${ele.stuId}</td>
<td>${ele.uname}</td>
<td>${ele.age}</td>
<td>${ele.gender}</td>
<td>${ele.salary}</td>
<td>${ele.city}</td>
<td>${ele.time}</td>
<td>
<a href="javascript:">
<i class="iconfont icon-shanchu"></i> 删除
</a>
</td>
</tr>
`;
});
tbody.innerHTML = trArr.join('');
}
render();
</script>
</body>
</html>
学生就业统计表案例
<!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>
/* 添加样式 */
</style>
</head>
<body>
<form class="info" action="">
<input type="text" class="uname" placeholder="请输入姓名">
<input type="text" class="age" placeholder="请输入年龄">
<input type="text" class="salary" placeholder="请输入薪资">
<select class="gender" name="gender">
<option value="男">男</option>
<option value="女">女</option>
</select>
<select class="city" name="city">
<option value="北京">北京</option>
<option value="上海">上海</option>
<option value="广州">广州</option>
<option value="深圳">深圳</option>
</select>
<button type="submit">添加</button>
</form>
<table>
<tbody>
<!-- 数据行将被渲染在这里 -->
</tbody>
</table>
<script>
const initData = [{
stuId: 1,
uname: '迪丽热巴',
age: 22,
gender: '女',
salary: '12000',
city: '北京',
time: '2099-09-09 08:08:08'
}];
const tbody = document.querySelector('tbody');
//如果没有数据,用空数组来代替
let arr = JSON.parse(localStorage.getItem('data')) || []
function render() {
const trArr = arr.map(ele => `
<tr>
<td>${ele.stuId}</td>
<td>${ele.uname}</td>
<td>${ele.age}</td>
<td>${ele.gender}</td>
<td>${ele.salary}</td>
<td>${ele.city}</td>
<td>${ele.time}</td>
<td>
<a href="javascript:">
<i class="iconfont icon-shanchu"></i> 删除
</a>
</td>
</tr>
`);
tbody.innerHTML = trArr.join('');
}
render();
const info = document.querySelector('.info');
const uname = document.querySelector('.uname');
const age = document.querySelector('.age');
const salary = document.querySelector('.salary');
const gender = document.querySelector('.gender');
const city = document.querySelector('.city');
info.addEventListener('submit', function (e) {
e.preventDefault(); // 防止表单提交的默认行为
if (!uname.value || !age.value || !salary.value) {
return alert('输入内容不能为空');
}
// 生成新的 stuId
const newStuId = arr.length ? arr[arr.length - 1].stuId + 1 : 1;
// 处理表单数据
arr.push({
stuId: newStuId,
uname: uname.value,
age: age.value,
gender: gender.value,
salary: salary.value,
city: city.value,
time: new Date().toLocaleString() // 调用方法
});
// 更新 localStorage
localStorage.setItem('data', JSON.stringify(arr));
// 渲染页面
render();
// 重置表单
this.reset();
});
</script>
</body>
</html>
<!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>
/* 添加样式 */
</style>
</head>
<body>
<form class="info" action="">
<input type="text" class="uname" placeholder="请输入姓名">
<input type="text" class="age" placeholder="请输入年龄">
<input type="text" class="salary" placeholder="请输入薪资">
<select class="gender" name="gender">
<option value="男">男</option>
<option value="女">女</option>
</select>
<select class="city" name="city">
<option value="北京">北京</option>
<option value="上海">上海</option>
<option value="广州">广州</option>
<option value="深圳">深圳</option>
</select>
<button type="submit">添加</button>
</form>
<table>
<tbody>
<!-- 数据行将被渲染在这里 -->
</tbody>
</table>
<script>
const initData = [{
stuId: 1,
uname: '迪丽热巴',
age: 22,
gender: '女',
salary: '12000',
city: '北京',
time: '2099-09-09 08:08:08'
}];
const tbody = document.querySelector('tbody');
//如果没有数据,用空数组来代替
let arr = JSON.parse(localStorage.getItem('data')) || initData;
function render() {
const trArr = arr.map(ele => `
<tr data-id="${ele.stuId}">
<td>${ele.stuId}</td>
<td>${ele.uname}</td>
<td>${ele.age}</td>
<td>${ele.gender}</td>
<td>${ele.salary}</td>
<td>${ele.city}</td>
<td>${ele.time}</td>
<td>
<a href="javascript:" class="delete-btn">
<i class="iconfont icon-shanchu"></i> 删除
</a>
</td>
</tr>
`);
tbody.innerHTML = trArr.join('');
// 绑定删除按钮事件
const deleteButtons = document.querySelectorAll('.delete-btn');
deleteButtons.forEach(button => {
button.addEventListener('click', function (e) {
const stuId = parseInt(this.closest('tr').getAttribute('data-id'));
deleteRecord(stuId);
});
});
}
function deleteRecord(stuId) {
// 从数组中删除对应的数据
arr = arr.filter(ele => ele.stuId !== stuId);
// 更新 localStorage
localStorage.setItem('data', JSON.stringify(arr));
// 渲染页面
render();
}
render();
const info = document.querySelector('.info');
const uname = document.querySelector('.uname');
const age = document.querySelector('.age');
const salary = document.querySelector('.salary');
const gender = document.querySelector('.gender');
const city = document.querySelector('.city');
info.addEventListener('submit', function (e) {
e.preventDefault(); // 防止表单提交的默认行为
if (!uname.value || !age.value || !salary.value) {
return alert('输入内容不能为空');
}
// 生成新的 stuId
const newStuId = arr.length ? arr[arr.length - 1].stuId + 1 : 1;
// 处理表单数据
arr.push({
stuId: newStuId,
uname: uname.value,
age: age.value,
gender: gender.value,
salary: salary.value,
city: city.value,
time: new Date().toLocaleString() // 调用方法
});
// 更新 localStorage
localStorage.setItem('data', JSON.stringify(arr));
// 渲染页面
render();
// 重置表单
this.reset();
});
</script>
</body>
</html>
正则表达式
返回true或false
返回数组
具有特殊意义的字符就是元字符。比如,可以将abcdef.....z替换成[a-z]。
-
g
(global):全局匹配。查找整个输入字符串中所有符合正则表达式的匹配项,而不是找到第一个匹配项就停止搜索。 -
i
(ignore case):忽略大小写。匹配时不区分字母的大小写。例如,/a/i
会匹配 'a'、'A' 等。
闭包
闭包是一种编程概念,指的是一个函数与其相关的变量环境捆绑在一起的能力。换句话说,闭包允许一个函数在其外部定义的变量范围内操作,即使这些变量在函数外部已经不再存在。这种特性使得函数能够记住并访问它们创建时的作用域。闭包常用于创建私有变量和函数,封装代码,以及实现一些函数式编程的模式。
变量提升(了解)
变量提升实际上是js的缺陷,只会用var的时候会出现。仅作了解
<script>
console.log(num);//undefine
var num = 10;
</script>
<script>
// console.log(num);//undefine
// var num = 10;
//变量未申明就被使用,会出现变量提升,
//所有var变量都被提到当前作用域最前面,
//但是只提升声明,不提升赋值,因此代码相当于
var num
console.log(num);
num = 10
</script>
函数进阶
函数提升
函数提升和变量提升有点像。
只提升声明,不提升调用
动态参数
剩余参数
展开运算符
这个符号就是“...”
箭头函数(重要)
<script>
const fn1 = function () {
console.log('普通函数');
}
const fn2 = () => {
console.log('普通箭头函数')
}
const fn3 = (x) => {
//带参数的箭头函数
console.log(x)
}
const fn4 = x => {
//只有一个参数的箭头函数,可以省略()
console.log(x);
}
//当{}里只有一行代码时可以省略{}
const fn5 = (x, y) => x + y
//返回对象字面量表达式。加()是为了不会混淆
const fn6 = uname =>({uname : uname})
</script>
注意事项
箭头函数没有自己的this,如果非要用的话,会从自己作用域链的上一层沿用this,很不方便,因此如果用this的话一般不用箭头函数
解构
解构赋值
把数组里的元素快速地赋值给变量,使代码更简洁
必须加分号,不然会被当成数组的符号而不是解构的符号
<script>
const pc = ['海尔', '联想', '小米', '方正']
;[hr, l, x, f] = pc
const getval = () => [100, 1]
;[max, min] = getval()
console.log(hr, l, x, f, max, min);
</script>
对象解构
注意!对象解构用的符号是{},数组用的才是[]
<script>
const obj = {
name: 'lmm',
age: '3'
};
//注意,解构定义的变量名必须与对象的名字一样
const { name, age } = obj
console.log(name, age);
</script>
当然,也可以重新改名
下面是一个案例。
值得一提的是,
const { data } = msg;
的意思是:
- 从
msg
对象中提取data
属性的值。- 将提取的值赋给一个新的变量
data
。这段代码的效果等同于以下代码:
const data = msg.data;
<!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>
/* 添加样式 */
</style>
</head>
<body>
<script>
const msg = {
"code": 200,
"msg": "获取新闻列表成功",
"data": [
{
"id": 1,
"title": "5G商用自己,三大运用商收入下降",
"count": 58
},
{
"id": 2,
"title": "国际媒体头条速览",
"count": 56
},
{
"id": 3,
"title": "乌克兰和俄罗斯持续冲突",
"count": 1669
}
]
};
//需求1:用对象解构的方式取出data
const { data } = msg
console.log(data);
//需求2:把data当作参数传递给渲染函数
//第一种写法
function render(arr) {
console.log(arr);
}
render(data)
//第二种更简洁的写法
function render2({ data }) {
console.log(data);
}
render2(msg)
//需求3:为了防止msg里面的data名字混淆,
//要求渲染函数里的数据名改为myData
function render3({ data: myData }) {
console.log(myData);
}
render3(msg)
</script>
</body>
</html>
forEach方法(重点)
和map遍历一样的 。区别在于map遍历会返回一个数组
这个渲染,本质上就是把东西转换成字符串然后再拼接而已
构造函数
“上一次值” 就是上一次计算的结果,如果是第一次循环的话,上一次值就是第一个元素的值或者初始值(如果有设置的话)
<body>
<script>
const arr = [1, 2, 3]
//没有初始值
let sum1 = arr.reduce(function (pre, cur) {
return pre + cur;
})
console.log(sum1);//6
//有初始值。只是把结果加上初始值而已
let sum2 = arr.reduce(function (pre, cur) {
return pre + cur;
}, 6)
console.log(sum2);//12
//箭头函数写法
let sum3 = arr.reduce((pre, cur) => pre + cur, 6)
console.log(sum3);//12
</script>
</body>
可以看到,一个相同的函数被创造了两次,浪费内存
怎么解决内存浪费的问题?
<script>
function star(name, age) {
this.name = name
this.age = age
}
star.prototype.sing_wrong = () => {
//这样会错!!!
//因为箭头函数没有自己的this
console.log(this.name + '在唱歌');
}
star.prototype.sing = function () {
console.log(this.name + '在唱歌');
}
const a = new star('刘德华', 40)
const b = new star('张学友', 43)
a.sing(); b.sing();
</script>
利用原型来写数组的求最大值函数
<body>
<script>
const arr = [1, 2, 3, 4, 5]
//其实相当于
//const arr = new Array(1, 2, 3, 4, 5)
Array.prototype.max = function () {
return Math.max(...this)
}
console.log(arr.max());
</script>
</body>
能让原型对象找到其构造函数