◆ XMLHttpRequest
什么是XMLHttpRequest?
定义:
关系:axios 内部采用 XMLHttpRequest 与服务器交互
注意:直白点说就是axios内部就是封装了XMLHttpRequest这个对象来实现发送异步请求的
使用 XMLHttpRequest
步骤:
-
创建 XMLHttpRequest 对象
-
配置请求方法和请求 url 地址
-
监听 loadend 事件,接收响应结果
-
发起请求
1.无参数的情况
获取并展示所有省份名字
javascript
//1. 创建 XMLHttpRequest 对象
const xhr = new XMLHttpRequest()
//2. 配置请求方法和请求 url 地址
xhr.open('GET','http://hmajax.itheima.net/api/province')
//3. 监听 loadend 事件,接收响应结果
xhr.addEventListener('loadend',function(){
console.log(xhr.response);
const rs = JSON.parse(xhr.response)
console.log(rs.list.join('<br>'));
document.querySelector('p').innerHTML = rs.list.join('<br>')
})
//4. 发起请求
xhr.send()
2.有URL查询参数的情况
- 使用字符串拼接
- 使用浏览器提供的内置对对象 URLSearchParams
javascript
// 1. 组织查询参数字符串
const qObj = {
pname: '辽宁省',
cname: '大连市'
}
// 2查询参数对象 -> 查询参数字符串
const paramsObj = new URLSearchParams(qObj)
const queryString = paramsObj.toString()
console.log(queryString)
// 3. 使用XHR对象,查询地区列表
const xhr = new XMLHttpRequest()
xhr.open('GET', `http://hmajax.itheima.net/api/area?${queryString}`)
xhr.addEventListener('loadend', () => {
console.log(xhr.response)
const data = JSON.parse(xhr.response)
console.log(data)
const htmlStr = data.list.map(areaName => {
return `<li class="list-group-item">${areaName}</li>`
}).join('')
console.log(htmlStr)
})
xhr.send()
3.以请求体(JSON)的方式发送数据的情况
需求:通过 XHR 提交用户名和密码,完成注册功能
核心:
请求头设置 Content-Type:application/json
请求体携带 JSON 字符串
javascript
/**
* 目标:使用xhr进行数据提交-完成注册功能
*/
document.querySelector('.reg-btn').addEventListener('click', () => {
const xhr = new XMLHttpRequest()
xhr.open('POST', 'http://hmajax.itheima.net/api/register')
xhr.addEventListener('loadend', () => {
console.log(xhr.response)
})
// 设置请求头-告诉服务器内容类型(JSON字符串)
xhr.setRequestHeader('Content-Type', 'application/json')
// 准备提交的数据
const userObj = {
username: 'itheima007',
password: '7654321'
}
//将对象转化成JSON字符串
const userStr = JSON.stringify(userObj)
// 设置请求体,发起请求
xhr.send(userStr)
})
总结:
. AJAX 原理是什么?
- ➢ XMLHttpRequest 对象
- 为什么学习 XHR?
- ➢ 有更多与服务器数据通信方式
- ➢ 了解 axios 内部原理
- XHR 使用步骤?
- ➢ 创建 XHR 对象
- ➢ 调用 open 方法,设置 url 和请求方法
- ➢ 监听 loadend 事件,接收结果
- ➢ 调用 send 方法,发起请求
4.上传图片等二进制的情况
javascript
//4 上传图片等二进制的情况
//1. 获取图片文件
document.querySelector('.upload').addEventListener('change',(e)=>{
// console.log(e.target.files);
//2. 使用 FormData 携带图片文件
const fd = new FormData()
// append() 追加元素
fd.append('img',e.target.files[0])
//3 使用XmlHttpRequest提交数据
const xhr = new XMLHttpRequest()
//设置方法和url
xhr.open('POST','http://hmajax.itheima.net/api/uploadimg')
//设置回调函数
xhr.addEventListener('loadend',function(){
console.log(xhr.response); //这里不是一个对象,是字符串
console.log(JSON.parse(xhr.response));
document.querySelector('img').src = JSON.parse(xhr.response).data.url
})
xhr.send(fd)
})
◆ Promise
什么是 Promise?
- 表示(管理)一个异步操作最终状态和结果值的对象
定义:
Promise 使用步骤
Promise - 三种状态
概念:一个Promise对象,必然处于以下几种状态之一
- 待定(pending) :初始状态,既没有被兑现,也没有被拒绝
- 已兑现(fulfilled) :意味着,操作成功完成
- 已拒绝(rejected) :意味着,操作失败
注意:Promise对象一旦被兑现/拒绝就是已敲定了,状态无法再被改变
html
<!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>案例_使用Promise+XHR_获取省份列表</title>
</head>
<body>
<p class="my-p"></p>
<script>
/**
* 目标:使用Promise管理XHR请求省份列表
* 1. 创建Promise对象
* 2. 执行XHR异步代码,获取省份列表
* 3. 关联成功或失败函数,做后续处理
*/
// 1. 创建Promise对象
const p = new Promise((resolve, reject) => {
// 2. 执行XHR异步代码,获取省份列表
const xhr = new XMLHttpRequest()
xhr.open('GET', 'http://hmajax.itheima.net/api/province')
xhr.addEventListener('loadend', () => {
// xhr如何判断响应成功还是失败的?
// 2xx开头的都是成功响应状态码
if (xhr.status >= 200 && xhr.status < 300) {
resolve(JSON.parse(xhr.response))
} else {
reject(new Error(xhr.response))
}
})
xhr.send()
})
// 3. 关联成功或失败函数,做后续处理
p.then(result => {
console.log(result)
document.querySelector('.my-p').innerHTML = result.list.join('<br>')
}).catch(error => {
// 错误对象要用console.dir详细打印
console.dir(error)
// 服务器返回错误提示消息,插入到p标签显示
document.querySelector('.my-p').innerHTML = error.message
})
</script>
</body>
</html>
总结
◆ 封装简易版 axios
javascript
function myAxios(config) {
return new Promise((resolve, reject) => {
const xhr = new XMLHttpRequest()
if (config.params) {
const paramsObj = new URLSearchParams(config.params)
const queryString = paramsObj.toString()
config.url += `?${queryString}`
}
xhr.open(config.method || 'GET', config.url)
xhr.addEventListener('loadend', () => {
if (xhr.status >= 200 && xhr.status < 300) {
resolve(JSON.parse(xhr.response))
} else {
reject(new Error(xhr.response))
}
})
if (config.data) {
const jsonStr = JSON.stringify(config.data)
xhr.setRequestHeader('Content-Type', 'application/json')
xhr.send(jsonStr)
} else {
xhr.send()
}
})
}
◆ 案例 - 天气预报
步骤:
-
获取北京市天气数据,展示
-
搜索城市列表,展示
-
点击城市,显示对应天气数据
html
<!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">
<link rel="stylesheet" href="./css/reset.css">
<link rel="stylesheet" href="./css/index.css">
<title>案例_天气预报</title>
</head>
<body>
<div class="container">
<!-- 顶部 -->
<div class="top-box">
<div class="title">
<span class="dateShort">10月28日</span>
<span class="calendar">农历
<span class="dateLunar">十月初四</span>
</span>
</div>
<div class="search-box">
<div class="location">
<img src="./imgs/定位.png" alt="">
<span class="area">城市名</span>
</div>
<!-- 搜索框+搜索列表 -->
<div class="search">
<input type="text" class="search-city" placeholder="搜索城市">
<ul class="search-list">
<li class="city-item">北京市</li>
</ul>
</div>
</div>
</div>
<!-- 当前天气 -->
<div class="weather-box">
<div class="tem-box">
<span class="temp">
<span class="temperature">12</span>
<span>°</span>
</span>
</div>
<div class="climate-box">
<div class="air">
<span class="psPm25">55</span>
<span class="psPm25Level">良</span>
</div>
<ul class="weather-list">
<li>
<img src="./imgs/小雨-line.png" class="weatherImg" alt="">
<span class="weather">多云</span>
</li>
<li class="windDirection">东南风</li>
<li class="windPower">2级</li>
</ul>
</div>
</div>
<div class="today-weather">
<div class="range-box">
<span>今天:</span>
<span class="range">
<span class="weather">晴</span>
<span class="temNight">9</span>
<span>-</span>
<span class="temDay">14</span>
<span>℃</span>
</span>
</div>
<ul class="sun-list">
<li>
<span>紫外线</span>
<span class="ultraviolet">强</span>
</li>
<li>
<span>湿度</span>
<span class="humidity">53</span>%
</li>
<li>
<span>日出</span>
<span class="sunriseTime">06:38</span>
</li>
<li>
<span>日落</span>
<span class="sunsetTime">17:18</span>
</li>
</ul>
</div>
<!-- 周天气预报 -->
<div class="week-weather-box">
<div class="title">7日内天气预报</div>
<ul class="week-wrap">
<li class="item">
<div class="date-box">
<span class="dateFormat">今天</span>
<span class="date">10月28日</span>
</div>
<img src="./imgs/多云.png" alt="" class="weatherImg">
<span class="weather">多云</span>
<div class="temp">
<span class="temNight">12</span>-
<span class="temDay">12</span>
<span>℃</span>
</div>
<div class="wind">
<span class="windDirection">东南风</span>
<span class="windPower"><3级</span>
</div>
</li>
<li class="item">
<div class="date-box">
<span class="dateFormat">今天</span>
<span class="date">10月28日</span>
</div>
<img src="./imgs/多云.png" alt="" class="weatherImg">
<span class="weather">多云</span>
<div class="temp">
<span class="temDay">12</span>-
<span class="temNight">12</span>
<span>℃</span>
</div>
<div class="wind">
<span class="windDirection">东南风</span>
<span class="windPower"><3级</span>
</div>
</li>
<li class="item">
<div class="date-box">
<span class="dateFormat">今天</span>
<span class="date">10月28日</span>
</div>
<img src="./imgs/多云.png" alt="" class="weatherImg">
<span class="weather">多云</span>
<div class="temp">
<span class="temDay">12</span>-
<span class="temNight">12</span>
<span>℃</span>
</div>
<div class="wind">
<span class="windDirection">东南风</span>
<span class="windPower"><3级</span>
</div>
</li>
<li class="item">
<div class="date-box">
<span class="dateFormat">今天</span>
<span class="date">10月28日</span>
</div>
<img src="./imgs/多云.png" alt="" class="weatherImg">
<span class="weather">多云</span>
<div class="temp">
<span class="temDay">12</span>-
<span class="temNight">12</span>
<span>℃</span>
</div>
<div class="wind">
<span class="windDirection">东南风</span>
<span class="windPower"><3级</span>
</div>
</li>
<li class="item">
<div class="date-box">
<span class="dateFormat">今天</span>
<span class="date">10月28日</span>
</div>
<img src="./imgs/多云.png" alt="" class="weatherImg">
<span class="weather">多云</span>
<div class="temp">
<span class="temDay">12</span>-
<span class="temNight">12</span>
<span>℃</span>
</div>
<div class="wind">
<span class="windDirection">东南风</span>
<span class="windPower"><3级</span>
</div>
</li>
<li class="item">
<div class="date-box">
<span class="dateFormat">今天</span>
<span class="date">10月28日</span>
</div>
<img src="./imgs/多云.png" alt="" class="weatherImg">
<span class="weather">多云</span>
<div class="temp">
<span class="temDay">12</span>-
<span class="temNight">12</span>
<span>℃</span>
</div>
<div class="wind">
<span class="windDirection">东南风</span>
<span class="windPower"><3级</span>
</div>
</li>
<li class="item">
<div class="date-box">
<span class="dateFormat">今天</span>
<span class="date">10月28日</span>
</div>
<img src="./imgs/多云.png" alt="" class="weatherImg">
<span class="weather">多云</span>
<div class="temp">
<span class="temDay">12</span>-
<span class="temNight">12</span>
<span>℃</span>
</div>
<div class="wind">
<span class="windDirection">东南风</span>
<span class="windPower"><3级</span>
</div>
</li>
</ul>
</div>
</div>
<!-- 自己封装myAxios函数 -->
<script src="./js/my-axios.js"></script>
<!-- 搜索框+下拉菜单出现逻辑 -->
<script src="./js/search.js"></script>
<!-- 核心js -->
<script src="./js/index.js"></script>
<script>
//1 获取默认城市的天气预报
function getWeather(cityCode){
myAxios({
url: 'http://hmajax.itheima.net/api/weather',
params: {
city: cityCode
}
}).then(result=>{
//渲染数据
console.log(result);
const wObj = result.data
//更新城市名
document.querySelector('.area').innerHTML = result.data.area
//当前日期
document.querySelector('.title').innerHTML = `
<span class="dateShort">${wObj.dateShort}</span>
<span class="calendar">农历
<span class="dateLunar">${wObj.dateLunar}</span>
</span>
`
//当前气候
document.querySelector('.climate-box').innerHTML = `
<div class="air">
<span class="psPm25">${wObj.psPm25}</span>
<span class="psPm25Level">${wObj.psPm25Level}</span>
</div>
<ul class="weather-list">
<li>
<img src=${wObj.weatherImg} class="weatherImg" alt="">
<span class="weather">${wObj.weather}</span>
</li>
<li class="windDirection">${wObj.windDirection}</li>
<li class="windPower">${wObj.windPower}</li>
</ul>
`
//当前温度
document.querySelector('.tem-box').innerHTML = `
<span class="temp">
<span class="temperature">${wObj.temperature}</span>
<span>°</span>
</span>
`
const todayWeather = wObj.todayWeather
document.querySelector('.today-weather').innerHTML = `
<div class="range-box">
<span>今天:</span>
<span class="range">
<span class="weather">${todayWeather.weather}</span>
<span class="temNight">${todayWeather.temNight}</span>
<span>-</span>
<span class="temDay">${todayWeather.temDay}</span>
<span>℃</span>
</span>
</div>
<ul class="sun-list">
<li>
<span>紫外线</span>
<span class="ultraviolet">${todayWeather.ultraviolet}</span>
</li>
<li>
<span>湿度</span>
<span class="humidity">${todayWeather.humidity}</span>%
</li>
<li>
<span>日出</span>
<span class="sunriseTime">${todayWeather.sunriseTime}</span>
</li>
<li>
<span>日落</span>
<span class="sunsetTime">${todayWeather.sunsetTime}</span>
</li>
</ul>
`
// <!-- 周天气预报 -->
document.querySelector('.week-wrap').innerHTML = wObj.dayForecast.map((item)=>`
<li class="item">
<div class="date-box">
<span class="dateFormat">${item.dateFormat}</span>
<span class="date">${item.date}</span>
</div>
<img src=${item.weatherImg} alt="" class="weatherImg">
<span class="weather">多云</span>
<div class="temp">
<span class="temNight">${item.temNight}</span>-
<span class="temDay">${item.temDay}</span>
<span>℃</span>
</div>
<div class="wind">
<span class="windDirection">${item.windDirection}</span>
<span class="windPower">${item.windPower}</span>
</div>
</li>
`).join('')
})
}
getWeather('450700')
//2 搜索城市列表
document.querySelector('.search-city').addEventListener('input',function(e){
//得到输入的内容
const value = e.target.value
// console.log(value);
// 使用ajax调用接口
myAxios({
url: 'http://hmajax.itheima.net/api/weather/city',
params: {
city: value
}
}).then(result=>{
// console.log(result);
document.querySelector('.search-list').innerHTML = result.data.map(item=>`
<li class="city-item" data-code="${item.code}">${item.name}</li>
`)
})
})
//使用事件委托,给每个搜索出来的li加点击事件
document.querySelector('.search-list').addEventListener('click',function(e){
if(e.target.classList.contains('city-item')){
// console.log(222);
//获取自定义属性
let code = e.target.dataset.code
//调用天气函数
console.log(code);
getWeather(code)
}
})
</script>
</body>
</html>