Search K
Appearance
Appearance
以下代码运行结果是什么?(考察扩展运算符的使用)
const result = {
name: '老李',
age: 18,
};
const obj = {
...result,
};
console.log(obj.age);result对象的属性被复制到了新的对象obj中。因此,obj对象也包含了age属性,其值为18。最后,通过console.log(obj.age)打印出obj对象的age属性值,结果为18。什么是事件委托?
事件对象 e.target 作用是什么?
e 包含了触发事件的相关信息,其中 e.target 表示触发事件的目标元素。当事件在文档中的某个元素上触发时,e.target 将引用这个元素。e.target 来确定事件的实际目标,从而执行相应的操作。如果获取绑定在标签上自定义属性的值 10?
<div data-code="10">西游记</div>div标签对象.innerHTMLdiv标签对象.dataset.codediv标签对象.codedataset 属性。div 标签对象的 dataset.code 来获取 data-code 属性的值。所以,选项 B 是正确的。哪个方法可以判断目标标签是否包含指定的类名?
<div class="my-div title info"></div>div标签对象.className === 'title'div标签对象.classList.contains('title')classList.contains 方法。div 标签对象的 classList.contains('title') 来检查是否包含名为 'title' 的类名。所以,选项 B 是正确的。伪数组取值哪种方式是正确的?
let obj = { 0: '老李', 1: '老刘' };obj.0obj[0][])来访问伪数组(类数组对象)中的属性,因此 obj[0] 是正确的方法,可以得到 '老李' 的值。.)来访问属性,这在伪数组中是不正确的。以下哪个选项可以,往本地存储键为‘bgImg’,值为图片 url 网址的代码
localStorage.setItem('bgImg')localStorage.getItem('bgImg')localStorage.setItem('bgImg', '图片 url 网址')localStorage.getItem('bgImg', '图片 url 网址')localStorage.setItem(key, value) 方法,其中 key 是键,value 是对应的值。所以,选项 C 是正确的方式。以下代码运行结果是?
const obj = {
username: '老李',
age: 18,
sex: '男',
};
Object.keys(obj);[username, age, sex]["username", "age", "sex"]["老李", 18, "男"]Object.keys(obj) 方法返回一个包含给定对象的所有可枚举属性的字符串数组。obj 对象有三个属性,分别是 username、age 和 sex,因此 Object.keys(obj) 返回的结果是 ["username", "age", "sex"]。所以,选项 C 是正确的。下面哪个选项可以把数字字符串转成数字类型?
+'10''10' + 0+ 可以将数字字符串转换为数字类型。因此,+'10' 会将字符串 '10' 转换为数字 10。选项 A 是正确的。以下代码运行后的结果是什么?(考察逻辑与的短路特性)
const age = 18;
const result1 = age || '有年龄';
const sex = '';
const result2 = sex || '没有性别';报错,报错18,没有性别有年龄,没有性别18,''result1 中,age 的值是真值(非零数字),所以 result1 的值是 age,即 18。result2 中,sex 的值是假值(空字符串),所以 result2 的值是 '没有性别'。18,没有性别。学习目标
今天主要就是练,巩固 axios 的使用
打开备课代码运行图书管理案例效果 - 介绍要完成的增删改查业务效果和 Bootstrap 弹框使用


分析步骤和对应的视频模块
先学习 Bootstrap 弹框的使用(因为添加图书和编辑图书需要这个窗口来承载图书表单)
先做渲染图书列表(这样做添加和编辑以及删除可以看到数据变化,所以先做渲染)
再做新增图书功能
再做删除图书功能
再做编辑图书功能(注意:编辑和新增图书是 2 套弹框 - 后续做项目我们再用同 1 个弹框)
学习目标
什么是 Bootstrap 弹框?
需求:使用 Bootstrap 弹框,先做个简单效果,点击按钮,让弹框出现,点击 X 和 Close 让弹框隐藏

