1. XMLHttpRequest
1.1 XMLHttpRequest-基本使用
/*
定义:XMLHttpRequest(XHR)对象用于与服务器交互。
通过 XMLHttpRequest 可以在不刷新页面的情况下请求特定 URL,获取数据。
这允许网页在不影响用户操作的情况下,更新页面的局部内容。
XMLHttpRequest 在 AJAX 编程中被大量使用。
*/
// 1. 创建 XMLHttpRequest对象
const xhr = new XMLHttpRequest()
// 2. 设置请求方法 和 请求URL
xhr.open('请求方法', 'URL地址')
// 3. 监听 loadend 事件,接收响应结果
xhr.addEventListener('loadend', () => {
console.log(xhr.response)
})
// 4. 发起请求
xhr.send()
<!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">
<title>XMLHttpRequest-基础使用</title>
</head>
<body>
<h2>XMLHttpRequest-基础使用</h2>
<p class="list">
<!-- 数据渲染到这里 -->
</p>
<script>
/**
* 需求: XMLHttpRequest获取省份数据,渲染到页面上
* */
// 1. 创建 XMLHttpRequest对象
const xhr = new XMLHttpRequest()
// 2. 设置请求方法 和 请求URL, 请求方法不能省略
xhr.open('get', 'https://hmajax.itheima.net/api/province')
// 3. 监听 loadend 事件,接收响应结果
xhr.addEventListener('loadend', function () {
// console.log(xhr.response) // JSON格式字符串
const data = JSON.parse(xhr.response) // 将JSON格式字符串转为对象
// console.log(data) // 对象
// console.log(data.list) // 省份数组
// 将数据渲染到页面
document.querySelector('.list').innerHTML = data.list.join('--')
})
// 4. 发起请求
xhr.send()
</script>
</body>
</html>
1.2 XMLHttpRequest-查询参数
// 创建 URLSearchParams 对象
const params = new URLSearchParams({ key: value, key2: value2 })
// 生成查询参数 key=value&key2=value
const queryString = params.toString()
<!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">
<title>XMLHttpRequest-查询参数</title>
</head>
<body>
<h2>XMLHttpRequest-查询参数</h2>
<p class="city">
<!-- 城市渲染到这里 -->
</p>
<!--
XMLHttpRequest查询参数
语法: 用 & 符号分隔的键/值对列表
-->
<script>
/**
* 需求:通过 XMLHttpRequest 获取某个省份的所有城市,渲染到页面上
*/
// 1. 创建xhr对象
const xhr = new XMLHttpRequest()
// 2. 请求方法和url
// 2.1 查询参数写法1:http://xxxxxx/?参数1=值&参数2=值...
xhr.open('get', 'https://hmajax.itheima.net/api/city?pname=河南省')
// 3. 拿到响应结果
xhr.addEventListener('loadend', function () {
const data = JSON.parse(xhr.response)
document.querySelector('.city').innerHTML = data.list.join('--')
})
// 4. 发送请求
xhr.send()
</script>
</body>
</html>
1.3 案例1-地区查询
<!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">
<title>案例_地区查询</title>
<link href="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/5.1.3/css/bootstrap.min.css" rel="stylesheet">
<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 area-group">
<!-- 示例地区 -->
<li class="list-group-item">东城区</li>
</ul>
</div>
<script src="https://cdn.bootcdn.net/ajax/libs/axios/1.3.2/axios.min.js"></script>
<script>
/**
* 需求: 根据省份和城市名字, 查询对应的地区列表
* 1. 生成查询参数
* 2. 调用接口
* 3. 渲染数据
*/
document.querySelector('.sel-btn').addEventListener('click', function () {
const pname = document.querySelector('.province').value
const cname = document.querySelector('.city').value
// 1. 创建xhr对象
const xhr = new XMLHttpRequest()
// 2. 请求方法和url
// 2.2 查询参数写法2:
// 2.2.1 创建 URLSearchParams 对象
// URLSearchParams 拼接查询参数 new URLSearchParams({key:value,key2:value2})
const params = new URLSearchParams({ pname, cname }) // 返回数据类似为对象,不能直接拼成url
// 2.2.2 生成查询参数 key=value&key2=value
const queryString = params.toString() // 转成字符串
// 2.2.3 url
xhr.open('get', `https://hmajax.itheima.net/api/area?${queryString}`)
// 3. 拿到响应结果
xhr.addEventListener('loadend', function () {
const data = JSON.parse(xhr.response)
document.querySelector('.area-group').innerHTML = data.list.map(item => {
return `<li class="list-group-item">${item}</li>`
}).join('')
})
// 4. 发送请求
xhr.send()
})
</script>
</body>
</html>
1.4 XMLHttpRequest-数据提交
/*
XMLHttpRequest数据提交
核心步骤:
1. 请求头设置Content-Type
2. 请求体携带符合要求的数据
*/
const xhr = new XMLHttpRequest()
xhr.open('请求方法', '请求URL')
xhr.addEventListener('loadend', () => {
console.log(xhr.response)
})
// 设置请求头 告诉服务器,提交的数据类型为JSON
xhr.setRequestHeader('Content-Type', 'application/json')
// 请求体携带数据(和请求头设置的一致)
xhr.send('请求体数据')
<!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">
<title>XMLHttpRequest-数据提交</title>
</head>
<body>
<h2>XMLHttpRequest-数据提交</h2>
<button class="btn">点击注册</button>
<script>
/**
* 需求:使用xhr进行数据提交-完成注册功能
*/
const btn = document.querySelector('.btn')
btn.addEventListener('click', function () {
// 创建xhr对象
const xhr = new XMLHttpRequest()
// 请求方法及url
xhr.open('post', 'https://hmajax.itheima.net/api/register')
// 监听loadend事件,接收响应结果
xhr.addEventListener('loadend', function () {
console.log(xhr.response)
// {"code":10000,"message":"注册成功","data":{"id":182739,"account":"chlchl115"}}
})
const data = JSON.stringify({
username: 'chlchl115',
password: '123456'
})
// body 参数
// 1.设置请求头:内容类型是application/json;
// 2.发送数据,把这个数据在发送之前转json
xhr.setRequestHeader("Content-Type", "application/json")
// 发起请求
xhr.send(data)
})
</script>
</body>
</html>
2. Promise
2.1 认识-Promise
/*
Promise
浏览器的内置对象,管理异步操作,接收成功或失败的结果
*/
// 使用步骤
// 1. 实例化Promise对象
const p = new Promise((resolve, reject) => {
// 2. 执行异步操作,并传递结果
// 成功 resolve(成功结果) then()执行
// 失败 reject(失败结果) catch()执行
})
// 3. 接收结果
p.then(res => {
// 成功
}).catch(err => {
// 失败
})
const p = new Promise((resolve, reject) => {
resolve('成功')
reject('失败')
})
p.then(res => {
console.log(res)
}).catch(error => {
console.log(error)
})
2.2 了解-Promise的状态
/* Promise的状态:
一个Promise必然处于以下几种状态之一(3种)
1. pending 待定(默认状态),既没有被兑现,也没有被拒绝: 实例化
2. fullfilled 已兑现(成功): resolve -》then
3. rejected 已拒绝(失败) : reject -》catch
Promise对象一旦被兑现/拒绝,就是已敲定了,状态无法再改变
*/
2.3 案例2-Promise + XHR 获取省份列表
<!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">
<title>案例-使用 Promise+XHR 获取省份列表</title>
</head>
<body>
<h2>案例-使用 Promise+XHR 获取省份列表</h2>
<button class="success">请求成功</button>
<button class="err">请求异常</button>
<div class="box"></div>
<script>
const p = new Promise((resolve, reject) => {
const xhr = new XMLHttpRequest()
xhr.open('get', 'https://hmajax.itheima.net/api/province')
xhr.addEventListener('loadend', function () {
// document.querySelector('')
if (xhr.status >= 200 && xhr.status < 300) {
resolve(JSON.parse(xhr.response))
} else {
reject(xhr.response)
}
})
xhr.send()
})
p.then(res => {
console.log('成功', res)
}).catch(error => {
console.log('失败', error)
})
</script>
</body>
</html>
3. 封装-简易axios
3.1 封装-简易axios-获取省份列表
<!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">
<title>封装-简易axios函数-获取省份列表</title>
</head>
<body>
<h2>封装-简易axios-获取省份列表</h2>
<div class="box"></div>
<script>
// 封装 - 简易axios - 获取省份列表
function myAxios(config) {
return new Promise((resolve, reject) => {
const xhr = new XMLHttpRequest()
xhr.open(config.method || 'get', config.url)
xhr.addEventListener('loadend', function () {
if (xhr.status >= 200 && xhr.status < 300) {
resolve(JSON.parse(xhr.response))
} else {
reject(xhr.response)
}
})
xhr.send()
})
}
// 获取省份列表
myAxios({
url: 'https://hmajax.itheima.net/api/province'
}).then(res => {
console.log(res)
}).catch(error => {
console.log(error)
})
// 获取新闻列表
myAxios({
url: 'https://hmajax.itheima.net/api/news'
}).then(res => {
console.log(res)
}).catch(error => {
console.log(error)
})
</script>
</body>
</html>
3.2 封装-简易axios-获取地区列表
<!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">
<title>封装-简易axios函数-获取地区列表</title>
</head>
<body>
<h2>封装-简易axios函数-获取地区列表</h2>
<div class="box"></div>
<script>
// 封装 - 简易axios函数 - 获取地区列表
function myAxios(config) {
return new Promise((resolve, reject) => {
const xhr = new XMLHttpRequest()
// params 查询参数
if (config.params) {
const params = new URLSearchParams(config.params)
config.url = config.url + `?${params.toString()}`
}
xhr.open(config.method || 'get', config.url)
xhr.addEventListener('loadend', function () {
if (xhr.status >= 200 && xhr.status < 300) {
resolve(JSON.parse(xhr.response))
} else {
reject(xhr.response)
}
})
xhr.send()
})
}
// 获取地区列表 有查询参数
myAxios({
url: 'https://hmajax.itheima.net/api/area',
params: {
pname: '河北省',
cname: '邯郸市'
}
}).then(res => {
console.log(res.list)
document.querySelector('.box').innerHTML = res.list.join('--')
}).catch(error => {
console.log(error)
})
// 英雄百科-搜素 有查询参数
myAxios({
url: 'https://hmajax.itheima.net/api/lol/search',
params: {
q: '安'
}
}).then(res => {
console.log(res.data)
}).catch(error => {
console.log(error)
})
// 获取-新闻列表 无查询参数
myAxios({
url: 'https://hmajax.itheima.net/api/news',
}).then(res => {
console.log(res.data)
}).catch(error => {
console.log(error)
})
</script>
</body>
</html>
3.3 封装-简易axios-注册用户
<!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">
<title>封装-简易axios函数-注册用户</title>
</head>
<body>
<h2>封装-简易axios函数-注册用户</h2>
<button class="btn">注册用户</button>
<script>
// 封装 - 简易axios函数 - 注册用户
function myAxios(config) {
return new Promise((resolve, reject) => {
const xhr = new XMLHttpRequest()
// 判断是否有params查询参数
if (config.params) {
const params = new URLSearchParams(config.params)
config.url = config.url + `?${params.toString()}`
}
xhr.open(config.method || 'get', config.url)
xhr.addEventListener('loadend', function () {
if (xhr.status >= 200 && xhr.status < 300) {
resolve(JSON.parse(xhr.response))
} else {
reject(JSON.parse(xhr.response))
}
})
// data:提交数据,用于设置请求体的数据。data对应body
// 通常用于 POST、PUT 和 PATCH 请求,因为这些请求通常将数据作为请求体发送。
if (config.data) {
const data = JSON.stringify(config.data)
xhr.setRequestHeader("Content-Type", "application/json")
xhr.send(data)
} else {
xhr.send()
}
})
}
// 注册账号
myAxios({
url: 'https://hmajax.itheima.net/api/register',
method: 'post',
data: {
username: 'chlchl116',
password: '123456'
}
}).then(res => {
console.log(res)
}).catch(error => {
console.log(error)
})
// 登录
myAxios({
url: 'https://hmajax.itheima.net/api/login',
method: 'post',
data: {
username: 'chlchl116',
password: '123456'
}
}).then(res => {
console.log(res)
}).catch(error => {
console.log(error)
})
</script>
</body>
</html>
3.4 案例3-天气预报
myAxios
function myAxios(config) {
return new Promise((resolve, reject) => {
const xhr = new XMLHttpRequest();
// 判断是否有params查询参数
if (config.params) {
const params = new URLSearchParams(config.params);
config.url = config.url + `?${params.toString()}`;
}
xhr.open(config.method || "get", config.url);
xhr.addEventListener("loadend", function () {
if (xhr.status >= 200 && xhr.status < 300) {
resolve(JSON.parse(xhr.response));
} else {
reject(JSON.parse(xhr.response));
}
});
// data:提交数据,用于设置请求体的数据。data对应body
// 通常用于 POST、PUT 和 PATCH 请求,因为这些请求通常将数据作为请求体发送。
if (config.data) {
const data = JSON.stringify(config.data);
xhr.setRequestHeader("Content-Type", "application/json");
xhr.send(data);
} else {
xhr.send();
}
});
}
js
// 1. 封装查询天气函数 并渲染到页面
function getWeather(city) {
myAxios({
url: "https://hmajax.itheima.net/api/weather",
params: {
city,
},
})
.then((res) => {
// console.log(res);
// console.log(res.data);
const {
area, // √
date, // √
dateLunar,
// dateShort,
dayForecast,
psPm25,
psPm25Level,
temperature,
todayWeather,
weather,
weatherImg, // √
windDirection,
windPower,
} = res.data;
// console.log(date);
/* Object.keys(res.data).forEach((key) => {
if (key == "dayForecast") {
} else if (key == "todayWeather") {
} else if (key == "weatherImg") {
document.querySelector(`.${key}`).src = res.data[key];
} else {
document.querySelector(`.${key}`).innerHTML = res.data[key];
}
}); */
document.querySelector(".title").innerHTML = `
<span class="date">${date}</span>
<span class="calendar">农历
<span class="dateLunar">${dateLunar}</span>
</span>
`;
document.querySelector(".area").innerHTML = area;
document.querySelector(".weather-box").innerHTML = `
<div class="tem-box">
<span class="temp">
<span class="temperature">${temperature}</span>
<span>°</span>
</span>
</div>
<div class="climate-box">
<div class="air">
<span class="psPm25">${psPm25}</span>
<span class="psPm25Level">${psPm25Level}</span>
</div>
<ul class="weather-list">
<li>
<img src=${weatherImg} class="weatherImg" alt="">
<span class="weather">${weather}</span>
</li>
<li class="windDirection">${windDirection}</li>
<li class="windPower">${windPower}</li>
</ul>
</div>
`;
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 = 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("");
})
.catch((error) => {
console.log(error);
});
}
// 2. 默认查询北京天气
getWeather("110100");
// 3. 城市查询
const searchCity = document.querySelector(".search-city");
// const searchList = document.querySelector(".search-list");
// 3.1 性能优化 利用lodash的debounce方法生成防抖函数(或使用间歇函数做)
// 函数表达式,需先定义后使用(类似常量变量)
const fn = _.debounce(function () {
const city = searchCity.value.trim();
myAxios({
url: "https://hmajax.itheima.net/api/weather/city",
params: {
city,
},
}).then((res) => {
console.log(res.data);
document.querySelector(".search-list").innerHTML = res.data
.map((item) => {
return `
<li class="city-item" data-code="${item.code}">${item.name}</li>
`;
})
.join("");
});
}, 800);
searchCity.addEventListener("input", fn);
// 3.2 自做 性能差 输入框内只要有变化就会向服务器发送请请求
// input事件 搜索框内只要有数据 --> 下面列表就渲染城市数据,不用键盘事件keyup与回车Enter
// searchCity.addEventListener("keyup", function (e) {
/* searchCity.addEventListener("input", function () {
// if (e.key === "Enter") {
// console.log(1);
// trim()方法 字符串去两边空格
const city = searchCity.value.trim();
myAxios({
url: "https://hmajax.itheima.net/api/weather/city",
params: {
city,
},
}).then((res) => {
console.log(res.data);
document.querySelector(".search-list").innerHTML = res.data
.map((item) => {
return `
<li class="city-item" data-code="${item.code}">${item.name}</li>
`;
})
.join("");
});
// }
}); */
// 4. 点击查询城市天气
document.querySelector(".search-list").addEventListener("click", function (e) {
if (e.target.classList.contains("city-item")) {
getWeather(e.target.dataset.code);
}
searchCity.value = "";
});