AJAX初级
AJAX的概念:
-
使用浏览器的 XMLHttpRequest 对象 与服务器通信
-
浏览器网页中,使用 AJAX技术(XHR对象)发起获取省份列表数据的请求,服务器代码响应准备好的省份列表数据给前端,前端拿到数据数组以后,展示到网页
服务器可以展示理解为提供数据的一台电脑,学了AJAX,我们的数据就可以在服务器上获取,让数据变活。
怎么学 AJAX ?
-
这里使用一个第三方库叫 axios, 后续在学习 XMLHttpRequest 对象了解 AJAX 底层原理
-
因为 axios 库语法简单,让我们有更多精力关注在与服务器通信上,而且后续 Vue,React 学习中,也使用 axios 库与服务器通信
需求:从服务器获取省份列表数据,展示到页面上(体验 axios 语法的使用)
获取省份列表数据 - 目标资源地址:http://hmajax.itheima.net/api/province
axios 语法
引入 axios.js 文件到自己的网页中
axios.js文件链接: https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js
明确axios函数的使用语法
axios({url: '目标资源地址'}).then((result) => {// 对服务器返回的数据做后续处理})
注意:请求的 url 地址, 就是标记资源的网址
<!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>AJAX概念和axios使用</title>
</head><body><!--axios库地址:https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js省份数据地址:http://hmajax.itheima.net/api/province目标: 使用axios库, 获取省份列表数据, 展示到页面上1. 引入axios库--><p class="my-p"></p><script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script><script>// 2. 使用axios函数axios({url: 'http://hmajax.itheima.net/api/province'}).then(result => {console.log(result)// 好习惯:多打印,确认属性名console.log(result.data.list)console.log(result.data.list.join('<br>'))// 把准备好省份列表,插入到页面document.querySelector('.my-p').innerHTML = result.data.list.join('<br>') })</script>
</body></html>
URL
URL的概念:
统一资源定位符,简称网址,用于定位网络中的资源(资源指的是:网页,图片,数据,视频,音频等等)
URL的组成:
协议,域名,资源路径
http 协议:叫超文本传输协议,规定了浏览器和服务器传递数据的格式
域名:标记服务器在互联网当中的方位,网络中有很多服务器,你想访问哪一台,就需要知道它的域名才可以
资源路径:一个服务器内有多个资源,用于标识你要访问的资源具体的位置接下来做个需求,访问新闻列表的 URL 网址,打印新闻数据
新闻列表数据 URL 网址:http://hmajax.itheima.net/api/news
axios({url: 'http://hmajax.itheima.net/api/news'
}).then(result => {console.log(result)
})
url解释:从黑马服务器使用http协议,访问/api/news路径下的新闻列表资源
URL 查询参数
查询参数 :
-
携带给服务器额外信息,让服务器返回我想要的某一部分数据而不是全部数据
-
举例:查询河北省下属的城市列表,需要先把河北省传递给服务器
查询参数的语法:
-
在 url 网址后面用?拼接格式:XXXX?参数名1=值1&参数名2=值
-
参数名一般是后端规定的,值前端看情况传递即可
axios 如何携带查询参数:
使用 params 选项即可
axios({url: '目标资源地址',params: {参数名: 值}
}).then(result => {// 对服务器返回的数据做后续处理
})
查询城市列表的 url地址:http://hmajax.itheima.net/api/city
参数名:pname (值要携带省份名字)
获取“河北省”下属的城市列表,展示到页面,对应代码:
<!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>查询参数</title>
</head>
<body><!-- 城市列表: http://hmajax.itheima.net/api/city参数名: pname值: 省份名字--><p></p><script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script><script>axios({url: 'http://hmajax.itheima.net/api/city',// 查询参数params: {pname: '辽宁省'}}).then(result => {console.log(result.data.list)document.querySelector('p').innerHTML = result.data.list.join('<br>')})</script>
</body>
</html>
案例-查询-地区列表
-
需求:根据输入的省份名字和城市名字,查询下属地区列表相关参数
查询地区: http://hmajax.itheima.net/api/area
参数名:
pname:省份名字
cname:城市名字
/*获取地区列表: http://hmajax.itheima.net/api/area查询参数:pname: 省份或直辖市名字cname: 城市名字*/
// 目标: 根据省份和城市名字, 查询地区列表
// 1. 查询按钮-点击事件
document.querySelector('.sel-btn').addEventListener('click', () => {// 2. 获取省份和城市名字let pname = document.querySelector('.province').valuelet cname = document.querySelector('.city').value// 3. 基于axios请求地区列表数据axios({url: 'http://hmajax.itheima.net/api/area',params: {pname,cname}}).then(result => {// console.log(result)// 4. 把数据转li标签插入到页面上let list = result.data.listconsole.log(list)let theLi = list.map(areaName => `<li class="list-group-item">${areaName}</li>`).join('')console.log(theLi)document.querySelector('.list-group').innerHTML = theLi})
})
常用请求方法和数据提交
想要提交数据,先来了解什么是请求方法:
-
请求方法是一些固定单词的英文,例如:GET,POST,PUT,DELETE,PATCH(这些都是http协议规定的),每个单词对应一种对服务器资源要执行的
-
GET:获取数据
-
POST:数据提交
-
PUT:修改数据(全部)
-
DELETE:删除数据
-
PATCH:修改数据(部分)
-
前面我们获取数据其实用的就是GET请求方法,但是axios内部设置了默认请求方法就是GET,我们就没有写
-
但是提交数据需要使用POST请求方法
什么时候进行数据提交:
例如:多端要查看同一份订单数据,或者使用同一个账号进行登录,那订单/用户名+密码,就需要保存在服务器上,随时随地进行访问
axios 如何提交数据到服务器:
需要学习,method 和 data 这2个新的选项了(大家不用担心,这2个学完,axios常用的选项就都学完了)
axios({url: '目标资源地址',method: '请求方法',data: {参数名: 值}
}).then(result => {// 对服务器返回的数据做后续处理
})
需求:注册账号,提交用户名和密码到服务器保存:
注册用户 URL 网址:http://hmajax.itheima.net/api/register
请求方法:POST
参数名:
username:用户名(要求中英文和数字组成,最少8位)
password:密码(最少6位)
/*注册用户:http://hmajax.itheima.net/api/register请求方法:POST参数名:username:用户名(中英文和数字组成,最少8位)password:密码 (最少6位)目标:点击按钮,通过axios提交用户和密码,完成注册
*/
document.querySelector('.btn').addEventListener('click', () => {axios({url: 'http://hmajax.itheima.net/api/register',method: 'POST',data: {username: 'itheima007',password: '7654321'}})
})
请求方法最常用的是:
POST 提交数据,GET 查询数据
axios 的核心配置项:
url:目标资源地址,method:请求方法,params:查询参数,data:提交的数据
axios 错误处理
如果注册相同的用户名,则会遇到注册失败的请求,也就是 axios 请求响应失败了,你会在控制台看到如图的错误:
-
在 axios 语法中要如何处理呢?
-
因为,普通用户不会去控制台里看错误信息,我们要编写代码拿到错误并展示给用户在页面上
-
-
使用 axios 的 catch 方法,捕获这次请求响应的错误并做后续处理,语法如下:
axios({// ...请求选项}).then(result => {// 处理成功数据}).catch(error => {// 处理失败错误})
-
需求:再次重复注册相同用户名,提示用户注册失败的原因
document.querySelector('.btn').addEventListener('click', () => {axios({url: 'http://hmajax.itheima.net/api/register',method: 'post',data: {username: 'itheima007',password: '7654321'}}).then(result => {// 成功console.log(result)}).catch(error => {// 失败// 处理错误信息console.log(error)console.log(error.response.data.message)alert(error.response.data.message)}) })
HTTP 协议-请求报文
HTTP 协议规定了浏览器和服务器返回内容的格式
请求报文:是浏览器按照协议规定发送给服务器的内容,例如刚刚注册用户时,发起的请求报文:
-
这里的格式包含:
- 请求行:请求方法,URL,协议
- 请求头:以键值对的格式携带的附加信息,比如:Content-Type(指定了本次传递的内容类型)
- 空行:分割请求头,空行之后的是发送给服务器的资源
- 请求体:发送的资源
-
我们切换到浏览器中,来看看刚才注册用户发送的这个请求报文以及内容去哪里查看呢
-
代码:直接在上个代码基础上复制,然后运行查看请求报文对应关系即可
-
浏览器发送给服务器的内容叫做,请求报文
-
请求报文的组成是什么?
请求行,请求头,空行,请求体 -
通过 Chrome 的网络面板如何查看请求体?
请求报文-错误排查
学习了查看请求报文可以用来确认我们代码发送的请求数据是否真的正确
HTTP 协议-响应报文
响应报文:是服务器按照协议固定的格式,返回给浏览器的内容
-
响应报文的组成:
- 响应行(状态行):协议,HTTP响应状态码,状态信息
- 响应头:以键值对的格式携带的附加信息,比如:Content-Type(告诉浏览器,本次返回的内容类型)
- 空行:分割响应头,控制之后的是服务器返回的资源
- 响应体:返回的资源
HTTP 响应状态码:
-
用来表明请求是否成功完成
-
例如:404(客户端要找的资源,在服务器上不存在)
接口文档
-
接口文档:描述接口的文章(一般是后端工程师,编写和提供)
-
接口:指的使用 AJAX 和 服务器通讯时,使用的 URL,请求方法,以及参数,例如:AJAX阶段接口文档
-
例如:获取城市列表接口样子
需求:打开 AJAX 阶段接口文档,查看登录接口,并编写代码,完成一次登录的效果
document.querySelector('.btn').addEventListener('click', () => {// 用户登录axios({url: 'http://hmajax.itheima.net/api/login',method: 'post',data: {username: 'itheima007',password: '7654321'}})
})
案例-用户登录-主要业务
-
需求:编写代码,查看接口文档,填写相关信息,完成登录业务
-
分析实现的步骤
-
点击登录,获取并判断用户名和长度
-
提交数据和服务器通信
-
提示信息,反馈给用户
// 目标1:点击登录时,用户名和密码长度判断,并提交数据和服务器通信// 1.1 登录-点击事件
document.querySelector('.btn-login').addEventListener('click', () => {// 1.2 获取用户名和密码const username = document.querySelector('.username').valueconst password = document.querySelector('.password').value// console.log(username, password)// 1.3 判断长度if (username.length < 8) {console.log('用户名必须大于等于8位')return // 阻止代码继续执行}if (password.length < 6) {console.log('密码必须大于等于6位')return // 阻止代码继续执行}// 1.4 基于axios提交用户名和密码// console.log('提交数据到服务器')axios({url: 'http://hmajax.itheima.net/api/login',method: 'POST',data: {username,password}}).then(result => {console.log(result)console.log(result.data.message)}).catch(error => {console.log(error)console.log(error.response.data.message)})
})
总结下用户登录案例的思路:
1. 登录按钮-绑定点击事件 2. 从页面输入框里,获取用户名和密码 3. 判断长度是否符合要求 4. 基于 axios 提交用户名和密码
案例-用户登录-提示信息
需求:使用提前准备好的提示框,来把登录成功/失败结果提示给用户
-
使用提示框,反馈提示消息,因为有4处地方需要提示框,所以封装成函数
-
获取提示框
-
封装提示框函数,重复调用,满足提示需求
功能:
-
显示提示框
-
不同提示文字msg,和成功绿色失败红色isSuccess参数(true成功,false失败)
-
过2秒后,让提示框自动消失
-
-
对应提示框核心代码:
/*** 2.2 封装提示框函数,重复调用,满足提示需求* 功能:* 1. 显示提示框* 2. 不同提示文字msg,和成功绿色失败红色isSuccess(true成功,false失败)* 3. 过2秒后,让提示框自动消失
*/
function alertFn(msg, isSuccess) {// 1> 显示提示框myAlert.classList.add('show')// 2> 实现细节myAlert.innerText = msgconst bgStyle = isSuccess ? 'alert-success' : 'alert-danger'myAlert.classList.add(bgStyle)// 3> 过2秒隐藏setTimeout(() => {myAlert.classList.remove('show')// 提示:避免类名冲突,重置背景色myAlert.classList.remove(bgStyle)}, 2000)
}
form-serialize 插件
使用 form-serialize 插件,快速收集目标表单范围内表单元素的值
-
我们前面收集表单元素的值,是一个个标签获取的
-
如果一套表单里有很多很多表单元素,如何一次性快速收集出来呢?
-
使用 form-serialize 插件提供的 serialize 函数就可以办到
-
form-serialize 插件语法:
-
引入 form-serialize 插件到自己网页中
-
使用 serialize 函数
-
参数1:要获取的 form 表单标签对象(要求表单元素需要有 name 属性-用来作为收集的数据中属性名)
-
参数2:配置对象
-
hash:
-
true - 收集出来的是一个 JS 对象结构
-
false - 收集出来的是一个查询字符串格式
-
-
empty:
-
true - 收集空值
-
false - 不收集空值
-
-
-
-
-
需求:收集登录表单里用户名和密码
<!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>form-serialize插件使用</title>
</head><body><form action="javascript:;" class="example-form"><input type="text" name="username"><br><input type="text" name="password"><br><input type="button" class="btn" value="提交"></form><!-- 目标:在点击提交时,使用form-serialize插件,快速收集表单元素值1. 把插件引入到自己网页中--><script src="./lib/form-serialize.js"></script><script>document.querySelector('.btn').addEventListener('click', () => {/*** 2. 使用serialize函数,快速收集表单元素的值* 参数1:要获取哪个表单的数据* 表单元素设置name属性,值会作为对象的属性名* 建议name属性的值,最好和接口文档参数名一致* 参数2:配置对象* hash 设置获取数据结构* - true:JS对象(推荐)一般请求体里提交给服务器* - false: 查询字符串* empty 设置是否获取空值* - true: 获取空值(推荐)数据结构和标签结构一致* - false:不获取空值*/const form = document.querySelector('.example-form')const data = serialize(form, { hash: true, empty: true })// const data = serialize(form, { hash: false, empty: true })// const data = serialize(form, { hash: true, empty: false })console.log(data)})</script>
</body></html>
用户登录-form-serialize
-
基于模板代码,使用 form-serialize 插件来收集用户名和密码
-
在原来的代码基础上修改即可
-
先引入插件
<!-- 3.1 引入插件 --><script src="./lib/form-serialize.js"></script>
-
案例_图书管理-介绍
介绍要完成的增删改查业务效果和 Bootstrap 弹框使用
分析步骤和对应的视频模块
-
先学习 Bootstrap 弹框的使用(因为添加图书和编辑图书需要这个窗口来承载图书表单)
-
先做渲染图书列表(这样做添加和编辑以及删除可以看到数据变化,所以先做渲染)
-
再做新增图书功能
-
再做删除图书功能
-
再做编辑图书功能(注意:编辑和新增图书是2套弹框-后续做项目我们再用同1个弹框)
Bootstrap 弹框_属性控制
使用属性方式控制 Bootstarp 弹框的显示和隐藏
什么是 Bootstrap 弹框?
-
不离开当前页面,显示单独内容,供用户操作
需求:使用 Bootstrap 弹框,先做个简单效果,点击按钮,让弹框出现,点击 X 和 Close 让弹框隐藏
如何使用 Bootstrap 弹框呢?
-
先引入 bootstrap.css 和 bootstrap.js 到自己网页中
-
准备弹框标签,确认结构(可以从 Bootstrap 官方文档的 Modal 里复制基础例子)- 运行到网页后,逐一对应标签和弹框每个部分对应关系
-
通过自定义属性,通知弹框的显示和隐藏,语法如下:
<button data-bs-toggle="modal" data-bs-target="css选择器">显示弹框
</button><button data-bs-dismiss="modal">Close</button>
<!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>Bootstrap 弹框</title><!-- 引入bootstrap.css --><link href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.2/dist/css/bootstrap.min.css" rel="stylesheet">
</head><body><!-- 目标:使用Bootstrap弹框1. 引入bootstrap.css 和 bootstrap.js2. 准备弹框标签,确认结构3. 通过自定义属性,控制弹框的显示和隐藏--><button type="button" class="btn btn-primary" data-bs-toggle="modal" data-bs-target=".my-box">显示弹框</button><!-- 弹框标签bootstrap的modal弹框,添加modal类名(默认隐藏)--><div class="modal my-box" tabindex="-1"><div class="modal-dialog"><!-- 弹框-内容 --><div class="modal-content"><!-- 弹框-头部 --><div class="modal-header"><h5 class="modal-title">Modal title</h5><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="https://cdn.jsdelivr.net/npm/bootstrap@5.2.2/dist/js/bootstrap.min.js"></script>
</body></html>
Bootstrap 弹框_JS控制
使用 JS 方式控制 Bootstarp 弹框的显示和隐藏
为什么需要 JS 方式控制呢?
-
当我显示之前,隐藏之前,需要执行一些 JS 逻辑代码,就需要引入 JS 控制弹框显示/隐藏的方式了
-
例如:
-
点击编辑姓名按钮,在弹框显示之前,在输入框填入默认姓名
-
点击保存按钮,在弹框隐藏之前,获取用户填入的名字并打印
-
// 1. 创建弹框对象
const modalDom = document.querySelector('.name-box')
const modal = new bootstrap.Modal(modalDom)// 编辑姓名->点击->赋予默认姓名->弹框显示
document.querySelector('.edit-btn').addEventListener('click', () => {document.querySelector('.username').value = '默认姓名'// 2. 显示弹框modal.show()
})// 保存->点击->->获取姓名打印->弹框隐藏
document.querySelector('.save-btn').addEventListener('click', () => {const username = document.querySelector('.username').valueconsole.log('模拟把姓名保存到服务器上', username)// 2. 隐藏弹框modal.hide()
})
直接出现/隐藏用属性方式控制,如果需要先执行一段 JS 逻辑再显示/隐藏就用 JS 方式控制
案例_图书管理_渲染列表
基于 axios 获取到图书列表数据,并用 JS 代码渲染数据,到准备好的模板标签中
步骤:
-
获取数据
-
渲染数据
我们所有人数据都来自同一个服务器上,为了区分每个同学不同的数据,需要大家设置一个外号告诉服务器,服务器就会返回你对应的图书数据了
因为默认展示列表,新增,修改,删除后都要重新获取并刷新列表,所以把获取数据渲染数据的代码封装在一个函数内,方便复用
/*** 目标1:渲染图书列表* 1.1 获取数据* 1.2 渲染数据*/
const creator = '老张'
// 封装-获取并渲染图书列表函数
function getBooksList() {// 1.1 获取数据axios({url: 'http://hmajax.itheima.net/api/books',params: {// 外号:获取对应数据creator}}).then(result => {// console.log(result)const bookList = result.data.data// console.log(bookList)// 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('')// console.log(htmlStr)document.querySelector('.list').innerHTML = htmlStr})
}
// 网页加载运行,获取并渲染列表一次
getBooksList()
案例_图书管理_新增图书
点击添加按钮,出现准备好的新增图书弹框,填写图书信息提交到服务器保存,并更新图书列表
步骤:
-
新增弹框(控制显示和隐藏)(基于 Bootstrap 弹框和准备好的表单-用属性和 JS 方式控制)
-
在点击保存按钮时,收集数据&提交保存
-
刷新-图书列表(重新调用下之前封装的获取并渲染列表的函数)
/*** 目标2:新增图书* 2.1 新增弹框->显示和隐藏* 2.2 收集表单数据,并提交到服务器保存* 2.3 刷新图书列表*/
// 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 })// console.log(bookObj)// 提交到服务器axios({url: 'http://hmajax.itheima.net/api/books',method: 'POST',data: {...bookObj,creator}}).then(result => {// console.log(result)// 2.3 添加成功后,重新请求并渲染图书列表getBooksList()// 重置表单addForm.reset()// 隐藏弹框addModal.hide()})
})
案例_图书管理_删除图书
点击图书删除元素,删除当前图书数据
步骤:
-
给删除元素,绑定点击事件(事件委托方式并判断点击的是删除元素才走删除逻辑代码),并获取到要删除的数据id
-
基于 axios 和接口文档,调用删除接口,让服务器删除这条数据
-
重新获取并刷新图书列表
/*** 目标3:删除图书* 3.1 删除元素绑定点击事件->获取图书id* 3.2 调用删除接口* 3.3 刷新图书列表*/
// 3.1 删除元素->点击(事件委托)
document.querySelector('.list').addEventListener('click', e => {// 获取触发事件目标元素// console.log(e.target)// 判断点击的是删除元素if (e.target.classList.contains('del')) {// console.log('点击删除元素')// 获取图书id(自定义属性id)const theId = e.target.parentNode.dataset.id// console.log(theId)// 3.2 调用删除接口axios({url: `http://hmajax.itheima.net/api/books/${theId}`,method: 'DELETE'}).then(() => {// 3.3 刷新图书列表getBooksList()})}
})
案例_图书管理_编辑图书
完成编辑图书回显当前图书数据到编辑表单,在用户点击修改按钮,收集数据提交到服务器保存,并刷新列表
-
编辑数据的核心思路:
-
给编辑元素,绑定点击事件(事件委托方式并判断点击的是编辑元素才走编辑逻辑代码),并获取到要编辑的数据id
-
基于 axios 和接口文档,调用查询图书详情接口,获取正在编辑的图书数据,并回显到表单中(页面上的数据是在用户的浏览器中不够准备,所以只要是查看数据都要从服务器获取)
-
收集并提交保存修改数据,并重新从服务器获取列表刷新页面
-
/*** 目标4:编辑图书* 4.1 编辑弹框->显示和隐藏* 4.2 获取当前编辑图书数据->回显到编辑表单中* 4.3 提交保存修改,并刷新列表*/
// 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.idaxios({url: `http://hmajax.itheima.net/api/books/${theId}`}).then(result => {const bookObj = result.data.data// document.querySelector('.edit-form .bookname').value = bookObj.bookname// document.querySelector('.edit-form .author').value = bookObj.author// 数据对象“属性”和标签“类名”一致// 遍历数据对象,使用属性去获取对应的标签,快速赋值const keys = Object.keys(bookObj) // ['id', 'bookname', 'author', 'publisher']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({url: `http://hmajax.itheima.net/api/books/${id}`,method: 'PUT',data: {bookname,author,publisher,creator}}).then(() => {// 修改成功以后,重新获取并刷新列表getBooksList()// 隐藏弹框editModal.hide()})
})
案例_图书管理_总结
因为增删改查的业务在前端实际开发中非常常见,思路是可以通用的,所以总结下思路
1.渲染列表(查)
2.新增图书(增)
3.删除图书(删)
4.编辑图书(改)
相关文章:

AJAX初级
AJAX的概念: 使用浏览器的 XMLHttpRequest 对象 与服务器通信 浏览器网页中,使用 AJAX技术(XHR对象)发起获取省份列表数据的请求,服务器代码响应准备好的省份列表数据给前端,前端拿到数据数组以后…...
重载大于号运算符,比较复数大小
本题目要求编写代码的功能为: 输入两个复数(变量名自拟),比较复数模的大小,复数实部与虚部都是整数 要求输入时输入4个整数,分别代表复数1的实部、虚部,复数2的实部虚部 输入格式: 在同一行中输…...

go ast语义分析实现指标计算器
什么是AST 首先我们要知道AST是什么(Abstract Syntax Tree,AST),简称为语法树,是go语言源代码语法结构的一种抽象表示。它以树状的形式表现编程语言的语法结构,树上的每个节点都表示源代码中的一种结构。 …...
【Vue】组件间传参与方法调用
【前言】 … 【目标】 1 了解组件间传参 2 组件间自定义事件绑定与解绑 3 组件的事件总线 4 消息订阅与发布 一 组件间传参 1 props 引入并使用组件:传递参数 <template><div id="app"><HelloWorld :msg="msg" :name="name" …...
类和对象2
三、C对象模型和this指针 3.1 成员变量和成员函数分开存储 在C中,类内的成员变量和成员函数分开存储,只有非静态成员变量才属于类的对象上 #define _CRT_SECURE_NO_WARNINGS 1 #include <iostream> #include <string.h> using namespace …...

Linux系统命令traceroute详解(语法、选项、原理和实例)
目录 一、traceroute概述 二、语法 1、基本语法 2、命令选项 三、帮助信息 四、示例 1. 使用默认模式(ICMP Echo)追踪到目标主机 2. 使用UDP模式(需要root权限)追踪到目标主机 3. 不解析IP地址为主机名,直接显…...

中兴通讯助力中国移动,推动SPN AI节能技术于23省规模部署
SPN作为中国移动自主创新的新一代综合承载网络,相比PTN设备,SPN的单机容量及性能有大幅提升,整机功耗也相应变大。在当前国家双碳政策的目标下,SPN设备的节能降耗也日益成为中国移动关注的焦点。因此,中国移动选择与中…...
SQL Server--死锁
今天,客户反应打不开xxx页面了。好家伙肯定锁表了。。。。。 只能先吧死锁进程先kill掉,不能耽误客户生产环境运行。。。。。 一定要看看是那张表发生了死锁 1、查询死锁语句 select dbid,* from sys.sysprocesses where 11 and spid >50 and blo…...

中科蓝讯AB32VG1中文寄存器说明GPIO端口操作
1 GPIO管理 1.1 GPIO通用控制寄存器 寄存器 1- 1 GPIOA:端口 A 数据寄存器 位寄存器名模式缺省描述31:8---未使用7:0GPIOA写0x00PAx 数据。当 PAx 用作 GPIO 时有效 0:读取时PAx为输入低电平状态,写入时PAx为输出低电平; 1:PAx…...

如何查看热门GPT应用?
1、登陆chatgpt 2、访问 https://chatgpt.com/gpts 3、在该界面,可以搜索并使用image generator, Write For Me,Language Teature等热门应用。...
C++中的各种定义
文章目录 前言一、1、unsigned2、_countof、sizeof 总结 前言 一、 1、unsigned 在C语言中,"unsigned"是一个数据类型修饰符,用于修饰整数类型,表示该类型的变量只能存储非负整数,即无符号整数。它可以应用于char、s…...
Java面向对象-常用类(日期时间类)
常用类-日期时间类 Date(java.util.Date) – 日期类 SimpleDateFormat – 格式化日期类 Calendar – 日历类 1 Date类 java.util.Date类表示特定的瞬间,精确到毫秒。 package com.qf.datetime;import java.util.Date;public class Test01 {…...

Shell环境变量深入:自定义系统环境变量
Shell环境变量深入:自定义系统环境变量 目标 能够自定义系统级环境变量 全局配置文件/etc/profile应用场景 当前用户进入Shell环境初始化的时候会加载全局配置文件/etc/profile里面的环境变量, 供给所有Shell程序使用 以后只要是所有Shell程序或命令使用的变量…...

【C++课程学习】:命名空间的理解(图文详解)
🎁个人主页:我们的五年 🔍系列专栏:C课程学习 🎉欢迎大家点赞👍评论📝收藏⭐文章 目录 📷1.命名冲突 📷2.重定义 📷3.命名空间 🍺命名空间可…...

鸿蒙ArkUI-X平台差异化:【运行态差异化(@ohos.deviceInfo)】
平台差异化 简介 跨平台使用场景是一套ArkTS代码运行在多个终端设备上,如Android、iOS、OpenHarmony(含基于OpenHarmony发行的商业版,如HarmonyOS Next)。当不同平台业务逻辑不同,或使用了不支持跨平台的API…...
蓝牙Mesh模块组网时无线回程影响速率吗?
随着科技的发展,智能家居、智能办公等场景越来越广泛地应用于我们的生活。其中,蓝牙Mesh组网技术作为一种新型的无线通信技术,受到了越来越多用户的关注。那么,蓝牙Mesh模块在组网时无线回程过程中是否会影响速率呢?本…...

将3D检测的box框投影到BEV图片上
前言 点云数据作为一种丰富的三维空间信息表达方式,通常用于自动驾驶、机器人导航和三维建模等领域。然而,点云数据的直观性不如二维图像,这限制了它在一些需要快速视觉反馈的应用场景中的使用。本文将探讨如何将点云数据转换为二维图像&…...
Flutter 中的 ClipOval 小部件:全面指南
Flutter 中的 ClipOval 小部件:全面指南 在Flutter的丰富布局库中,ClipOval是一个用于裁剪子组件的显示区域为椭圆形或圆形的小部件。这种裁剪效果可以用于创建头像、图标或其他图形元素的美观边框。本文将提供ClipOval的全面指南,帮助你了解…...
ubuntu 硬盘转移
我插了两个 文件系统: ubuntu 硬盘转移: sudo dd if/dev/sdX1 of/dev/sdY1 bs128K convnoerror,sync statusprogressdd 的意思是DiskToDisk,if 是输入文件系统,of是输出文件系统。 bs是每次传递的数据大小。 注意:接…...
three.js中使用CameraHelper来可视化调整阴影相机的范围
1. three.js中使用CameraHelper来可视化调整阴影相机的范围 光源 const directionLight new THREE.DirectionalLight(0xffffff, 1); directionLight.position.set(100, 60, 20); directionLight.castShadow true; scene.add(directionLight);设置计算阴影的范围 direction…...
云原生核心技术 (7/12): K8s 核心概念白话解读(上):Pod 和 Deployment 究竟是什么?
大家好,欢迎来到《云原生核心技术》系列的第七篇! 在上一篇,我们成功地使用 Minikube 或 kind 在自己的电脑上搭建起了一个迷你但功能完备的 Kubernetes 集群。现在,我们就像一个拥有了一块崭新数字土地的农场主,是时…...
树莓派超全系列教程文档--(62)使用rpicam-app通过网络流式传输视频
使用rpicam-app通过网络流式传输视频 使用 rpicam-app 通过网络流式传输视频UDPTCPRTSPlibavGStreamerRTPlibcamerasrc GStreamer 元素 文章来源: http://raspberry.dns8844.cn/documentation 原文网址 使用 rpicam-app 通过网络流式传输视频 本节介绍来自 rpica…...

3.3.1_1 检错编码(奇偶校验码)
从这节课开始,我们会探讨数据链路层的差错控制功能,差错控制功能的主要目标是要发现并且解决一个帧内部的位错误,我们需要使用特殊的编码技术去发现帧内部的位错误,当我们发现位错误之后,通常来说有两种解决方案。第一…...

UDP(Echoserver)
网络命令 Ping 命令 检测网络是否连通 使用方法: ping -c 次数 网址ping -c 3 www.baidu.comnetstat 命令 netstat 是一个用来查看网络状态的重要工具. 语法:netstat [选项] 功能:查看网络状态 常用选项: n 拒绝显示别名&#…...

为什么需要建设工程项目管理?工程项目管理有哪些亮点功能?
在建筑行业,项目管理的重要性不言而喻。随着工程规模的扩大、技术复杂度的提升,传统的管理模式已经难以满足现代工程的需求。过去,许多企业依赖手工记录、口头沟通和分散的信息管理,导致效率低下、成本失控、风险频发。例如&#…...

屋顶变身“发电站” ,中天合创屋面分布式光伏发电项目顺利并网!
5月28日,中天合创屋面分布式光伏发电项目顺利并网发电,该项目位于内蒙古自治区鄂尔多斯市乌审旗,项目利用中天合创聚乙烯、聚丙烯仓库屋面作为场地建设光伏电站,总装机容量为9.96MWp。 项目投运后,每年可节约标煤3670…...

【Zephyr 系列 10】实战项目:打造一个蓝牙传感器终端 + 网关系统(完整架构与全栈实现)
🧠关键词:Zephyr、BLE、终端、网关、广播、连接、传感器、数据采集、低功耗、系统集成 📌目标读者:希望基于 Zephyr 构建 BLE 系统架构、实现终端与网关协作、具备产品交付能力的开发者 📊篇幅字数:约 5200 字 ✨ 项目总览 在物联网实际项目中,**“终端 + 网关”**是…...
C++中string流知识详解和示例
一、概览与类体系 C 提供三种基于内存字符串的流,定义在 <sstream> 中: std::istringstream:输入流,从已有字符串中读取并解析。std::ostringstream:输出流,向内部缓冲区写入内容,最终取…...

select、poll、epoll 与 Reactor 模式
在高并发网络编程领域,高效处理大量连接和 I/O 事件是系统性能的关键。select、poll、epoll 作为 I/O 多路复用技术的代表,以及基于它们实现的 Reactor 模式,为开发者提供了强大的工具。本文将深入探讨这些技术的底层原理、优缺点。 一、I…...
【C++从零实现Json-Rpc框架】第六弹 —— 服务端模块划分
一、项目背景回顾 前五弹完成了Json-Rpc协议解析、请求处理、客户端调用等基础模块搭建。 本弹重点聚焦于服务端的模块划分与架构设计,提升代码结构的可维护性与扩展性。 二、服务端模块设计目标 高内聚低耦合:各模块职责清晰,便于独立开发…...