如何使用 Bootstrap 弹框呢?
先引入 bootstrap.css 和 bootstrap.js 到自己网页中
<link
href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css"
rel="stylesheet"
integrity="sha384-T3c6CoIi6uLrA9TneNEoa7RxnatzjcDSCmG1MXxSR1GAsXEV/Dwwykc2MPK8M2HN"
crossorigin="anonymous" />
<script
src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.min.js"
integrity="sha384-BBtl+eGJRgqQAUMxJ7pMwbEyER4l1g+O15P+16Ep7Q9Q+zqX6gSbd85u4mG4QzX+"
crossorigin="anonymous"></script>
<link
rel="stylesheet"
href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css"
integrity="sha256-MBffSnbbXwHCuZtgPYiwMQbfE7z+GOZ7fBPCNB06Z98="
crossorigin="anonymous" />
<script
src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.min.js"
integrity="sha256-YMa+wAM6QkVyz999odX7lPRxkoYAan8suedu4k2Zur8="
crossorigin="anonymous"></script>准备弹框标签,确认结构(可以从 Modal · Bootstrap v5.3 里复制基础例子)
运行到网页后,逐一对应标签和弹框每个部分对应关系
通过自定义属性,通知弹框的显示和隐藏,语法如下:
<button data-bs-toggle="modal" data-bs-target="css 选择器">显示弹框</button>
<button data-bs-dismiss="modal">Close</button><!-- `data-bs-toggle="modal"` 表示点击按钮时以模态框方式展示目标元素 -->
<button data-bs-toggle="modal" data-bs-target="#myModal">打开对话框</button><!-- `data-bs-target` 指定了要控制的对话框的 ID 为 `myModal` -->
<button data-bs-toggle="modal" data-bs-target="#myModal">打开对话框</button>
<div class="modal" id="myModal">对话框内容</div><!-- 按钮被点击时,data-bs-dismiss="modal" 表示关闭包含它的最近的对话框 -->
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">关闭</button><!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>12 属性控制 Bootstrap 弹窗</title>
<!-- 引入 bootstrap.css -->
<link rel="stylesheet" href="./css/bootstrap.min.css">
</head>
<body class="p-3 mb-2 d-flex justify-content-center align-items-center vh-100">
<!-- Button trigger modal -->
<button type="button" class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#exampleModal">
显示弹窗/对话框
</button>
<!-- Modal -->
<div class="modal fade" id="exampleModal" tabindex="-1" aria-labelledby="exampleModalLabel" aria-hidden="true">
<div class="modal-dialog modal-dialog-centered">
<div class="modal-content">
<div class="modal-header">
<h1 class="modal-title fs-5" id="exampleModalLabel">Modal title 弹框头部</h1>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<p>Modal body text goes here. 弹框身体</p>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>
<button type="button" class="btn btn-primary">Save changes</button>
</div>
</div>
</div>
</div>
<!-- 引入 bootstrap.js -->
<script src="./js/bootstrap.min.js"></script>
</body>
</html>为什么需要 JS 方式控制呢?
当我显示之前,隐藏之前,需要执行一些 JS 逻辑代码,就需要引入 JS 控制弹框显示/隐藏的方式了
例如:
所以在现实和隐藏之前,需要执行 JS 代码逻辑,就使用 JS 方式 控制 Bootstrap 弹框显示和隐藏。
语法如下:
// 创建弹框对象
const modalDom = document.querySelector('css 选择器');
const modal = new bootstrap.Modal(modelDom);
// 显示弹框
modal.show();
// 隐藏弹框
modal.hide();<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>13 JS 控制 Bootstrap 弹窗</title>
<!-- 引入 bootstrap.css -->
<link rel="stylesheet" href="./css/bootstrap.min.css">
</head>
<body class="p-3 mb-2 d-flex justify-content-center align-items-center vh-100">
<!-- Button trigger modal -->
<button type="button" class="btn btn-primary edit-btn" data-bs-toggle="modal" data-bs-target="#exampleModal">
编辑姓名
</button>
<!-- Modal -->
<div class="modal name-box" id="exampleModal" tabindex="-1" aria-labelledby="exampleModalLabel" aria-hidden="true">
<div class="modal-dialog modal-dialog-centered">
<div class="modal-content">
<div class="modal-header">
<h4 class="modal-title fs-5" id="exampleModalLabel">请输入姓名</h4>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<form action="" method="get" class="add-form">
<label for="name">姓名:</label>
<input type="text" id="name" name="name" class="form-control" placeholder="请输入姓名">
</form>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">取消</button>
<button type="button" class="btn btn-primary save-btn">保存</button>
</div>
</div>
</div>
</div>
<!-- 引入 bootstrap.js -->
<script src="./js/bootstrap.min.js"></script>
<script>
// 创建弹窗对象
const modalDom = document.querySelector(".name-box");
const modal = new bootstrap.Modal(modalDom);
// 点击按钮显示弹窗
const editBtn = document.querySelector(".edit-btn");
editBtn.addEventListener("click", () => {
modal.show();
});
// 点击保存按钮,获取输入框的值,并关闭弹窗
const saveBtn = document.querySelector(".save-btn");
saveBtn.addEventListener("click", () => {
const name = document.querySelector("#name").value;
console.log(name);
modal.hide();
// 将输入框内容设置为默认值
// document.querySelector("#name").value = "";
// document.querySelector("#name").placeholder = "请输入姓名";
document.querySelector(".add-form").reset(); // .reset() 重置表单
});
</script>
</body>
</html>data-bs-toggle 和 data-bs-target 。data-bs-dismiss 。/**
* @description 渲染图书列表
*
* api: http://hmajax.itheima.net/api/books - GET
* @param {string} creator - 操作者昵称
*/
const creator = '秋豆麻袋';
function renderBookList() {
axios
.get('http://hmajax.itheima.net/api/books', {
params: {
creator,
},
})
.then((response) => {
// console.log(response.data);
console.log(response.data.data);
document.querySelector('.list').innerHTML = response.data.data
.map((item, index) => {
return `
<tr>
<td>${index + 1}</td>
<td>${item.bookname}</td>
<td>${item.author}</td>
<td>${item.publisher}</td>
<td data-id=${item.id}>
<span class="del">删除</span>
<span class="edit">编辑</span>
</td>
</tr>`;
})
.join('');
})
.catch((error) => {
console.log(error.message);
});
}
// 网页加载完成后执行
renderBookList();modalform-serialize 收集表单数据/**
* @description 新增图书
*
* api: http://hmajax.itheima.net/api/books - POST
* @param {string} bookname - 书名
* @param {string} author - 作者
* @param {string} publisher - 出版社
* @param {string} creator - 操作者昵称
*/
function addBook() {
// 新增弹窗(显示与隐藏),使用 bootstrap 的 modal
const addModalDom = document.querySelector('.add-modal');
const addModal = new bootstrap.Modal(addModalDom);
const addBtn = document.querySelector('.add-btn');
addBtn.addEventListener('click', () => {
// 使用 form-serialize 收集表单数据,然后发送到服务器保存
const addForm = document.querySelector('.add-form');
const bookObj = serialize(addForm, { hash: true, empty: true });
axios
.post('http://hmajax.itheima.net/api/books', {
...bookObj, // 合并对象
creator,
})
.then((response) => {
console.log(response.data);
// 成功后重新从服务器获取数据,然后渲染图书列表
renderBookList();
// 重置表单
addForm.reset();
// 关闭弹窗
addModal.hide();
})
.catch((error) => {
console.log(error.message);
});
});
}
addBook();服务器响应:
{
"message": "添加图书成功",
"data": {
"id": 349535,
"bookname": "我在北京送快递",
"author": "胡安焉",
"publisher": "湖南文艺出版社"
}
}
{
"message": "添加图书成功",
"data": {
"id": 349536,
"bookname": "寻求意义",
"author": "李泽厚",
"publisher": "人民文学出版社"
}
}/**
* @description 删除图书
*
* api: http://hmajax.itheima.net/api/books/:id - DELETE
* @param {number} id - 图书 id
*/
function delBook() {
// 删除元素绑定点击事件(事件委托)
document.querySelector('.list').addEventListener('click', (e) => {
// 判断触发事件目标元素:点击的是哪个元素
// console.log(e.target);
// 判断点击的是删除按钮
if (e.target.classList.contains('del')) {
// console.log('点击了删除按钮!!!');
// 获取元素的 data-id 属性,即图书 id
// const id = e.target.parentNode.dataset.id;
const id = e.target.parentNode.getAttribute('data-id');
// console.log(`图书 id:${id}`);
axios
.delete(`http://hmajax.itheima.net/api/books/${id}`)
.then((response) => {
console.log(response.data);
// 成功后重新从服务器获取数据,然后渲染图书列表
renderBookList();
})
.catch((error) => {
console.log(error.message);
});
}
});
}
delBook();
// {"message":"删除图书成功","data":{"id":"349536"}}modal),然后从服务器获取图书信息渲染在弹窗中/**
* @description 编辑图书信息
*
* api: http://hmajax.itheima.net/api/books/:id - PUT
* @param {number} id - 图书 id
*/
function editBook() {
// 新增弹窗(显示与隐藏),使用 bootstrap 的 modal
const editModalDom = document.querySelector('.edit-modal');
const editModal = new bootstrap.Modal(editModalDom);
// 点击列表中的编辑按钮,弹出编辑图书弹窗,然后从服务器获取图书信息渲染在弹窗中
document.querySelector('.list').addEventListener('click', (e) => {
// 判断触发事件目标元素:点击的是哪个元素
// console.log(e.target);
// 判断点击的是编辑按钮
if (e.target.classList.contains('edit')) {
// console.log('点击了编辑按钮!!!');
// 获取元素的 data-id 属性,即图书 id
const id = e.target.parentNode.getAttribute('data-id');
// console.log(`图书 id:${id}`);
// 使用 axios 发送请求,获取图书信息
axios
.get(`http://hmajax.itheima.net/api/books/${id}`)
.then((response) => {
// console.log(response.data);
// 将图书信息渲染到弹窗中
const bookObj = response.data.data;
// console.log(bookObj);
// 给表单赋值
const editForm = document.querySelector('.edit-form');
// editForm.bookname.value = bookObj.bookname;
// editForm.author.value = bookObj.author;
// editForm.publisher.value = bookObj.publisher;
// editForm.id.value = bookObj.id;
// 因为对象 "属性" 和标签 "类名" 一样,所以我们使用循环遍历 bookObj 对象,使用属性去获取对应的标签,实现快速赋值
for (const key in bookObj) {
// console.log(key);
// console.log(bookObj[key]);
// console.log(editForm[key]);
editForm[key].value = bookObj[key];
}
// 显示弹窗
editModal.show();
})
.catch((error) => {
console.log(error.message);
});
}
});
// 在打开的编辑图书弹窗中,点击修改按钮后,发送数据到服务器保存
document.querySelector('.edit-btn').addEventListener('click', () => {
// 使用 form-serialize 收集表单数据,然后发送到服务器保存
const editForm = document.querySelector('.edit-form');
// const bookObj = serialize(editForm, { hash: true, empty: true });
const { bookname, author, publisher, id } = serialize(editForm, { hash: true, empty: true });
axios
.put(`http://hmajax.itheima.net/api/books/${id}`, {
// ...bookObj, // 合并对象
bookname,
author,
publisher,
creator,
})
.then((response) => {
console.log(response.data);
// 成功后重新从服务器获取数据,然后渲染图书列表
renderBookList();
// 关闭弹窗
editModal.hide();
})
.catch((error) => {
console.log(error.message);
});
});
}
editBook();服务器响应:
{
"message": "修改图书成功",
"data": {
"id": 349535,
"bookname": "我在北京送快递",
"author": "胡安焉",
"publisher": "湖南文艺出版社"
}
}// 1.1 获取数据
axios({...}).then(result => {
const bookList = result.data.data
// 1.2 渲染数据
const htmlStr = bookList.map((item, index) => {
return `<tr>
<td>${index + 1}</td>
<td>${item.bookname}</td>
<td>${item.author}</td>
<td>${item.publisher}</td>
<td data-id=${item.id}>
<span class="del">删除</span>
<span class="edit">编辑</span>
</td>
</tr>`
}).join('')
document.querySelector('.list').innerHTML = htmlStr
})// 2.1 创建弹框对象
const addModalDom = document.querySelector('.add-modal')
const addModal = new bootstrap.Modal(addModalDom)
document.querySelector('.add-btn').addEventListener('click', () => {
// 2.2 收集表单数据,并提交到服务器保存
const addForm = document.querySelector('.add-form')
const bookObj = serialize(addForm, { hash: true, empty: true })
axios({...}).then(result => {
// 2.3 添加成功后,重新请求并渲染图书列表
getBooksList()
addForm.reset()
addModal.hide()
})
})// 3.1 删除元素->点击(事件委托)
document.querySelector('.list').addEventListener('click', e => {
if (e.target.classList.contains('del')) {
// 获取图书 id(自定义属性 id)
const theId = e.target.parentNode.dataset.id
// 3.2 调用删除接口
axios({...}).then(() => {
// 3.3 刷新图书列表
getBooksList()
})
}
})// 4.1 编辑弹框->显示和隐藏
const editDom = document.querySelector('.edit-modal')
const editModal = new bootstrap.Modal(editDom)
document.querySelector('.list').addEventListener('click', e => {
if (e.target.classList.contains('edit')) {
// 4.2 获取当前编辑图书数据->回显到编辑表单中
const theId = e.target.parentNode.dataset.id
axios({...}).then(result => {
const bookObj = result.data.data
// 遍历数据对象,使用属性去获取对应的标签,快速赋值
const keys = Object.keys(bookObj)
keys.forEach(key => {
document.querySelector(`.edit-form .${key}`).value = bookObj[key]
})
})
editModal.show()
}
})
document.querySelector('.edit-btn').addEventListener('click', () => {
// 4.3 提交保存修改,并刷新列表
const editForm = document.querySelector('.edit-form')
const { id, bookname, author, publisher } = serialize(editForm, { hash: true, empty: true})
// 保存正在编辑的图书 id,隐藏起来:无需让用户修改
// <input type="hidden" class="id" name="id" value="84783">
axios({...}).then(() => {
getBooksList()
editModal.hide()
})
})什么是图片上传?
图片上传怎么做?
为什么不直接显示到浏览器上,要放到服务器上呢?
图片上传步骤:
先获取图片文件对象
使用 FormData 表单数据对象装入
FormData 以键值对 - 文件流的数据传递(可以查看请求体 - 确认请求体结构)const formData = new FormData()
formData.append(参数名,值)提交表单数据对象,使用服务器返回图片 url 网址
FormData 表单对象中,再发给服务器img 标签加载图片显示<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>15 图片上传</title>
<!-- 引入 bootstrap.css -->
<link rel="stylesheet" href="./css/bootstrap.min.css">
</head>
<body class="p-5">
<div class="mb-3">
<label for="formFile" class="form-label">上传图片</label>
<input class="form-control" type="file" id="formFile">
</div>
<img src="" class="rounded mx-auto d-block" alt="上传的图片">
<script src="./js/axios.min.js"></script>
<script>
document.querySelector("#formFile").addEventListener("change", (e) => {
// 获取文件
const file = e.target.files[0]
console.log(file)
// FormData 对象用于构建一组键/值对,以模拟一个完整的 HTML 表单
// FormData 对象可以携带文件用来上传
const formData = new FormData()
formData.append("img", file)
axios
.post("http://hmajax.itheima.net/api/uploadimg", formData)
.then((response) => {
console.log(response.data)
document.querySelector("img.rounded").src = response.data.data.url
}).catch(error => {
console.log(error.message)
})
})
</script>
</body>
</html>------WebKitFormBoundarykB0csH4AW9ehZW9Z
Content-Disposition: form-data; name="img"; filename="16761891466140.7797740766205927.png"
Content-Type: image/png
------WebKitFormBoundarykB0csH4AW9ehZW9Z--{
"message": "上传成功",
"data": {
"url": "http://yjy-teach-oss.oss-cn-beijing.aliyuncs.com/ajax/17045282675650.4073109932758119.png"
}
}网站更换背景图如何实现呢,并且保证刷新后背景图还在显示呢?
解决方案:
使用 localStorage 本地存储,将图片的 url 存储到本地,
刷新页面时,再通过 localStorage 获取到 url 并加载,并判断本地有图片 url 网址字符串才设置
localStorage 取值和赋值的语法
// 赋值
localStorage.setItem('background-image', 'url(https://picsum.photos/id/1005/1920/1080)');
// 取值
localStorage.getItem('background-image');<!DOCTYPE html>
<html lang="zh-CN">
<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>网站-更换背景</title>
<!-- 初始化样式 -->
<link rel="stylesheet" href="./css/reset.min.css">
<!-- 核心样式 -->
<link rel="stylesheet" href="./css/index.css">
</head>
<body>
<div class="container">
<div class="nav">
<div class="left">
<ul>
<li><a href="http://yun.itheima.com/?webzly" target="_blank" rel="nofollow">免费教程</a></li>
<li><a href="http://resource.ityxb.com/booklist/?webzly" target="_blank" rel="nofollow">原创书籍</a></li>
<li><a href="http://www.itheima.com/teacher.html?webzly#ajavaee" target="_blank" rel="nofollow">教研团队</a></li>
<li><a href="http://www.itheima.com/special/hmschool/index.shtml?webzly" target="_blank"
rel="nofollow">校区汇总</a></li>
<li><a href="http://www.itheima.com/flow/flow.html?webzly" target="_blank" rel="nofollow">报名流程</a></li>
<li><a href="https://pip.itcast.cn?hmgw$webzly" target="_blank" rel="nofollow">项目信息站</a></li>
<li><a href="http://bbs.itheima.com/forum.php?webzly" target="_blank" rel="nofollow">技术社区</a></li>
</ul>
</div>
<div class="right">
<label for="bg">更换背景</label>
<input class="bg-ipt" type="file" id="bg">
</div>
</div>
<div class="search-container">
<img src="./logo.png" alt="">
<div class="search-box">
<input type="text">
<button>搜索一下</button>
</div>
</div>
</div>
<script src="./js/axios.min.js"></script>
<!-- <script src="./js/index.js"></script> -->
<script>
// 更换背景按钮绑定点击事件
document.querySelector('.bg-ipt').addEventListener('change', (e) => {
if (e.target.files[0]) {
// 读取文件
const formData = new FormData();
formData.append('img', e.target.files[0]);
// 上传文件
axios
.post('http://hmajax.itheima.net/api/uploadimg', formData)
.then((response) => {
// 上传成功
console.log(response.data);
document.body.style.backgroundImage = `url(${response.data.data.url})`;
// 保存背景图片 url 地址到 localStorage
localStorage.setItem('bgImg', response.data.data.url);
})
.catch((error) => {
console.log(error.message);
});
}
});
// 网页运行后从 localStorage 中读取背景图片
const bgImg = localStorage.getItem('bgImg');
// bgImg && (document.body.style.backgroundImage = `url(${bgImg})`);
if (bgImg) {
document.body.style.backgroundImage = `url(${bgImg})`;
}
</script>
</body>
</html>介绍个人信息设置案例。
项目分为:信息回显 + 头像修改 + 信息修改 + 提示框反馈 4 部分。
把昵称对应的用户信息渲染到页面上。
/**
* @description 个人信息渲染:把用户信息渲染到页面上
*
* api: http://hmajax.itheima.net/api/settings - GET
* @param {string} creator - 操作者昵称
*/
const creator = '秋豆麻袋';
function renderInfo() {
axios
.get(`http://hmajax.itheima.net/api/settings?creator=${creator}`)
.then((response) => {
console.log(response.data);
const userObj = response.data.data;
for (const key of Object.keys(userObj)) {
// console.log(`${key}: ${userObj[key]}`);
// userObj: {avatar: 'http://hmajax.itheima.net/avatar/avatar1.png', nickname: 'itheima', email: 'itheima@itcast.cn', desc: '我是秋豆麻袋', gender: 0(0 男 1 女)}
// html 里的 class 为:prew, nickname, email, desc, gender
if (key === 'avatar') {
document.querySelector('.avatar-box .prew').src = userObj[key];
} else if (key === 'gender') {
// 获取性别单选框:[男 radio 元素,女 radio 元素]
const genderRadioList = document.querySelectorAll('.user-form .gender');
// 获取性别数字:0 男,1 女
const genderNum = userObj[key];
// 通过性别数字,作为下标,找到对应性别单选框,设置选中状态
genderRadioList[genderNum].checked = true;
} else {
// 其他情况,直接赋值给对应的输入框
document.querySelector(`.user-form .${key}`).value = userObj[key];
}
}
})
.catch((error) => {
console.log(error.message);
});
}
renderInfo();FormData 表单数据对象中携带操作者昵称url 网址设置在页面上/**
* @description: 个人头像修改
*
* api: http://hmajax.itheima.net/api/avatar - PUT
* @param {file} avatar - 个人头像文件
* @param {string} creator - 操作者昵称
*/
function changeAvatar() {
// 更改头像 按钮绑定事件
document.querySelector('.avatar-box #upload').addEventListener('change', (e) => {
if (e.target.files.length > 0) {
const formData = new FormData();
formData.append('avatar', e.target.files[0]);
formData.append('creator', creator);
axios
.put('http://hmajax.itheima.net/api/avatar', formData)
.then((response) => {
console.log('保存个人头像成功');
document.querySelector('.avatar-box .prew').src = response.data.data.avatar;
})
.catch((error) => {
console.log(error.message);
});
}
});
}
changeAvatar();/**
* @description: 个人信息修改
*
* api: http://hmajax.itheima.net/api/settings - PUT
* @param {string} desc - 用户简介
* @param {string} email - 邮箱
* @param {integer} gender - 用户性别 (0 男 1 女)
* @param {string} nickname - 用户昵称
* @param {string} creator - 操作者昵称
*/
function updateInfo() {
// 提交按钮绑定事件
document.querySelector('.submit').addEventListener('click', () => {
// 获取表单数据
const userForm = document.querySelector('.user-form');
const userObj = serialize(userForm, { hash: true, empty: true });
console.log(userObj);
// {email: 'itheima@itcast.cn', nickname: 'itheima', gender: '0', desc: '我是秋豆麻袋'}
// 需要将 gender 转换为数字,添加 creator 属性
userObj.gender = +userObj.gender;
userObj.creator = creator;
console.log(userObj);
// {email: 'itheima@itcast.cn', nickname: 'itheima', gender: 0, desc: '我是秋豆麻袋', creator: '秋豆麻袋'}
axios
.put('http://hmajax.itheima.net/api/settings', userObj)
.then((response) => {
console.log(response.data);
console.log('保存个人设置成功');
// 使用 bootstrap 里的 toast 组件
const toastDom = document.querySelector('.my-toast');
const toast = new bootstrap.Toast(toastDom);
// 显示 toast
toast.show();
})
.catch((error) => {
console.log(error.msessage);
});
});
}
updateInfo();把用户更新个人信息结果,用提示框反馈给用户
使用 bootstrap 提示框,提示个人信息设置后的结果。
bootstrap 的 toast 提示框和 modal 弹框使用很像,语法如下:
先准备对应的标签结构(模板里已有),设置延迟自动消失的时间
<!-- data-bs-delay="1500" 表示延迟 1.5 秒后自动消失 -->
<div class="toast" data-bs-delay="1500">提示框内容</div>使用 JS 的方式,在 axios 请求响应成功时,展示结果
// 创建提示框对象
const toastDom = document.querySelector('css 选择器');
const toast = new bootstrap.Toast(toastDom);
// 显示提示框
toast.show();掌握增删改查数据的思路
// 1.1 获取数据
axios({...}).then(result => {
const bookList = result.data.data
// 1.2 渲染数据
const htmlStr = bookList.map((item, index) => {
return `<tr>
<td>${index + 1}</td>
<td>${item.bookname}</td>
<td>${item.author}</td>
<td>${item.publisher}</td>
<td data-id=${item.id}>
<span class="del">删除</span>
<span class="edit">编辑</span>
</td>
</tr>`
}).join('')
document.querySelector('.list').innerHTML = htmlStr
})// 2.1 创建弹框对象
const addModalDom = document.querySelector('.add-modal')
const addModal = new bootstrap.Modal(addModalDom)
document.querySelector('.add-btn').addEventListener('click', () => {
// 2.2 收集表单数据,并提交到服务器保存
const addForm = document.querySelector('.add-form')
const bookObj = serialize(addForm, { hash: true, empty: true })
axios({...}).then(result => {
// 2.3 添加成功后,重新请求并渲染图书列表
getBooksList()
addForm.reset()
addModal.hide()
})
})// 3.1 删除元素->点击(事件委托)
document.querySelector('.list').addEventListener('click', e => {
if (e.target.classList.contains('del')) {
// 获取图书 id(自定义属性 id)
const theId = e.target.parentNode.dataset.id
// 3.2 调用删除接口
axios({...}).then(() => {
// 3.3 刷新图书列表
getBooksList()
})
}
})// 4.1 编辑弹框->显示和隐藏
const editDom = document.querySelector('.edit-modal')
const editModal = new bootstrap.Modal(editDom)
document.querySelector('.list').addEventListener('click', e => {
if (e.target.classList.contains('edit')) {
// 4.2 获取当前编辑图书数据->回显到编辑表单中
const theId = e.target.parentNode.dataset.id
axios({...}).then(result => {
const bookObj = result.data.data
// 遍历数据对象,使用属性去获取对应的标签,快速赋值
const keys = Object.keys(bookObj)
keys.forEach(key => {
document.querySelector(`.edit-form .${key}`).value = bookObj[key]
})
})
editModal.show()
}
})
document.querySelector('.edit-btn').addEventListener('click', () => {
// 4.3 提交保存修改,并刷新列表
const editForm = document.querySelector('.edit-form')
const { id, bookname, author, publisher } = serialize(editForm, { hash: true, empty: true})
// 保存正在编辑的图书 id,隐藏起来:无需让用户修改
// <input type="hidden" class="id" name="id" value="84783">
axios({...}).then(() => {
getBooksList()
editModal.hide()
})
})掌握图片上传的思路和流程
<form id="uploadForm" enctype="multipart/form-data">
<input type="file" name="fileInput" id="fileInput" />
<button type="button" onclick="uploadFile()">Upload</button>
</form>
<script>
function uploadFile() {
var fileInput = document.getElementById('fileInput');
var file = fileInput.files[0];
var formData = new FormData();
formData.append('file', file);
// 使用 XMLHttpRequest 发送请求
var xhr = new XMLHttpRequest();
xhr.open('POST', '/upload', true);
xhr.onreadystatechange = () => {
if (xhr.readyState === 4 && xhr.status === 200) {
// 上传成功,处理响应
console.log(xhr.responseText);
}
};
xhr.send(formData);
// 使用 Axios
// axios.post('/upload', formData)
// .then(response => console.log(response.data))
// .catch(error => console.error(error));
// 使用 Fetch API
// fetch('/upload', { method: 'POST', body: formData })
// .then(response => response.json())
// .then(data => console.log(data))
// .catch(error => console.error(error));
}
</script>理解调用接口时,携带外号的作用
了解 bootstrap 弹框的使用
<!-- 使用 CDN 引入 Bootstrap 样式文件 -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap/dist/css/bootstrap.min.css" />
<!-- toast 定义外观,toastBody 定义内容,data-bs-delay="1500" 表示延迟 1.5 秒后自动消失 -->
<div class="toast" id="myToast" role="alert" aria-live="assertive" aria-atomic="true" data-bs-delay="1500">
<div class="toast-body">This is a toast message.</div>
</div>
<!-- 引入 Bootstrap JS 文件 -->
<script src="https://cdn.jsdelivr.net/npm/bootstrap/dist/js/bootstrap.bundle.min.js"></script>
<!-- 定义弹框显示/隐藏的 JS 代码 -->
<script>
// 获取弹框元素
const myToast = document.getElementById('myToast');
// 创建弹框对象
const toast = new bootstrap.Toast(myToast);
// 手动触发 Toast 的显示
toast.show();
</script>在线答题:Day02_AJAX 综合案例
事件对象 e.target 的作用?
e.target 是事件对象中的一个属性,它在事件处理函数中指向触发事件的对象。对于事件委托(event delegation)来说,如果事件是在委托的父元素上触发的,e.target 将会是真正触发事件的子元素。什么时候用 JS 方式控制 Bootstrap 弹框显示/隐藏?
获取数据,渲染页面列表是哪个需求的思路?
以下哪个思路做表单回显更好?
Object.keys 方法的解释正确的是?
Object.keys 方法是 JavaScript 中用于获取对象自身可枚举属性的属性名的方法。它返回一个包含给定对象所有的可枚举属性的字符串数组。以下哪个描述是正确的?
图片上传哪个描述正确?
答案是 C. 把本地图片上传到服务器,服务器返回图片在服务器上的 URL 地址,前端使用这个地址来访问图片,但是刷新后图片 URL 地址如果没有持久化也会消失
常见的图片上传流程:
需要注意的是,这个 URL 地址通常是临时的,如果没有在前端进行持久化(例如存储到数据库或本地存储中),刷新页面后可能会失效。
新增数据思路哪个是正确的?
答案是 B. 收集数据提交到服务器后,还要重新从服务器获取最新数据列表,刷新页面
通常,新增数据的正确流程是:
外号有什么用
现有代码 let userName = '小智',以下哪个简写正确?
{ userName: userName }{ userName }{ userName: 'userName' }{ username }{ userName }{ userName } 就是 let userName = '小智' 的简写形式,表示一个包含属性名为 userName,值为变量 userName 的对象。<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<meta name="renderer" content="webkit" />
<meta http-equiv="X-UA-Compatible" content="IE=Edge" />
<title>必要商城_大牌品质 工厂价格</title>
<link href="./favicon.ico" rel="shortcut icon" type="image/x-icon" />
<link href="./css/common.css" rel="stylesheet" type="text/css" />
<link href="./css/new.main.css" rel="stylesheet" type="text/css" />
<link href="./css/elementUI.css" rel="stylesheet" type="text/css" />
<link href="./css/global.css" rel="stylesheet" type="text/css" />
<link href="./css/iprHeader.css" rel="stylesheet" type="text/css" />
<link href="./css/new.category.css" rel="stylesheet" type="text/css" />
</head>
<body id="pagebody">
<div class="header header-index"></div>
<!-- 导航栏 -->
<div class="nav nav-index">
<div class="clearfix">
<a href="#" class="nav-logo"><img src="./logo.png" height="51" /></a>
<div class="nav-category">
<p><span>全部分类</span><i></i></p>
<div>
<ul class="nav-list">
<li class="nav-main">
<p>
<a href="http://www.biyao.com/classify/category.html?categoryId=621"> 咖啡 </a>
<span>/</span>
<a href="http://www.biyao.com/classify/category.html?categoryId=627"> 饮食 </a>
<span>/</span>
<a href="http://www.biyao.com/classify/category.html?categoryId=691"> 正餐 </a>
</p>
</li>
<li class="nav-main">
<p>
<a href="http://www.biyao.com/classify/category.html?categoryId=279"> 男装 </a>
<span>/</span>
<a href="http://www.biyao.com/classify/category.html?categoryId=294"> 女装 </a>
<span>/</span>
<a href="http://www.biyao.com/classify/category.html?categoryId=35"> 鞋靴 </a>
</p>
</li>
<li class="nav-main">
<p>
<a href="http://www.biyao.com/classify/category.html?categoryId=122"> 眼镜 </a>
<span>/</span>
<a href="http://www.biyao.com/classify/category.html?categoryId=339"> 内衣配饰 </a>
<span>/</span>
<a href="http://www.biyao.com/classify/category.html?categoryId=39"> 运动 </a>
</p>
</li>
<li class="nav-main">
<p>
<a href="http://www.biyao.com/classify/category.html?categoryId=119"> 美妆 </a>
<span>/</span>
<a href="http://www.biyao.com/classify/category.html?categoryId=724"> 个护 </a>
<span>/</span>
<a href="http://www.biyao.com/classify/category.html?categoryId=391"> 母婴 </a>
</p>
</li>
<li class="nav-main">
<p>
<a href="http://www.biyao.com/classify/category.html?categoryId=652"> 生鲜直供 </a>
<span>/</span>
<a href="http://www.biyao.com/classify/category.html?categoryId=51"> 餐厨 </a>
<span>/</span>
<a href="http://www.biyao.com/classify/category.html?categoryId=334"> 电器 </a>
</p>
</li>
<li class="nav-main">
<p>
<a href="http://www.biyao.com/classify/category.html?categoryId=153"> 箱包 </a>
<span>/</span>
<a href="http://www.biyao.com/classify/category.html?categoryId=223"> 数码办公 </a>
<span>/</span>
<a href="http://www.biyao.com/classify/category.html?categoryId=429"> 汽配 </a>
</p>
</li>
<li class="nav-main">
<p>
<a href="http://www.biyao.com/classify/category.html?categoryId=355"> 家纺 </a>
<span>/</span>
<a href="http://www.biyao.com/classify/category.html?categoryId=10"> 家具 </a>
<span>/</span>
<a href="http://www.biyao.com/classify/category.html?categoryId=369"> 家装 </a>
</p>
</li>
<li class="nav-main">
<p>
<a href="http://www.biyao.com/classify/category.html?categoryId=546"> 健康保健 </a>
<span>/</span>
<a href="http://www.biyao.com/classify/category.html?categoryId=685"> 宠物 </a>
<span>/</span>
<a href="http://www.biyao.com/classify/category.html?categoryId=816"> 礼品 </a>
</p>
</li>
</ul>
</div>
</div>
<div class="nav-search">
<p><input type="text" id="searchInput" placeholder="请输入要搜索的商品" /><span id="searchBtn"></span></p>
<ul>
<li>电动牙刷</li>
<li>男士内裤</li>
<li>防晒霜</li>
<li>防晒</li>
<li>防晒衣女</li>
<li>眼镜近视女</li>
<li>洗发水</li>
<li>面膜</li>
<li>凉席</li>
<li>沐浴露</li>
</ul>
</div>
<div class="nav-tab">
<ul>
<li><a href="http://www.biyao.com/home/index.html">首页</a></li>
<li><a href="http://www.biyao.com/classify/newProduct.html">每日上新</a></li>
<li class="border-l"></li>
<li class="nav-tab-last">
<div class="hover_text">
了解必要
<div class="hover_code gzh">
<span>关注必要微信公众号<br />了解你想了解的一切<br />小必姐在此发福利哦</span>
</div>
</div>
</li>
<li class="nav-tab-last" id="appDownload">下载必要 APP</li>
<li class="border-l"></li>
<li class="nav-tab-last">
<div class="hover_text">
我的必要
<div class="hover_code app">
<span>
扫码下载必要 app
<br />
手机用户独享海量权益
</span>
</div>
</div>
</li>
</ul>
</div>
</div>
</div>
<!-- 分类栏 -->
<div class="cateBread">
<span>一级分类:</span>
<ul id="one">
<li>示例</li>
</ul>
</div>
<div class="cateBread">
<span>二级分类:</span>
<ul id="two">
<li>休食</li>
</ul>
</div>
<div class="cateBread">
<span>三级分类:</span>
<ul id="three">
<li>零食</li>
</ul>
</div>
<script src="./js/axios.min.js"></script>
<script src="./js/index.js"></script>
</body>
</html>/**
* @description: 显示一级分类导航
*
* api: https://hmajax.itheima.net/api-s/categoryfirst - GET
*
*/
function getFirstList() {
axios
.get('https://hmajax.itheima.net/api-s/categoryfirst')
.then((res) => {
console.log(res.data);
document.querySelector('#one').innerHTML = res.data.list
.map((item) => {
return `<li data-id="${item.firstId}">${item.firstName}</li>`;
})
.join('');
})
.catch((err) => {
console.log(err.message);
});
}
/**
* @description: 点击一级分类切换,展示下属二级分类数据
*
* api: https://hmajax.itheima.net/api-s/categorySecond - GET
* @param {String} firstId - 一级分类的 id
*/
function getSecondList(firstId) {
axios
.get(`https://hmajax.itheima.net/api-s/categorySecond?firstId=${firstId}`)
.then((res) => {
console.log(res.data);
document.querySelector('#two').innerHTML = res.data.list
.map((item) => {
return `<li data-id="${item.secondId}">${item.secondName}</li>`;
})
.join('');
})
.catch((err) => {
console.log(err.message);
});
}
/**
* @description: 点击二级分类分类,展示下属三级分类数据
*
* api: https://hmajax.itheima.net/api-s/categoryThird - GET
* @param {String} secondId - 二级分类的 id
*/
function getThirdList(secondId) {
axios
.get(`https://hmajax.itheima.net/api-s/categoryThird?secondId=${secondId}`)
.then((res) => {
console.log(res.data);
document.querySelector('#three').innerHTML = res.data.list
.map((item) => {
return `<li data-id="${item.thiredId}">${item.thiredName}</li>`;
})
.join('');
})
.catch((err) => {
console.log(err.message);
});
}
// 默认打开网页时,展示所有一级分类数据
getFirstList();
// 监听一级按钮点击事件
document.querySelector('#one').addEventListener('click', (e) => {
// 判断点击元素为 li 标签
if (e.target.tagName === 'LI') {
// 获取点击的 li 标签的 data-id 属性值
const id = e.target.getAttribute('data-id');
// 向服务器发送请求,获取二级列表
getSecondList(id);
}
});
// 监听二级列表的点击事件
document.querySelector('#two').addEventListener('click', (e) => {
// 判断点击元素为 li 标签
if (e.target.tagName === 'LI') {
// 获取点击的 li 标签的 data-id 属性值
const id = e.target.getAttribute('data-id');
// 向服务器发送请求,获取三级列表
getThirdList(id);
}
});<!DOCTYPE html>
<html lang="zh-CN">
<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>网站-更换背景</title>
<!-- 初始化样式 -->
<link rel="stylesheet" href="./css/reset.min.css">
<!-- 核心样式 -->
<link rel="stylesheet" href="./css/index.css">
</head>
<body>
<div class="container">
<div class="nav">
<div class="left">
<ul>
<li><a href="http://yun.itheima.com/?webzly" target="_blank" rel="nofollow">免费教程</a></li>
<li><a href="http://resource.ityxb.com/booklist/?webzly" target="_blank" rel="nofollow">原创书籍</a></li>
<li><a href="http://www.itheima.com/teacher.html?webzly#ajavaee" target="_blank" rel="nofollow">教研团队</a></li>
<li><a href="http://www.itheima.com/special/hmschool/index.shtml?webzly" target="_blank"
rel="nofollow">校区汇总</a></li>
<li><a href="http://www.itheima.com/flow/flow.html?webzly" target="_blank" rel="nofollow">报名流程</a></li>
<li><a href="https://pip.itcast.cn?hmgw$webzly" target="_blank" rel="nofollow">项目信息站</a></li>
<li><a href="http://bbs.itheima.com/forum.php?webzly" target="_blank" rel="nofollow">技术社区</a></li>
</ul>
</div>
<div class="right">
<label for="bg">更换背景</label>
<input class="bg-ipt" type="file" id="bg">
</div>
</div>
<div class="search-container">
<img src="https://www.itheima.com/images/logo.png" alt="">
<div class="search-box">
<input type="text">
<button>搜索一下</button>
</div>
</div>
</div>
<script src="./js/axios.min.js"></script>
<script src="./js/index.js"></script>
</body>
</html>// 这个案例中有 6 处报错,改正后让代码正常完成更换背景图案例吧(刷新背景图也要在)
/**
* 目标:网站 - 更换背景
* 1. 选择图片上传,设置 body 背景
* 2. 上传成功时,"保存"图片 url 网址
* 3. 网页运行后,"获取"url 网址使用
* */
document.querySelector('.bg-ipt').addEventListener('click', (e) => {
// 1. 选择图片上传,设置 body 背景
console.log(e.target.files[0]);
const fd = new FormData();
fd.append('avatar', e.target.files[0]);
axios({
url: 'http://hmajax.itheima.net/api/uploadimg',
method: 'PUT',
data: fd,
}).then((result) => {
const imgUrl = result.data.data.url;
document.body.style.backgroundImage = imgUrl;
// 2. 上传成功时,"保存"图片 url 网址
localStorage.setItem('bgImg', imgUrl);
});
});
// 3. 网页运行后,"获取"url 网址使用
const bgUrl = localStorage.getItem('bg');
console.log(bgUrl);
bgUrl || (document.body.style.backgroundImage = `url(${bgUrl})`);打开浏览器,控制台输出 null index.js:28:9,查看 index.js 代码相关片段
const bgUrl = localStorage.getItem('bg');
console.log(bgUrl);
bgUrl || (document.body.style.backgroundImage = `url(${bgUrl})`);发现代码逻辑错误,应该用逻辑与 && 判断,而不是逻辑 ||
const bgUrl = localStorage.getItem('bg');
console.log(bgUrl);
bgUrl && (document.body.style.backgroundImage = `url(${bgUrl})`);点击右上角更换背景按钮后背景图片没有更改,再次返回浏览器控制台输出
undefined index.js:10
PUT http://hmajax.itheima.net/api/uploadimg 404 (Not Found)查看浏览器网络窗口,选择请求报文,看到请求报文为
------WebKitFormBoundaryMvWBHUPM6BkPn4RY
Content-Disposition: form-data; name="avatar"
undefined
------WebKitFormBoundaryMvWBHUPM6BkPn4RY--问题 1:undefined index.js:10,事件处理函数没有拿到图片文件,查看 index.js 文件
document.querySelector('.bg-ipt').addEventListener('click', (e) => {
// 1. 选择图片上传,设置 body 背景
console.log(e.target.files[0]);发现事件名写错,应该为 change
问题 2:PUT http://hmajax.itheima.net/api/uploadimg 404 (Not Found) 接口 404,查看接口文档:
http://hmajax.itheima.net/api/uploadimg - POST所以更改代码里的 PUT 请求为 POST 请求
axios({
url: 'http://hmajax.itheima.net/api/uploadimg',
method: 'POST',
data: fd,再次刷新浏览器,点击更换背景按钮上传图片后发现背景图片还是没有更换,查看源代码发现两处错误,
const imgUrl = result.data.data.url;
document.body.style.backgroundImage = imgUrl;
// 2. 上传成功时,"保存"图片 url 网址
localStorage.setItem('bgImg', imgUrl);
});
});
// 3. 网页运行后,"获取"url 网址使用
const bgUrl = localStorage.getItem('bg');url(${imgUrl})localStorage 时使用 bgImg 键名,而在取值时使用 bg 键名。正确代码为:
const imgUrl = result.data.data.url;
document.body.style.backgroundImage = `url(${imgUrl})`;
// 2. 上传成功时,"保存"图片 url 网址
localStorage.setItem('bgImg', imgUrl);
});
});
bgImg
// 3. 网页运行后,"获取"url 网址使用
const bgUrl = localStorage.getItem('bgImg');// 这个案例中有 6 处报错,改正后让代码正常完成更换背景图案例吧(刷新背景图也要在)
/**
* 目标:网站 - 更换背景
* 1. 选择图片上传,设置 body 背景
* 2. 上传成功时,"保存"图片 url 网址
* 3. 网页运行后,"获取"url 网址使用
* */
document.querySelector('.bg-ipt').addEventListener('click', (e) => {
// 1. 选择图片上传,设置 body 背景
console.log(e.target.files[0]);
const fd = new FormData();
fd.append('avatar', e.target.files[0]);
axios({
url: 'http://hmajax.itheima.net/api/uploadimg',
method: 'PUT',
data: fd,
}).then((result) => {
const imgUrl = result.data.data.url;
document.body.style.backgroundImage = imgUrl;
// 2. 上传成功时,"保存"图片 url 网址
localStorage.setItem('bgImg', imgUrl);
});
});
// 3. 网页运行后,"获取"url 网址使用
const bgUrl = localStorage.getItem('bg');
console.log(bgUrl);
bgUrl || (document.body.style.backgroundImage = `url(${bgUrl})`);// 这个案例中有 6 处报错,改正后让代码正常完成更换背景图案例吧(刷新背景图也要在)
/**
* 目标:网站 - 更换背景
* 1. 选择图片上传,设置 body 背景
* 2. 上传成功时,"保存"图片 url 网址
* 3. 网页运行后,"获取"url 网址使用
* */
document.querySelector('.bg-ipt').addEventListener('change', (e) => {
// 1. 选择图片上传,设置 body 背景
console.log(e.target.files[0]);
const fd = new FormData();
fd.append('avatar', e.target.files[0]);
axios({
url: 'http://hmajax.itheima.net/api/uploadimg',
method: 'POST',
data: fd,
}).then((result) => {
const imgUrl = result.data.data.url;
document.body.style.backgroundImage = `url(${imgUrl})`;
// 2. 上传成功时,"保存"图片 url 网址
localStorage.setItem('bgImg', imgUrl);
});
});
// 3. 网页运行后,"获取"url 网址使用
const bgUrl = localStorage.getItem('bgImg');
console.log(bgUrl);
bgUrl && (document.body.style.backgroundImage = `url(${bgUrl})`);数组的常用方法有哪些?
梳理建议,说几个常用的即可,回想下平时写代码常用的以及他们的功能和场景说出即可
详细参考 面试官:数组的常用方法有哪些?
请回答 == 和 === 的区别?
回流和重绘是什么?