十六(AJAX3)、XMLHttpRequest、Promise、简易axios封装、案例天气预报

1. XMLHttpRequest

1.1 XMLHttpRequest-基本使用

javascript 复制代码
/* 
  定义: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()
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">
  <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-查询参数

javascript 复制代码
// 创建 URLSearchParams 对象
const params = new URLSearchParams({ key: value, key2: value2 })

// 生成查询参数 key=value&key2=value
const queryString = params.toString()
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">
  <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-地区查询

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">
  <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-数据提交

javascript 复制代码
/*
  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('请求体数据')
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">
  <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

javascript 复制代码
/* 
  Promise
  浏览器的内置对象,管理异步操作,接收成功或失败的结果
*/

// 使用步骤

// 1. 实例化Promise对象
const p = new Promise((resolve, reject) => {
  // 2. 执行异步操作,并传递结果
  // 成功 resolve(成功结果) then()执行
  // 失败 reject(失败结果) catch()执行
})

// 3. 接收结果
p.then(res => {
  // 成功
}).catch(err => {
  // 失败
})
javascript 复制代码
const p = new Promise((resolve, reject) => {
  resolve('成功')
  reject('失败')
})

p.then(res => {
  console.log(res)
}).catch(error => {
  console.log(error)
})

2.2 了解-Promise的状态

javascript 复制代码
/* Promise的状态:
  一个Promise必然处于以下几种状态之一(3种)
  1. pending 待定(默认状态),既没有被兑现,也没有被拒绝: 实例化
  2. fullfilled 已兑现(成功): resolve -》then
  3. rejected 已拒绝(失败) : reject -》catch

  Promise对象一旦被兑现/拒绝,就是已敲定了,状态无法再改变 
*/

2.3 案例2-Promise + XHR 获取省份列表

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">
  <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-获取省份列表

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">
  <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-获取地区列表

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">
  <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-注册用户

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">
  <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

javascript 复制代码
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

javascript 复制代码
// 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">农历&nbsp;
          <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">&lt;${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");

// input事件 搜索框内有数据 --> 下面列表就渲染城市数据,不用键盘事件keyup与回车Enter
// searchCity.addEventListener("keyup", function (e) {
searchCity.addEventListener("input", function (e) {
  // 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);
    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 = "";
});
相关推荐
西猫雷婶9 分钟前
python学opencv|读取图像(十六)修改HSV图像HSV值
开发语言·python·opencv
ordinary9018 分钟前
指令-v-for的key
前端·javascript·vue.js
weixin_5375904520 分钟前
《Java编程入门官方教程》第八章练习答案
java·开发语言·servlet
lsx20240624 分钟前
MVC 发布
开发语言
前端Hardy35 分钟前
HTML&CSS:酷炫的3D开关控件
前端·javascript·css·3d·html
qincjun41 分钟前
文件I/O操作:C++
开发语言·c++
小马超会养兔子1 小时前
如何写一个数字老虎机滚轮
开发语言·前端·javascript·vue
Web打印1 小时前
web打印插件 HttpPrinter 使用半年评测
javascript·json·firefox·jquery·html5
Mr。轩。1 小时前
Vue 单表 CRUD模板 前端
前端·javascript·vue.js
irisMoon061 小时前
react项目框架了解
前端·javascript·react.js