AJAX的原理(重点)

◆ XMLHttpRequest

什么是XMLHttpRequest?

定义:

关系:axios 内部采用 XMLHttpRequest 与服务器交互

注意:直白点说就是axios内部就是封装了XMLHttpRequest这个对象来实现发送异步请求的

使用 XMLHttpRequest

步骤:

  1. 创建 XMLHttpRequest 对象

  2. 配置请求方法和请求 url 地址

  3. 监听 loadend 事件,接收响应结果

  4. 发起请求

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 对象
  1. 为什么学习 XHR?
  • ➢ 有更多与服务器数据通信方式
  • ➢ 了解 axios 内部原理
  1. 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()
    }
  })
}

◆ 案例 - 天气预报

步骤:

  1. 获取北京市天气数据,展示

  2. 搜索城市列表,展示

  3. 点击城市,显示对应天气数据

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">农历&nbsp;
          <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">&lt;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">&lt;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">&lt;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">&lt;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">&lt;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">&lt;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">&lt;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">农历&nbsp;
          <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>
相关推荐
小政爱学习!13 分钟前
封装axios、环境变量、api解耦、解决跨域、全局组件注入
开发语言·前端·javascript
魏大帅。19 分钟前
Axios 的 responseType 属性详解及 Blob 与 ArrayBuffer 解析
前端·javascript·ajax
花花鱼25 分钟前
vue3 基于element-plus进行的一个可拖动改变导航与内容区域大小的简单方法
前端·javascript·elementui
k093328 分钟前
sourceTree回滚版本到某次提交
开发语言·前端·javascript
EricWang13581 小时前
[OS] 项目三-2-proc.c: exit(int status)
服务器·c语言·前端
September_ning1 小时前
React.lazy() 懒加载
前端·react.js·前端框架
web行路人1 小时前
React中类组件和函数组件的理解和区别
前端·javascript·react.js·前端框架
番茄小酱0011 小时前
Expo|ReactNative 中实现扫描二维码功能
javascript·react native·react.js
子非鱼9211 小时前
【Ajax】跨域
javascript·ajax·cors·jsonp
超雄代码狂1 小时前
ajax关于axios库的运用小案例
前端·javascript·ajax