写在开始
学习完了前端三件套(HTML、CSS、JavaScript),
在进行框架学习之前,
我们还需要学习一些前置知识,
在当下,我们将初步进行“前后端交互”、感知“前端工程化”;
在未来,它将伴随,并推进,整个的前端框架学习过程;
……
我们继续跟随黑马网课,打下框架学习基础。本次学习的是:
我是Capybara,您的前端学习伙伴,高级网课品鉴官,前端学习测评家
不达目的不放弃,追逐理想的过程本身就难能可贵。
AJAX入门——让数据“活”起来
AJAX 概念和 axios 使用
浏览器大家不陌生,服务器可以暂时理解为一台“提供数据”的电脑(一台二十四小时不关机的电脑)。
我们可以在浏览器的网页中使用AJAX相关对应的代码,
运行时,将会发出一次“请求”(让服务器满足我的要求——例如我要一份省份列表数据),
数据不再直接嵌在代码里,而是从服务器返回,
因此称数据“活”起来了。
如何使用AJAX —— 可以使用封装好的axios库
axios语法(使用到promise,后续讲解)
需要使用到网络地址
直接点击网址可在浏览器访问到,返回一个对象结构的json字符串
message是提示信息,list才是省份列表数据
打印返回结果result,result为一个对象,其中data属性为服务器返回真正数据。
我们可以通过result.data.list拿到省份列表数据
获取到数据后,数组转字符串(join方法)并插入换行符(<br>),
便可展示到元素上
实践代码:
<!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的组成:协议 + 域名 + 资源路径
协议——规定了浏览器和服务器之间传输数据的格式
域名——指出访问的是哪一台服务器电脑
资源路径——标识访问文件在服务器电脑当中的具体位置
尝试获取新闻列表数据
URL 查询参数
在axios中,查询参数写到params选项中
不同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>
日常常见的功能,比如设置籍贯,可以选择省份,城市,地区,三级选择。
本案例选择省份和城市,展示地区。
要携带多个参数
对象增强写法(ES6):变量名和属性名相同时,可简写
params: {
pname,
cname
}
实践代码:
<!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> <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css"> <style> :root { font-size: 15px; } body { padding-top: 15px; } </style> </head> <body> <div class="container"> <form id="editForm" class="row"> <!-- 输入省份名字 --> <div class="mb-3 col"> <label class="form-label">省份名字</label> <input type="text" value="北京" name="province" class="form-control province" placeholder="请输入省份名称" /> </div> <!-- 输入城市名字 --> <div class="mb-3 col"> <label class="form-label">城市名字</label> <input type="text" value="北京市" name="city" class="form-control city" placeholder="请输入城市名称" /> </div> </form> <button type="button" class="btn btn-primary sel-btn">查询</button> <br><br> <p>地区列表: </p> <ul class="list-group"> <!-- 示例地区 --> <li class="list-group-item">东城区</li> </ul> </div> <script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script> <script> /* 获取地区列表: http://hmajax.itheima.net/api/area 查询参数: pname: 省份或直辖市名字 cname: 城市名字 */ // 目标: 根据省份和城市名字, 查询地区列表 // 1. 查询按钮-点击事件 document.querySelector('.sel-btn').addEventListener('click', () => { // 2. 获取省份和城市名字 let pname = document.querySelector('.province').value let 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.list console.log(list) let theLi = list.map(areaName => `<li class="list-group-item">${areaName}</li>`).join('') console.log(theLi) document.querySelector('.list-group').innerHTML = theLi }) }) </script> </body> </html>
常用请求方法和数据提交
前面都是从服务器“拿”(获取)数据,
怎样把数据“存”(提交、保存)到服务器呢?
什么情况需要提交数据?
注意区分:params和data
method不区分大小写,get可以省略,属性值为字符串,记得加上引号
数据提交场景——注册账号
实操代码:
<!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> <button class="btn">注册用户</button> <script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script> <script> /* 注册用户: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' } }) }) </script> </body> </html>
重复提交相同数据,会提示账号被占用:
总结
axios 错误处理
想要把错误信息展示给用户(用户不会去查看控制台)
在axios的then方法后使用catch方法,
当出现axios错误时,控制台一共会出现两段错误信息,
第一段(上面一段)为浏览器报错,它是没有服务器返回的错误原因
不管它
而在下面一段(第二段)是axios捕获(catch)到的错误信息
是一个对象,
在response属性的data属性,有报错原因
我们要取到它,再反馈给用户
通过catch方法捕获错误信息(错误信息传至形参error)
(错误信息不再爆红,之前爆红 显示Uncaught(in pormise),未捕获)
把错误原因取出error.response.data.message
用提示框提示用户alert
HTTP协议-报文
报文中有一些自动生成的,
也有一些对应着axios的选项设置,比如post方法,url,
其中Content-Type: application/json规定的是这次请求携带的数据类型
一个空行后面,就是携带的json字符串了
axios在运行时会把代码中的data对象转成json字符串携带到请求报文中。
请求报文的组成部分/格式
自己(程序员)如何查看这些请求信息?——浏览器
发送请求之后,
网络-->fetch/XHR-->选中某一个请求-->标头(看请求头,载荷看请求体)-->点击查看源代码(点击后变成查看解析结果)
部分内容(协议 http://)经浏览器格式化
总结:
报文一共有四个部分:
请求行、请求头、空行、请求体
请求报文-错误排查
在登录时,报错“用户名或密码错误”,如何排查错误?
把input框type改成text可以看到密码
查看请求报文,发现所传密码有误
原来是在代码中,获取密码框出现错误
HTTP 协议-响应报文
响应报文也分成四部分,
其中响应行中携带HTTP响应状态码
响应状态码表示请求是否成功
关注2和4开头的(200、404)
客户端错误,客户端可以理解为浏览器
通过代码发送请求后,这次要查看的是“响应”标头
响应头(携带额外信息)
响应体
实操代码:
<!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>HTTP协议_响应报文</title> </head> <body> <button class="btn">注册用户</button> <script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script> <script> /* 注册用户: http://hmajax.itheima.net/api/register 请求方法: POST 参数名: username: 用户名 (中英文和数字组成, 最少8位) password: 密码 (最少6位) 目标: 点击按钮, 通过axios提交用户和密码, 完成注册 需求: 使用axios错误处理语法, 拿到报错信息, 弹框反馈给用户 */ document.querySelector('.btn').addEventListener('click', () => { axios({ url: 'http://hmajax.itheima.net/api/registrweer1ddd', 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) }) }) </script> </body> </html>
总结
接口文档
文档内容与代码相对应
application/json是
后端告诉我们,这一次提交的请求体数据需要json字符串
我们传入的不是data对象吗?
axios源码发现data属性值为对象,内部会把对象转成json字符串,携带给服务器
已注册,实操登录
对照接口文档,填入相关信息:url、请求方法、请求体数据
没有使用then方法捕获,但可以在浏览器中直接查看响应
查看请求载荷(请求体)(需要查看源代码),发现已经转成json字符串。
总结:接口文档是后端提供的描述接口的文章
案例-用户登录
面对嵌套多层的对象,可以在浏览器中找到需要的属性并右键,选择复制属性路径
error. 然后粘贴
实操代码:
<!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> <!-- 引入bootstrap.css --> <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.2/dist/css/bootstrap.min.css"> <!-- 公共 --> <style> html, body { background-color: #EDF0F5; width: 100%; height: 100%; display: flex; justify-content: center; align-items: center; } .container { width: 520px; height: 540px; background-color: #fff; padding: 60px; box-sizing: border-box; } .container h3 { font-weight: 900; } </style> <!-- 表单容器和内容 --> <style> .form_wrap { color: #8B929D !important; } .form-text { color: #8B929D !important; } </style> <!-- 提示框样式 --> <style> .alert { transition: .5s; opacity: 0; } .alert.show { opacity: 1; } </style> </head> <body> <div class="container"> <h3>欢迎-登录</h3> <!-- 登录结果-提示框 --> <div class="alert alert-success" role="alert"> 提示消息 </div> <!-- 表单 --> <div class="form_wrap"> <form> <div class="mb-3"> <label for="username" class="form-label">账号名</label> <input type="text" class="form-control username"> </div> <div class="mb-3"> <label for="password" class="form-label">密码</label> <input type="password" class="form-control password"> </div> <button type="button" class="btn btn-primary btn-login"> 登 录 </button> </form> </div> </div> <script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script> <script> // 目标1:点击登录时,用户名和密码长度判断,并提交数据和服务器通信 // 1.1 登录-点击事件 document.querySelector('.btn-login').addEventListener('click', () => { // 1.2 获取用户名和密码 const username = document.querySelector('.username').value const 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) }) }) </script> </body> </html>
提示信息
使用了bootstrap
警告框(Alert) · Bootstrap v5 中文文档 v5.3 | Bootstrap 中文网
<!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> <!-- 引入bootstrap.css --> <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.2/dist/css/bootstrap.min.css"> <!-- 公共 --> <style> html, body { background-color: #EDF0F5; width: 100%; height: 100%; display: flex; justify-content: center; align-items: center; } .container { width: 520px; height: 540px; background-color: #fff; padding: 60px; box-sizing: border-box; } .container h3 { font-weight: 900; } </style> <!-- 表单容器和内容 --> <style> .form_wrap { color: #8B929D !important; } .form-text { color: #8B929D !important; } </style> <!-- 提示框样式 --> <style> .alert { transition: .5s; opacity: 0; } .alert.show { opacity: 1; } </style> </head> <body> <div class="container"> <h3>欢迎-登录</h3> <!-- 登录结果-提示框 --> <div class="alert alert-success" role="alert"> 提示消息 </div> <!-- 表单 --> <div class="form_wrap"> <form> <div class="mb-3"> <label for="username" class="form-label">账号名</label> <input type="text" class="form-control username"> </div> <div class="mb-3"> <label for="password" class="form-label">密码</label> <input type="password" class="form-control password"> </div> <button type="button" class="btn btn-primary btn-login"> 登 录 </button> </form> </div> </div> <script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script> <script> // 目标1:点击登录时,用户名和密码长度判断,并提交数据和服务器通信 // 目标2:使用提示框,反馈提示消息 // 2.1 获取提示框 const myAlert = document.querySelector('.alert') /** * 2.2 封装提示框函数,重复调用,满足提示需求 * 功能: * 1. 显示提示框 * 2. 不同提示文字msg,和成功绿色失败红色isSuccess(true成功,false失败) * 3. 过2秒后,让提示框自动消失 */ function alertFn(msg, isSuccess) { // 1> 显示提示框 myAlert.classList.add('show') // 2> 实现细节 myAlert.innerText = msg const bgStyle = isSuccess ? 'alert-success' : 'alert-danger' myAlert.classList.add(bgStyle) // 3> 过2秒隐藏 setTimeout(() => { myAlert.classList.remove('show') // 提示:避免类名冲突,重置背景色 myAlert.classList.remove(bgStyle) }, 2000) } // 1.1 登录-点击事件 document.querySelector('.btn-login').addEventListener('click', () => { // 1.2 获取用户名和密码 const username = document.querySelector('.username').value const password = document.querySelector('.password').value // console.log(username, password) // 1.3 判断长度 if (username.length < 8) { alertFn('用户名必须大于等于8位', false) console.log('用户名必须大于等于8位') return // 阻止代码继续执行 } if (password.length < 6) { alertFn('密码必须大于等于6位', false) console.log('密码必须大于等于6位') return // 阻止代码继续执行 } // 1.4 基于axios提交用户名和密码 // console.log('提交数据到服务器') axios({ url: 'http://hmajax.itheima.net/api/login', method: 'POST', data: { username, password } }).then(result => { alertFn(result.data.message, true) console.log(result) console.log(result.data.message) }).catch(error => { alertFn(error.response.data.message, false) console.log(error) console.log(error.response.data.message) }) }) </script> </body> </html>
form-serialize 插件
打印获取到的表单数据(表单元素的值)
表单元素需要设置name属性,name属性回作为返回对象的属性名
配置对象中的hash属性用于设置获取数据的结构:
为true时,获取数据为JS对象;
为false时,获取数据为查询字符串。
一般使用true,表单获取的数据会被提交到服务器,将被携带在请求体,一般要求传一个对象。
empty属性设置是否获取空值(表单元素的值为空)
如果不获取空值,而表单元素的值均为空,则返回空对象(不是null)
登录案例结合serialize插件
<!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> <!-- 引入bootstrap.css --> <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.2/dist/css/bootstrap.min.css"> <!-- 公共 --> <style> html, body { background-color: #EDF0F5; width: 100%; height: 100%; display: flex; justify-content: center; align-items: center; } .container { width: 520px; height: 540px; background-color: #fff; padding: 60px; box-sizing: border-box; } .container h3 { font-weight: 900; } </style> <!-- 表单容器和内容 --> <style> .form_wrap { color: #8B929D !important; } .form-text { color: #8B929D !important; } </style> <!-- 提示框样式 --> <style> .alert { transition: .5s; opacity: 0; } .alert.show { opacity: 1; } </style> </head> <body> <div class="container"> <h3>欢迎-登录</h3> <!-- 登录结果-提示框 --> <div class="alert alert-success" role="alert"> 提示消息 </div> <!-- 表单 --> <div class="form_wrap"> <form class="login-form"> <div class="mb-3"> <label for="username" class="form-label">账号名</label> <input type="text" class="form-control username" name="username"> </div> <div class="mb-3"> <label for="password" class="form-label">密码</label> <input type="password" class="form-control password" name="password"> </div> <button type="button" class="btn btn-primary btn-login"> 登 录 </button> </form> </div> </div> <script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script> <!-- 3.1 引入插件 --> <script src="./lib/form-serialize.js"></script> <script> // 目标1:点击登录时,用户名和密码长度判断,并提交数据和服务器通信 // 目标2:使用提示框,反馈提示消息 // 目标3:使用form-serialize插件,收集用户名和密码 // 2.1 获取提示框 const myAlert = document.querySelector('.alert') /**2.2 封装提示框函数,重复调用,满足提示需求 * 功能: * 1. 显示提示框 * 2. 不同提示文字msg,和成功绿色失败红色isSuccess(true成功,false失败) * 3. 过2秒后,让提示框自动消失 */ function alertFn(msg, isSuccess) { // 1> 显示提示框 myAlert.classList.add('show') // 2> 实现细节 myAlert.innerText = msg const bgStyle = isSuccess ? 'alert-success' : 'alert-danger' myAlert.classList.add(bgStyle) // 3> 过2秒隐藏 setTimeout(() => { myAlert.classList.remove('show') // 提示:避免类名冲突,重置背景色 myAlert.classList.remove(bgStyle) }, 2000) } // 1.1 登录-点击事件 document.querySelector('.btn-login').addEventListener('click', () => { // 3.2 使用serialize函数,收集登录表单里用户名和密码 const form = document.querySelector('.login-form') const data = serialize(form, { hash: true, empty: true }) console.log(data) // {username: 'itheima007', password: '7654321'} const { username, password } = data // 1.2 获取用户名和密码 // const username = document.querySelector('.username').value // const password = document.querySelector('.password').value console.log(username, password) // 1.3 判断长度 if (username.length < 8) { alertFn('用户名必须大于等于8位', false) console.log('用户名必须大于等于8位') return // 阻止代码继续执行 } if (password.length < 6) { alertFn('密码必须大于等于6位', false) console.log('密码必须大于等于6位') return // 阻止代码继续执行 } // 1.4 基于axios提交用户名和密码 // console.log('提交数据到服务器') axios({ url: 'http://hmajax.itheima.net/api/login', method: 'POST', data: { username, password } }).then(result => { alertFn(result.data.message, true) console.log(result) console.log(result.data.message) }).catch(error => { alertFn(error.response.data.message, false) console.log(error) console.log(error.response.data.message) }) }) </script> </body> </html>
我是Capybara,期待你的点赞支持。