写在开始
学习完了前端三件套(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,期待你的点赞支持。