目录
[一、AJAX原理 ------ XMLHttpRequest](#一、AJAX原理 —— XMLHttpRequest)
[1.1 使用XMLHttpRequest](#1.1 使用XMLHttpRequest)
[二、 XMLHttpRequest - 查询参数 (就是往服务器后面拼接要查询的字符串)](#二、 XMLHttpRequest - 查询参数 (就是往服务器后面拼接要查询的字符串))
[三、 地区查询](#三、 地区查询)
[四、 XMLHttpRequest - 数据提交](#四、 XMLHttpRequest - 数据提交)
[五、 认识Promise](#五、 认识Promise)
[5.1 为什么 JavaScript 需要异步?](#5.1 为什么 JavaScript 需要异步?)
[5.2 Promiss - 三种状态](#5.2 Promiss - 三种状态)
[5.3 使用Promiss + XHM 获取省份列表](#5.3 使用Promiss + XHM 获取省份列表)
[六、 封装简易的axios------获取省份列表](#六、 封装简易的axios——获取省份列表)
[七、 注册账号------支持传递请求体数据 data选项](#七、 注册账号——支持传递请求体数据 data选项)
[总结不易~ 本章节对我有很大的收获,希望对你也是!!!](#总结不易~ 本章节对我有很大的收获,希望对你也是!!!)
本节素材已上传至Gitee:https://gitee.com/liu-yihao-hhh/ajax_studyhttps://gitee.com/liu-yihao-hhh/ajax_study
一、AJAX原理 ------ XMLHttpRequest
定义
XMLHttpRequest(XHR) 对象用于与服务器交互。通过XMLHttpRequst可以再不刷新页面的情况下请求特定URL,获取数据。这允许网页在不影响用户操作的情况下,更新页面的局部内容。XMLHttpRequest在AJAX编程中被大量使用。
与axios的关系: axios内部采用XMLHttpRequest 与服务器交互

1.1 使用XMLHttpRequest
- 创建XMLHttpRequest对象
- 配置请求方法和请求url地址
- 监听loadend事件,接受响应结果
- 发起请求
javascript
const xhr = new XMLHttpRequest()
xhr.open('请求方法', '请求url网址')
xhr.addEventListener('loadend', () => {
// 接受 - 响应结果
console.log(xhr.response)
})
// 发送 - 请求
xhr.send()
XMLHttpRequest基础使用,获取服务器的数据并展示

javascript
// 1. 创建一个XMR对象
const xhr = new XMLHttpRequest()
// 2. 配置请求方法和请求url地址
xhr.open('GET', 'http://hmajax.itheima.net/api/province')
// 3. 监听 loadend事件 接收响应结果
xhr.addEventListener('loadend', () => {
console.log(xhr.response) // 这里返回的是json字符串
// json字符串转对象
const data = JSON.parse(xhr.response)
console.log(data.list.join('<br>')) // 数组转字符串进行拼接
document.querySelector('.my-p').innerHTML = data.list.join('<br>')
})
// 4. 发起请求
xhr.send()
二、 XMLHttpRequest - 查询参数 (就是往服务器后面拼接要查询的字符串)
定义: 浏览器提供给服务器的额外信息, 让服务器返回浏览器想要的数据

javascript
/**
* 目标:使用XHR携带查询参数,展示某个省下属的城市列表
*/
const xhr = new XMLHttpRequest()
// 进行查询 往服务器后面进行拼接查询的参数名 ?pname=
xhr.open('GET', 'http://hmajax.itheima.net/api/city?pname=辽宁省')
// loadend 加载结束事件
xhr.addEventListener('loadend', () => {
console.log(xhr.response)
const data = JSON.parse(xhr.response)
console.log(data.list)
document.querySelector('.city-p').innerHTML = data.list.join('<br>')
})
xhr.send()
三、 地区查询

这一个案例就是要我们同时传入两个参数,但是我们不方便自己获取两个参数后拼接到url后面,这个时候,我们就可以采用浏览器内置的构造函数URLSearchParams 来创建一个对象,里面放入我们需要传入URL的对象参数,他就会自动给我们返回一个url编码的字符串,我们就可以直接在url后面进行拼接 ?+编码即可
javascript
/**
* 目标: 根据省份和城市名字, 查询对应的地区列表
*/
// 1. 给查询按钮绑定一个点击事件
document.querySelector('.sel-btn').addEventListener('click', () => {
// 2. 收集省份和城市名字
const pname = document.querySelector('.province').value
const cname = document.querySelector('.city').value
// 3. 组织查询参数字符串
const qObj = {
pname,
cname
}
// 查询参数对象 -》 查询参数字符串
// 浏览器内置的构造函数
// 1. 创建 URLSearchParams 对象 自动将我们需要的多个查询对象转换成一个字符串 好方便后续的拼接
const paramsObj = new URLSearchParams(qObj)
const queryString = paramsObj.toString()
console.log(queryString) // 拿到一个url编码 pname=%E6%B9%96%E5%8C%97&cname=%E6%AD%A6%E6%B1%89%E5%B8%82
// 4. 使用XHR对象, 查询地区列表
const xhr = new XMLHttpRequest()
xhr.open('GET', `http://hmajax.itheima.net/api/area?${queryString}`)
// loadend 加载结束事件
xhr.addEventListener('loadend', () => {
console.log(xhr.response)
const data = JSON.parse(xhr.response)
console.log(data)
const htmlStr = data.list.map(item => {
return `<li class="list-group-item">${item}</li>`
})
console.log(htmlStr)
const html = htmlStr.join('<br>')
document.querySelector('.list-group').innerHTML = html
})
xhr.send()
})
四、 XMLHttpRequest - 数据提交
需求: 通过XHR提交用户名和密码,完成注册功能
核心: 请求头设置Content-Type:application/json
请求体携带JSON字符串

提交数据就是在xhr.send()中进行提交,但是要提前设置请求头,告诉服务器我们提交的数据是JSON数据
xhr.setRequestHeader('Content-Type', 'application/json')
准备好要进行提交的数据之后,就将该数据转换成JSON字符串直接进行提交即可!
javascript
/**
* 目标:使用xhr进行数据提交-完成注册功能
*/
// 后端的数据提交 http://hmajax.itheima.net/api/register
// 请求参数 body application/json
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: '我是hhhhha',
password: '11111111'
}
const userStr = JSON.stringify(userObj)
console.log(userStr)
// 设置请求体 发送请求
xhr.send(userStr)
})
五、 认识Promise
定义: Promise对象用于表示一个异步操作的最终完成(或失败)及其结果值
-
同步方式:你站在门口等外卖员送来,什么事都不干,一直等着。
-
异步方式:你点完外卖,继续干别的事(比如学习/打游戏),等外卖来了,电话通知你,然后你去取。
5.1 为什么 JavaScript 需要异步?
因为 JavaScript 是 单线程的 (同一时间只能做一件事),如果你在执行一个耗时操作(比如网络请求、读取大文件),同步写法会卡住整个页面 ,用户无法点击、无法操作,非常糟糕。异步写法可以把"耗时的事"交给浏览器处理,不阻塞主线程,页面流畅运行
Promise语法
javascript
// 1. 创建Promise对象
const p = new Promise((resolve, reject) => {
// 2. 执行异步任务 并传递结果
// 成功调用: resolve(值) 触发then()执行
// 失败调用: reject(值) 触发catch()执行
})
// 3. 接收结果
p.then(result => {
// 成功
}).catch(error => {
// 失败
})
学了Promise后, 会更好的理解axios , 能够解决回调函数地狱的问题

创建Promise对象后传入的两个参数都是函数,但是二者分别是表示成功时调用的函数 和 失败时调用的函数,等待定时器异步操作完成后,屏幕会输出函数传入的字符

javascript
// 1. 创建Promise对象
// 参数名 类型 作用
// resolve 函数 表示成功时调用,用来传递"成功的结果"
// reject 函数 表示失败时调用,用来传递"失败的原因"
const p = new Promise((resolve, reject) => {
// 2. 执行异步操作
setTimeout(() => {
resolve('模拟AJAX请求-成功的结果')
// reject(new Error('模拟AJAX请求-失败的结果'))
}, 2000)
})
// 3. 获取结果
p.then(result => {
console.log(result)
}).catch(error => {
console.log(error)
})
5.2 Promiss - 三种状态
一个Promiss对象,必然处于一下的一种状态:
待定(pending) new Promiss(): 初始状态, 既没有被兑现,也没有被拒绝
已兑现(fulfilled) .then(回调函数):意味着,操作成功完成
已拒绝(rejected) .catch(回调函数): 意味着操作失败
请求成功时,是fulfilled状态,触发.then()

请求失败时,是rejected状态, 触发.catch()

5.3 使用Promiss + XHM 获取省份列表
当发送请求错误的时候 将error.message错误信息渲染到屏幕上

六、 封装简易的axios------获取省份列表

通过myAxios传入的对象参数进行接收,默认是GET选项
- 创建Promise对象
- 发起XHR请求,默认是GET
- 进行xhr.open设置请求方法和地址,来为发送请求做准备
- loadend 是在请求完成后触发,来进行发挥成功或者失败的函数
- xhr.status 是服务器响应状态,xhr.response 是服务器响应内容
- xhr.send()正式发起请求到服务器
javascript
<p class="my-p"></p>
<script>
/**
* 目标:封装_简易axios函数_获取省份列表
* 1. 定义myAxios函数,接收配置对象,返回Promise对象
* 2. 发起XHR请求,默认请求方法为GET
* 3. 调用成功/失败的处理程序
* 4. 使用myAxios函数,获取省份列表展示
*/
// 1. 定义myAxios函数,接收配置对象,返回Promise对象
function myAxios(config) {
return new Promise((resolve, reject) => {
// 2. 发起XHR请求 默认是get
const xhr = new XMLHttpRequest()
// open 设置请求的方法和地址,为发送请求做准备
xhr.open(config.method || 'GET', config.url)
// loadend 是在 请求完成 (不管成功还是失败)时触发的事件,用来统一处理响应结果。
xhr.addEventListener('loadend', () => {
// 3. 调用成功 / 失败 \
// xhr.response 是服务器响应的内容。
if (xhr.status >= 200 && xhr.status < 300) resolve(JSON.parse(xhr.response))
else reject(new Error(xhr.response))
})
// 正式发起请求,把配置好的 XHR 请求发送到服务器。
xhr.send()
})
}
// 4. 使用myAxios函数 获取省份列表
myAxios({
url: 'http://hmajax.itheima.net/api/province'
}).then(result => {
console.log(result)
document.querySelector('.my-p').innerHTML = result.list.join('<br>')
}).catch(error => {
console.log(error)
document.querySelector('.my-p').innerHTML = error.message
})
</script>
修改myAxios函数,支持传递查询参数,就是需要传入params选项

javascript
// 判断 有 params 选项, 携带查询参数
if (config.params) {
// 使用URLSearchParmas转换 并携带到url上
const paramsObj = new URLSearchParams(config.params)
const queryString = paramsObj.toString()
console.log(paramsObj)
console.log(queryString)
// 把查询数字字符串 拼接到url?后面
config.url += `?${queryString}`
console.log(config.url)
}
起到查询作用就是要根据上面学习的URLSearchParams浏览器内置函数来将用户传入的params查询参数对象转换成字符串来坪街道url?后面
- 判断是否携带params对象参数
- 使用 URLSearchParams转换 并携带到url上 此时还是一个对象关系
- 将paramsObj转换成字符串queryString
- 进行与url拼接
javascript
<p class="my-p"></p>
<script>
/**
* 目标:封装_简易axios函数_获取省份列表
* 1. 定义myAxios函数,接收配置对象,返回Promise对象
* 2. 发起XHR请求,默认请求方法为GET
* 3. 调用成功/失败的处理程序
* 4. 使用myAxios函数,获取省份列表展示
*/
// 1. 定义myAxios函数,接收配置对象,返回Promise对象
function myAxios(config) {
return new Promise((resolve, reject) => {
// 2. 发起XHR请求 默认是get
const xhr = new XMLHttpRequest()
// 判断 有 params 选项, 携带查询参数
if (config.params) {
// 使用URLSearchParmas转换 并携带到url上
const paramsObj = new URLSearchParams(config.params)
const queryString = paramsObj.toString()
console.log(paramsObj)
console.log(queryString)
// 把查询数字字符串 拼接到url?后面
config.url += `?${queryString}`
}
console.log(config.url)
// open 设置请求的方法和地址,为发送请求做准备
xhr.open(config.method || 'GET', config.url)
// loadend 是在 请求完成 (不管成功还是失败)时触发的事件,用来统一处理响应结果。
xhr.addEventListener('loadend', () => {
// 3. 调用成功 / 失败 \
// xhr.response 是服务器响应的内容。
if (xhr.status >= 200 && xhr.status < 300) resolve(JSON.parse(xhr.response))
else reject(new Error(xhr.response))
})
// 正式发起请求,把配置好的 XHR 请求发送到服务器。
xhr.send()
})
}
// 4. 使用myAxios函数 获取省份列表
myAxios({
url: 'http://hmajax.itheima.net/api/area',
params: {
pname: '湖北省',
cname: '武汉市'
}
}).then(result => {
console.log(result)
document.querySelector('.my-p').innerHTML = result.list.join('<br>')
}).catch(error => {
console.log(error)
document.querySelector('.my-p').innerHTML = error.message
})
</script>
七、 注册账号------支持传递请求体数据 data选项
javascript
// 判断是否有data选项 携带请求体
if (config.data) {
// 数据转换类型 在send中发送
const jsonStr = JSON.stringify(config.data)
// 请求体数据类型标记
xhr.setRequestHeader('Content-Type', 'application/json')
xhr.send(jsonStr)
}
// 正式发起请求,把配置好的 XHR 请求发送到服务器。
else xhr.send()
})

- 提交数据到服务器,用POST方法进行提交,然后携带data对象数据
- 要将data对象数据转换成JSON字符串
- 标记数据传输到服务器的数据类型是json格式
- 然后正式发起请求 xhr.send(josnStr)
javascript
<button class="reg-btn">注册用户</button>
<script>
/**
* 目标:封装_简易axios函数_获取省份列表
* 1. 定义myAxios函数,接收配置对象,返回Promise对象
* 2. 发起XHR请求,默认请求方法为GET
* 3. 调用成功/失败的处理程序
* 4. 使用myAxios函数,获取省份列表展示
*/
// 1. 定义myAxios函数,接收配置对象,返回Promise对象
function myAxios(config) {
return new Promise((resolve, reject) => {
// 2. 发起XHR请求 默认是get
const xhr = new XMLHttpRequest()
// 判断 有 params 选项, 携带查询参数
if (config.params) {
// 使用URLSearchParmas转换 并携带到url上
const paramsObj = new URLSearchParams(config.params)
const queryString = paramsObj.toString()
console.log(paramsObj)
console.log(queryString)
// 把查询数字字符串 拼接到url?后面
config.url += `?${queryString}`
}
console.log(config.url)
// open 设置请求的方法和地址,为发送请求做准备
xhr.open(config.method || 'GET', config.url)
// loadend 是在 请求完成 (不管成功还是失败)时触发的事件,用来统一处理响应结果。
xhr.addEventListener('loadend', () => {
// 3. 调用成功 / 失败 \
// xhr.response 是服务器响应的内容。
if (xhr.status >= 200 && xhr.status < 300) resolve(JSON.parse(xhr.response))
else reject(new Error(xhr.response))
})
// 判断是否有data选项 携带请求体
if (config.data) {
// 数据转换类型 在send中发送
const jsonStr = JSON.stringify(config.data)
// 请求体数据类型标记
xhr.setRequestHeader('Content-Type', 'application/json')
xhr.send(jsonStr)
}
// 正式发起请求,把配置好的 XHR 请求发送到服务器。
else xhr.send()
})
}
document.querySelector('.reg-btn').addEventListener('click', () => {
// 4. 使用myAxios函数 获取省份列表
myAxios({
url: 'http://hmajax.itheima.net/api/register',
method: 'POST',
data: {
username: 'wshhaaaaa12w~',
password: '1234567'
}
}).then(result => {
console.log(result)
}).catch(error => {
console.log(error)
})
})
</script>
八、 天气预报案例

一些渲染操作都是非常简单的,就最后一步原生js 响应式输入,只要得到了当前的输入框,然后add~input就能做到响应式!!!
javascript
document.querySelector('.search-city').addEventListener('input', e => {
console.log(e.target.value)
})
javascript
/**
* 目标1:默认显示-北京市天气
* 1.1 获取北京市天气数据
* 1.2 数据展示到页面
*/
// 获取并渲染城市天气函数
const getWeather = async (cityCode) => {
// 获取天气数据
const response = await axios('http://hmajax.itheima.net/api/weather', { params: { city: cityCode } })
console.log(response.data)
const data = response.data.data
// 展示数据
document.querySelector('.dateShort').innerHTML = data.date
document.querySelector('.dateLunar').innerHTML = data.dateLunar
document.querySelector('.area').innerHTML = data.area
// 当天的气温
const nowWStr = `
<div class="tem-box">
<span class="temp">
<span class="temperature">${data.temperature}</span>
<span>°</span>
</span>
</div>
<div class="climate-box">
<div class="air">
<span class="psPm25">${data.psPm25}</span>
<span class="psPm25Level">${data.psPm25Level}</span>
</div>
<ul class="weather-list">
<li>
<img src="${data.weatherImg}" class="weatherImg" alt="">
<span class="weather">${data.weather}</span>
</li>
<li class="windDirection">${data.windDirection}</li>
<li class="windPower">${data.windPower}</li>
</ul>
</div>
`
document.querySelector('.weather-box').innerHTML = nowWStr
// 当天的天气
const twObj = data.todayWeather
const todayWStr = `
<div class="range-box">
<span>今天:</span>
<span class="range">
<span class="weather">${twObj.weather}</span>
<span class="temNight">${twObj.temNight}</span>
<span>-</span>
<span class="temDay">${twObj.temDay}</span>
<span>℃</span>
</span>
</div>
<ul class="sun-list">
<li>
<span>紫外线</span>
<span class="ultraviolet">${twObj.ultraviolet}</span>
</li>
<li>
<span>湿度</span>
<span class="humidity">${twObj.humidity}</span>%
</li>
<li>
<span>日出</span>
<span class="sunriseTime">${twObj.sunriseTime}</span>
</li>
<li>
<span>日落</span>
<span class="sunsetTime">${twObj.sunsetTime}</span>
</li>
</ul>
</div>
`
document.querySelector('.today-weather').innerHTML = todayWStr
// 七日天气预报数据展示
const dayForecast = data.dayForecast
const dayForecastStr = dayForecast.map(item => {
return `
<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">${item.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('')
document.querySelector('.week-wrap').innerHTML = dayForecastStr
}
// m默认进入网页 - 就要获取天气数据(北京城市编码就是 '110100')
getWeather('110100')
// 搜索城市列表
document.querySelector('.search-city').addEventListener('input', async e => {
console.log(e.target.value)
const response = await axios('http://hmajax.itheima.net/api/weather/city', { params: { city: e.target.value } })
const cityStr = response.data.data.map(item => {
return `<li class="city-item">${item.name}</li>`
}).join('')
document.querySelector('.search-list').innerHTML = cityStr
document.querySelector('.search-list').addEventListener('click', ee => {
const num = response.data.data.filter(item => {
return item.name === ee.target.innerHTML
})
console.log(num)
if (num.length > 0) getWeather(num[0].code)
})
})
最后获得城市的code值优化,只需要在渲染的同时加上自定义data-code属性就好!
javascript
const cityStr = response.data.data.map(item => {
return `<li class="city-item" data-code="${item.code}">${item.name}</li>`
}).join('')
document.querySelector('.search-list').innerHTML = cityStr
document.querySelector('.search-list').addEventListener('click', e => {
console.log(e.target.dataset.code)
getWeather(e.target.dataset.code)
})