AJAX-笔记(持续更新中)

文章目录

资料:
素材与资料都来自黑马程序员
思维导图
mdn网址

Day1 Ajax入门

1.AJAX概念和axios的使用

概念:AJAX是浏览器与服务器进行数据通信的技术

作用:浏览器和服务器之间通信,动态数据交互。

怎么使用AJAX?

1.先使用axios库,与服务器进行数据通信(使用场景:VUE,reat项目都会用到axios)

2.再学习XMLHttpREquest对象的使用,理解AJAX底层原理

axios使用:

  • 1.引入axios库:
    <script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
  • 2.使用axios函数
    √ 传入配置对象
    √ 再用.then回调函数接收结果,并做后续的处理
javascript 复制代码
axios({
	url:'目标资源地址'
}).then(result => {
//对服务器进行后续的处理
})

2. 认识URL

URL:统一资源定位符,网址,用于访问服务器资源

解释url每个部分的作用:

http://hmajax.itheima.net /api/login
协议域名 资源路径

3.URL的查询参数

定义:浏览器提供给服务器额外信息,让服务器返回浏览器想要的数据

语法:http://xxxx.com/xxx/xxx?参数名1=值1\&参数名2=值2

URL的查询参数的作用:浏览器提供给服务器额外信息,获取对应的数据

axios-查询参数:
使用params选项,携带参数名和值
axios在运行时把参数名和值,会拼接到url?参数名=值

javascript 复制代码
axios({
	url:'目标资源地址',
	params:{
	参数名:值
}).then(result => {
//对服务器进行后续的处理
})

4.常用的请求方法和数据提交

请求方法:对服务器资源,要执行的操作

请求方法 操作
GET 获取数据
POST 数据提交
PUT 修改数据(全部)
DELETE 删除数据
PATCH 修改数据(部分)

数据提交:当数据需要在服务器上保存

axios请求配置:

  • url:请求的URL网址
  • method:请求的方法,GET可以省略(不区分大小写)
  • data:提交数据
javascript 复制代码
axios({
	url:'目标资源地址',
	params:{
	参数名:值
	},
	data:{
	参数名:值
	}
}).then(result => {
//对服务器进行后续的处理
})

axios-错误处理

javascript 复制代码
axios({
	//请求选项
}).then(result => {
   //处理数据
}).catch(error => {
   //处理错误
})

5.HTTP协议-报文

  • 请求报文:浏览器发送给服务器的内容叫做请求报文
  • 请求报文的组成:

1.请求行:请求方法,URL,协议

2.请求头:以键值对的格式携带的附加信息,比如Content-Type

3.空行:分隔请求头,空行之后的是发送给服务器的资源(感觉我的浏览器有点不一样)

4.请求体:发送的资源

  • 通过Chrome的网络面板查看请求报文


响应报文的组成:

  • 1.响应行:协议、Http响应状态码、状态信息
  • 2.响应头:键值对的格式携带的附加信息,比如Content-Type
  • 3.空行:分隔响应头,空行之后的是返回给浏览器的资源
  • 4.响应体:返回的资源

Http响应状态码:用来表明请求是否成功完成。

状态码 说明
1xx 信息
2xx 成功
3xx 重定向消息
4xx 客户端错误
5xx 服务端错误

6.接口文档

接口文档:由后端提供的描述接口的文章

7.form-serialize插件

作用:快速收集表单元素的值。

素材:

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>13.form-serialize插件使用</title>
</head>

<body>
  <form action="javascript:;" class="example-form">
    <input type="text" name="uname">
    <br>
    <input type="text" name="pwd">
    <br>
    <input type="button" class="btn" value="提交">
  </form>
  <!-- 
    目标:在点击提交时,使用form-serialize插件,快速收集表单元素值
  -->
  <script>
    document.querySelector('.btn').addEventListener('click', () => {
      
    })
  </script>
</body>

</html>
javascript 复制代码
 <script src="./lib/form-serialize.js"></script>
  <script>
    document.querySelector('.btn').addEventListener('click', () => {
      /* 
      2.使用serialize函数,快速收集表单元素的值
      参数1:要获得哪个表单的数据
      表单元素设置name属性,值会作为对象的属性名
      建议name属性的值,最好和接口文档参数名一致
      参数2:配置对象
      hash:设置获取数据结构
          -true:JS对象(推荐) 一般请求体里提交给服务器
          -false;查询字符串
      empty:设置是否获取空值
          -true:获取空值(推荐)数据结构和标签结构一致
          -false:不获得空值
      */
     const form = document.querySelector('.example-form')
    //  const data = serialize(form,{hash:true,empty:true})
    //  const data = serialize(form,{hash:false,empty:true})
    const data = serialize(form,{hash:true,empty:false})
     console.log(data);
      
    })
  </script>

8.案例用户登录

素材:

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>12.案例_登录_提示消息</title>
  <!-- 引入bootstrap.css -->
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.2/dist/css/bootstrap.min.css">
  <!-- 公共 -->
  <style>
    html,
    body {
      background-color: #EDF0F5;
      width: 100%;
      height: 100%;
      display: flex;
      justify-content: center;
      align-items: center;
    }

    .container {
      width: 520px;
      height: 540px;
      background-color: #fff;
      padding: 60px;
      box-sizing: border-box;
    }

    .container h3 {
      font-weight: 900;
    }
  </style>
  <!-- 表单容器和内容 -->
  <style>
    .form_wrap {
      color: #8B929D !important;
    }

    .form-text {
      color: #8B929D !important;
    }
  </style>
  <!-- 提示框样式 -->
  <style>
    .alert {
      transition: .5s;
      opacity: 0;
    }

    .alert.show {
      opacity: 1;
    }
  </style>
</head>

<body>
  <div class="container">
    <h3>欢迎-登录</h3>
    <!-- 登录结果-提示框 -->
    <div class="alert alert-success" role="alert">
      提示消息
    </div>
    <!-- 表单 -->
    <div class="form_wrap">
      <form>
        <div class="mb-3">
          <label for="username" class="form-label">账号名</label>
          <input type="text" class="form-control username">
        </div>
        <div class="mb-3">
          <label for="password" class="form-label">密码</label>
          <input type="password" class="form-control password">
        </div>
        <button type="button" class="btn btn-primary btn-login"> 登 录 </button>
      </form>
    </div>
  </div>
  <script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
  <script>
    // 目标1:点击登录时,用户名和密码长度判断,并提交数据和服务器通信
    // 目标2:使用提示框,反馈提示消息
    
    // 1.1 登录-点击事件
    document.querySelector('.btn-login').addEventListener('click', () => {
      // 1.2 获取用户名和密码
      const username = document.querySelector('.username').value
      const password = document.querySelector('.password').value
      // console.log(username, password)

      // 1.3 判断长度
      if (username.length < 8) {
        console.log('用户名必须大于等于8位')
        return // 阻止代码继续执行
      }
      if (password.length < 6) {
        console.log('密码必须大于等于6位')
        return // 阻止代码继续执行
      }

      // 1.4 基于axios提交用户名和密码
      // console.log('提交数据到服务器')
      axios({
        url: 'http://hmajax.itheima.net/api/login',
        method: 'POST',
        data: {
          username,
          password
        }
      }).then(result => {
        console.log(result)
        console.log(result.data.message)
      }).catch(error => {
        console.log(error)
        console.log(error.response.data.message)
      })
    })
  </script>
</body>

</html>
javascript 复制代码
 <script>
    // 目标1:点击登录时,用户名和密码长度判断,并提交数据和服务器通信
    // 目标2:使用提示框,反馈提示消息
    
    // 1.1 登录-点击事件
    document.querySelector('.btn-login').addEventListener('click', () => {
      // 1.2 获取用户名和密码
      const username = document.querySelector('.username').value
      const password = document.querySelector('.password').value
      // console.log(username, password)

      // 1.3 判断长度
      if (username.length < 8) {
        console.log('用户名必须大于等于8位')
        return // 阻止代码继续执行
      }
      if (password.length < 6) {
        console.log('密码必须大于等于6位')
        return // 阻止代码继续执行
      }

      // 1.4 基于axios提交用户名和密码
      // console.log('提交数据到服务器')
      axios({
        url: 'http://hmajax.itheima.net/api/login',
        method: 'POST',
        data: {
          username,
          password
        }
      }).then(result => {
        console.log(result)
        console.log(result.data.message)
      }).catch(error => {
        console.log(error)
        console.log(error.response.data.message)
      })
    })
  </script>

Day2 Ajax综合案

bootstrap弹框

bootstrap中文文档

  • 属性控制方式
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>Bootstrap 弹框</title>
  <!-- 引入bootstrap.css -->
  <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.2/dist/css/bootstrap.min.css" rel="stylesheet">
</head>

<body>
  <!-- 
    目标:使用Bootstrap弹框
    1. 引入bootstrap.css 和 bootstrap.js
    2. 准备弹框标签,确认结构
    3. 通过自定义属性,控制弹框的显示和隐藏
   -->
  <button type="button" class="btn btn-primary" data-bs-target = '.my-box' data-bs-toggle="modal">
    显示弹框
  </button>
  <!-- 弹框标签 
   bootstrap的标签modal弹框:添加modal类名(默认隐藏)
  
  -->
  <div class="modal my-box" tabindex="-1">
    <div class="modal-dialog">
      <!-- 弹框内容 -->
      <div class="modal-content">
        <div class="modal-header">
          <h5 class="modal-title">Modal title</h5>
          <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
        </div>
        <div class="modal-body">
          <p>Modal body text goes here.</p>
        </div>
        <div class="modal-footer">
          <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>
          <button type="button" class="btn btn-primary">Save changes</button>
        </div>
      </div>
    </div>
  </div>

  <!-- 引入bootstrap.js -->
  <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.2.2/dist/js/bootstrap.min.js"></script>
</body>

</html>
  • js属性控制
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>Bootstrap 弹框</title>
  <!-- 引入bootstrap.css -->
  <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.2/dist/css/bootstrap.min.css" rel="stylesheet">
</head>

<body>
  <!-- 
    目标:使用JS控制弹框,显示和隐藏
    1. 创建弹框对象
    2. 调用弹框对象内置方法
      .show() 显示
      .hide() 隐藏
   -->
  <button type="button" class="btn btn-primary edit-btn">
    编辑姓名
  </button>

  <div class="modal name-box" tabindex="-1">
    <div class="modal-dialog">
      <div class="modal-content">
        <div class="modal-header">
          <h5 class="modal-title">请输入姓名</h5>
          <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
        </div>
        <div class="modal-body">
          <form action="">
            <span>姓名:</span>
            <input type="text" class="username">
          </form>
        </div>
        <div class="modal-footer">
          <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">取消</button>
          <button type="button" class="btn btn-primary save-btn">保存</button>
        </div>
      </div>
    </div>
  </div>

  <!-- 引入bootstrap.js -->
  <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.2.2/dist/js/bootstrap.min.js"></script>
  <script>
    // q.创建弹框对象
    const modalDom = document.querySelector('.name-box')
    const modal = new bootstrap.Modal(modalDom)


    // 编辑姓名-->点击-->赋予默认姓名 -->弹框显示
    document.querySelector('.edit-btn').addEventListener('click',()=>{
      document.querySelector('.username').value = '默认姓名'
      // 显示弹框
      modal.show()
    })
//  保存-->点击--->弹框隐藏
    document.querySelector('.save-btn').addEventListener('click',()=>{
      const username = document.querySelector('.username').value 
      console.log('模拟将姓名保存在服务器当中',username);
      // 隐藏弹框
      modal.hide()
    })
  </script>

</body>

</html>

图书管理

步骤如下:

  • 目标1:渲染图书列表
    1.1 获取数据
    1.2 渲染数据
javascript 复制代码
const creator = '老张'
// 封装-获取被渲染图书列表函数
function getBookList(){
    // 1.1获取数据
    axios({
        url:'http://hmajax.itheima.net/api/books',
        params:{
            // 外号:获取对应数据
            creator
        }
        
    }).then(result => {
        // console.log(result);
        // console.log(result.data.data);
        const bookList = result.data.data
        // 1.2渲染数据
        const htmlStr = bookList.map((item,index) => {
            return `
            <tr>
          <td>${index+1}</td>
          <td>${item.bookname}</td>
          <td>${item.author}</td>
          <td>${item.publisher}</td>
          <td data-id=${item.id}>
            <span class="del">删除</span>
            <span class="edit">编辑</span>
          </td>
        </tr>  
            `    
        }).join('')
        // console.log(htmlStr);
        document.querySelector('.list').innerHTML = htmlStr
    })
}
getBookList()
  • 目标2:新增图书
    2.1新增弹框-->显示和隐藏
    2.2 收集表单数据,并提交到服务器保存
    2.3 刷新图示列表
javascript 复制代码
// 2.1创建弹框对象
const addModalDom = document.querySelector('.add-modal')
const addModal =new bootstrap.Modal(addModalDom)
// 保存按钮->点击->隐藏弹框
document.querySelector('.add-btn').addEventListener('click',() => {
    // 2.2 收集表单数据,并提交到服务器
    const addForm = document.querySelector('.add-form')
    const bookObj = serialize(addForm,{hash:true,empty:true})
    console.log(bookObj);
//   提交到服务器
axios({
    url:'http://hmajax.itheima.net/api/books',
    method:'post',
    data:{
        ...bookObj,
        creator
    }
}).then(result => {
    console.log(result);
    // 2.3添加成功之后,重新请求并渲染图书列表
    getBookList()
    // 重置表单
    addForm.reset()
    // 隐藏弹框
    addModal.hide()

})
})
  • 目标3: 删除图书
    3.1 删除元素绑定点击事件 -> 获取图书id
    3.2 调用删除接口
    3.3刷新图书列表
javascript 复制代码
// 3.1 删除元素绑定点击事件 -> 获取图书id
// 事件委托
document.querySelector('.list').addEventListener('click',e => {
    // 获取触发事件目标元素
    // 判断点击的是删除元素
    if(e.target.classList.contains('del')){
        // console.log('删除元素');
        // 获取图书id(自定义属性)
        const theId = e.target.parentNode.dataset.id
        console.log(theId);
        // 3.2 调用删除接口
        axios({
            url:`http://hmajax.itheima.net/api/books/${theId}`,
            method:'delete'
        }).then(() => {
            // 3.3刷新图书列表
            getBookList()
        })

    }
})
  • 目标4:编辑图书
    4.1 编辑弹框->显示和隐藏
    4.2 获取当前编辑图书数据 -> 回显到编辑表单中
    4.3 提交保存修改,并刷新列表
javascript 复制代码
// 4.1 编辑弹框->显示和隐藏
const editDom = document.querySelector('.edit-modal')
const editModal = new bootstrap.Modal(editDom)
// 编辑元素 -> 点击弹框->弹框显示
document.querySelector('.list').addEventListener('click',e => {
    // 判断点击的是否是编辑元素
    if(e.target.classList.contains('edit')){
        // 4.2 获取当前编辑图书数据 -> 回显到编辑表单中
        const theId = e.target.parentNode.dataset.id
        axios({
            url:`http://hmajax.itheima.net/api/books/${theId}`
        }).then((result) => {
            const bookObj = result.data.data
            // 数据对象"属性"和标签"类名"一致
            // 遍历数据对象,使用属性去获得对应的标签,快速赋值
            const keys = Object.keys(bookObj)
            console.log(keys);// ['id', 'bookname', 'author', 'publisher']
            keys.forEach(key => {
                document.querySelector(`.edit-form .${key}`).value = bookObj[key]
            })
        })
        editModal.show()
    }
})
// 修改按钮->点击->隐藏弹框
document.querySelector('.edit-btn').addEventListener('click',()=>{
// 4.3 提交保存修改,并刷新列表
   const  editForm = document.querySelector('.edit-form')
   const{id,bookname,author,publisher} = serialize(editForm,{hash: true,empty:true})
//    保存正在编辑的图书id,隐藏起来:无需用户修改
// <input type="hidden" class="id" name="id" value="230530">
   axios({
    url:`http://hmajax.itheima.net/api/books/${id}`,
    method:'put',
    data:{
        bookname,author,publisher,creator
    }
   }).then(() => {
    // 修改成功以后,重新1获取并刷新列表
    getBookList()
   })

    editModal.hide()
})

图片上传

复制代码
   1. 获取图片文件
   2. 使用 FormData 携带图片文件
   3. 提交到服务器,获取图片url网址使用
javascript 复制代码
 <script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
  <script>
  
  //  文件选择元素->change事件
  document.querySelector('.upload').addEventListener('change',e => {
    // 1. 获取图片文件
    // console.dir(e.target)
    console.log(e.target.files[0]);

    // 2. 使用 FormData 携带图片文件
    const fd = new FormData()
    fd.append('img',e.target.files[0])

    // 3. 提交到服务器,获取图片url网址使用
    axios({
      url:'http://hmajax.itheima.net/api/uploadimg',
      method:'post',
      data:fd
    }).then(result => {
      console.log(result);
      // 取出url位置,用img标签加载显示
      const imgUrl = result.data.data.url
      document.querySelector('.my-img').src = imgUrl
    })


  })
    
  </script>

更换背景

复制代码
   目标:网站-更换背景
    1. 选择图片上传,设置body背景
    2. 上传成功时,"保存"图片url网址
    3. 网页运行后,"获取"url网址使用
javascript 复制代码
document.querySelector('.bg-ipt').addEventListener('change',e => {
    // 1. 选择图片上传,设置body背景
    // console.log(e.target.files[0]);
    const fd = new FormData()
    fd.append('img',e.target.files[0])
    //  提交到服务器,获取图片url网址使用
    axios({
        url:'http://hmajax.itheima.net/api/uploadimg',
        method:'post',
        data:fd
    }).then(result => {
    //    console.dir(result);  
    const imgUrl = result.data.data.url
    document.body.style.backgroundImage = `url(${imgUrl})`
    // 2. 上传成功时,"保存"图片url网址
    localStorage.setItem('bgImg',imgUrl)

    })
})


// 网页运行后,"获取"url网址使用
const bgUrl = localStorage.getItem('bgImg')
console.log(bgUrl);
bgUrl &&  (document.body.style.backgroundImage = `url(${bgUrl})`)

个人信息设置

复制代码
  目标1:信息渲染
   1.1 获取用户的数据
   1.2 回显数据到标签上
javascript 复制代码
const creator = '张三'
axios({
    url:`http://hmajax.itheima.net/api/settings`,
    params:{
        creator
    }
}).then(result => {
    const userObj = result.data.data
    console.log(userObj);
    // 1.2回显数据到标签上
    Object.keys(userObj).forEach(key => {
       
        if(key === 'avatar'){
             // 赋予默认头像
             document.querySelector('.prew').src = userObj[key]
        }else if(key === 'gender'){
            // 赋予默认性别
            // 获取性别单选框:[男radio元素,女radio元素]
            const gRadioList = document.querySelectorAll('.gender')
            // 获取性别数字:0男,1女
            const gNum = userObj[key]
            // 通过性别数字,作为下标,找到对应性别单选框,设置选中状态
            gRadioList[gNum].checked = true
        }else{
            // 赋予默认值
            document.querySelector(`.${key}`).value = userObj[key]
        }
    })
})
复制代码
目标2:修改头像
    2.1 获取头像文件
    2.2 提交服务器并更新头像
javascript 复制代码
// 文件选择元素->change事件
document.querySelector('.upload').addEventListener('change',e => {
    // 2.1获取头像
    console.log(e.target.files[0]);
    const fd = new FormData()
    fd.append('avatar',e.target.files[0])
    fd.append('creator',creator)
    // 2.2 提交服务器并更新头像
    axios({
        url:"http://hmajax.itheima.net/api/avatar",
        method:'put',
        data:fd
    }).then(result => {
        console.log(result);
        // data.data.avatar
        const imgUrl = result.data.data.avatar
        document.querySelector('.prew').src = imgUrl
    })

})

/*

复制代码
目标3:提交表单
	3.1 收集表单元素
	3.2 提交到服务器
目标4:结果显示
	4.1 创建toast对象
	4.2 调用show方法-> 显示提示框
javascript 复制代码
// 保存修改-点击
document.querySelector('.submit').addEventListener('click',() => {
    // 3.1 收集表单元素
    const userForm = document.querySelector('.user-form')
    const userObj = serialize(userForm,{hash:true,empty:true})
    userObj.creator = creator
    // 性别数字字符串,转成数字类型
    userObj.gender = +userObj.gender
    console.log(userObj);
    // 3.2提交给服务器
    axios({
        url:"http://hmajax.itheima.net/api/settings",
        method:'put',
        data:userObj
    }).then( result => {
        // 4.1 创建toast对象
    const toastDom = document.querySelector('.my-toast')
    const toast = new bootstrap.Toast(toastDom)
     // 4.2 调用show方法-> 显示提示框
     toast.show()
    })
})

Day3 AJAX原理

XMLHttpRequest

XMLHttpRequest(XHR)对象用于与服务器交互。通过 XMLHttpRequest 可以在不刷新页面的情况下请求特定 URL,获取数据。这允许网页在不影响用户操作的情况下,更新页面的局部内容。XMLHttpRequest 在 AJAX 编程中被大量使用。

AJAX原理:XMLHttpRequest对象;

学习XHR原因:

1.有更多与服务器数据通信方式

2.了解axios内部原理

XHR使用步骤:

  • 创建XHR对象
  • 调用open方法,设置url和请求方法
  • 监听loadend事件,接收结果
  • 调用send方法,发起请求
javascript 复制代码
let xhr = new XMLHttpRequest()
xhr.open('请求方法','请求url网址')
xhr.addEventlistener('loadend',()=>{
	//响应结果
	console.log(xhr.response)  接收响应
})
xhr.send() 发送请求




Promise

概念:表示(管理)一个异步操作最终状态和结果值的对象

好处:

1.逻辑清晰

2.了解axios函数内部运作机制

3.能解决回调函数地狱问题

学习promise对象原因:

√ 成功和失败状态,可以管理对于处理程序

√ 了解axios内部原理

promise使用步骤:

javascript 复制代码
  <script>
    /**
     * 目标:使用Promise管理异步任务
    */
    //  1.创建promise对象(pending待定状态)
    const p = new Promise((resolve, reject) => {
      // Promise对象创建,这里的代码都会执行
      // 2.执行代码
      setTimeout(() => {
        // resolve()=>'fulfilled状态--已兑现'=> then()   
        resolve('模拟AJAX请求-成功结果')
          // reject()=>'reject状态--已拒绝'=> catch
          ()
        reject(new Error('模拟AJAX请求-失败结果'))
      }, 2000)
    })


    console.log(p);
    // 3.获取结果
    p.then(result => {
      console.log(result);
    }).catch(error => {
      console.log(error);
    })
  </script>
复制代码
 目标:使用Promise管理XHR请求省份列表
    1. 创建Promise对象
    2. 执行XHR异步代码,获取省份列表
    3. 关联成功或失败函数,做后续处理
javascript 复制代码
 <script>
 
  //   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开头的都是成功响应状态码
            console.log(xhr);
            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>

封装简易版axios

复制代码
  目标:封装_简易axios函数_获取省份列表
  1. 定义myAxios函数,接收配置对象,返回Promise对象
  2. 发起XHR请求,默认请求方法为GET
  3. 调用成功/失败的处理程序
  4. 使用myAxios函数,获取省份列表展示
javascript 复制代码
<script>
 
    // 1. 定义myAxios函数,接收配置对象,返回Promise对象
   function myAxios(config){
    return new Promise((resolve,reject) =>{
      // 2. 发起XHR请求,默认请求方法为GET
      const xhr = new XMLHttpRequest()
      xhr.open('GET'||config.method,config.url)
      //  3. 调用成功/失败的处理程序
      xhr.addEventListener('loadend',()=>{
        if(xhr.status >= 200 && xhr.status < 300){
          resolve(JSON.parse(xhr.response))
        }else{
          reject(new Error(xhr.response))
        }
      })
      xhr.send()

    })
   }
   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.dir(error);
    document.querySelector('.my-p').innerHTML = error.message

   })
  </script>
复制代码
  目标:封装_简易axios函数_获取地区列表
    1. 判断有params选项,携带查询参数
    2. 使用URLSearchParams转换,并携带到url上
    3. 使用myAxios函数,获取地区列表
javascript 复制代码
<script>
    
    function myAxios(config) {
      if(config.params){
        const paramsObj = new URLSearchParams(config.params)
        const queryString = paramsObj.toString()
        config.url = config.url+`?${queryString}`
      }
      return new Promise((resolve, reject) => {
        const xhr = new XMLHttpRequest()
        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))
          }
        })
        xhr.send()
      })
    }
    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.dir详细打印
       console.dir(error);
      //  服务器返回错误提示消息,插入p标签

     document.querySelector('.my-p').innerHTML = error.message
    }) 
  </script>
复制代码
 目标:封装_简易axios函数_注册用户
  1. 判断有data选项,携带请求体
  2. 转换数据类型,在send中发送
  3. 使用myAxios函数,完成注册用户
javascript 复制代码
<script>
 
    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){
          // 告诉服务器,我传递的内容类型是JSON字符串
          xhr.setRequestHeader('Content-Type','application/json')
          // 准备数据并转成JSON字符串
          xhr.send(JSON.stringify(config.data))

        }else{
           xhr.send()
        }   
      })
    }
    document.querySelector('.reg-btn').addEventListener('click',() =>{
      myAxios({
      url:'http://hmajax.itheima.net/api/register',
      method:'POST',
      data:{
        username:'zz111111111222',
        password:'12345111226'
      }
    }).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>

案例-天气预报

复制代码
   目标1:默认显示-北京市天气
     	1.1 获取北京市天气数据
        1.2 数据展示到页面

// 获取并渲染城市天气函数

javascript 复制代码
function getWeather(cityCode){
// 1.1获取北京市天气数据

myAxios({
    url:'http://hmajax.itheima.net/api/weather',
   params:{
    city:cityCode 
  }

}).then(result => {
    console.log(result);
    const wObj = result.data
    // 1.2数据展示到页面
    const dateStr = `   <span class="dateShort">${wObj.date}</span>
    <span class="calendar">农历&nbsp;
      <span class="dateLunar">${wObj.dateLunar}</span>`
      document.querySelector('.title').innerHTML=dateStr
    //   城市名字
    document.querySelector('.area').innerHTML = wObj.area
    // 当天天气
    const nowWStr = ` 
     <div class="tem-box">
    <span class="temp">
      <span class="temperature">${wObj.temperature}</span>
      <span>°</span>
    </span>
  </div>
  <div class="climate-box">
    <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>
  </div>`
  document.querySelector('.weather-box').innerHTML = nowWStr
//   当前天气
 const twObj = wObj.todayWeather
 console.log(twObj);
 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>`
document.querySelector('.today-weather').innerHTML =  todayWStr
// 7天天气预报
const dayForecast = wObj.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">&lt;${item.windPower}</span>
    </div>
  </li>`
}).join('')
document.querySelector('.week-wrap').innerHTML=dayForecastStr

}).catch(error =>{
    console.log(error);

})
}
//默认进入网页-就要获取天气数据
getWeather('110100')
复制代码
目标2:搜索城市列表
	2.1绑定input手机开你,获取关键字
	2.2获取城市列表数据
javascript 复制代码
// 2.1绑定input手机开你,获取关键字
document.querySelector('.search-city').addEventListener('input',e => {
    // 2.2获取城市列表数据
    console.log(e.target.value);
    myAxios({
        url:'http://hmajax.itheima.net/api/weather/city',
        params:{
           city: e.target.value
        }
    }).then(result => {
        console.log(result);
        const liStr = result.data.map(item => {
            return `<li class="city-item" data-code=${item.code}>${item.name}</li>`
        }).join('')
        console.log(liStr);
         const a =document.querySelector('.search-list').innerHTML = liStr
        console.log(a);

    }).catch(error => {
        console.dir(error)
    })
})
复制代码
目标3:切换城市天气
	3.1绑定城市点击事件,获取城市code值
	3.2 调用获取并展示天气的函数
javascript 复制代码
document.querySelector('.search-list').addEventListener('click',e => {
    if(e.target.tagName === 'LI'){
        getWeather(e.target.dataset.code)
    }
})

Day4 AJAX进阶

同步代码和异步代码

同步代码:逐行执行,需原地等待结果后,才继续向下执行

异步代码:调用后耗时,不阻塞代码继续执行(不必原地等待),在将来完成后触发一个回调函数。

Js中的异步代码:setTimeout/setInterval,事件,AJAX

回调函数地狱和Promise链式调用

1.回调函数地狱
在回调函数一直向下嵌套回调函数,形成回调函数地狱

目标:演示回调函数地狱

需求:获取默认第一个省,第一个市,第一个地区并展示在下拉菜单中

概念:在回调函数中嵌套回调函数,一直嵌套下去就形成了回调函数地狱

缺点:可读性差,异常无法获取,耦合性严重,牵一发动全身

javascript 复制代码
 <script>
 
   axios({url:'http://hmajax.itheima.net/api/province'}).then(result => {
    const pname = result.data.list[0]
    document.querySelector('.province').innerHTML = pname
    // 2.获取默认第一个城市的名字
    axios({url:'http://hmajax.itheima.net/api/city', params:{pname}}).then(result => {
      const cname = result.data.list[0]
      document.querySelector('.city').innerHTML = cname
      // 3.获取默认第一个地区的名字
      axios({url:'http://hmajax.itheima.net/api/area',params:{pname,cname}}).then(result => {
        const areaName = result.data.list[0]
        document.querySelector('.area').innerHTML = areaName
      })

    })
    
   })
    
  </script>

2.Promise的链式调用--入门

概念:依靠then()方法会返回一个新生成的Promise对象特性,继续初恋下一环任务,直到结束

细节:then()回调函数中的返回值,会影响新生成的Promise对象最终状态和结果

目标:掌握Promise的链式调用

需求:把省市的嵌套结构,改成链式调用的线性结构

javascript 复制代码
  <script>
  
    //  1.创建Promise对象-模拟请求省份名字
    const p = new Promise((resolve, reject) => {
      setTimeout(() => {
        resolve('北京市')
      }, 2000)
    })

    // 2.获取省份的名字
    const p2 = p.then(result => {
      return new Promise((resolve, reject) => {
        setTimeout(() => {
          resolve(result + '-----北京市')
        }, 2000)
      })
    })

    // 4.获取城市名字
    p2.then(result => {
      console.log(result);
    })

  </script>

3.解决回调函数地狱

复制代码
目标:把回调函数嵌套代码,改成Promise链式调用结构
需求:获取默认第一个省,第一个市,第一个地区并展示在下拉菜单中
javascript 复制代码
 <script>
  
    let pname = ''
    axios({url:'http://hmajax.itheima.net/api/province'}).then(result => {
    pname = result.data.list[0]
    document.querySelector('.province').innerHTML = pname
    // 2.获取默认第一个城市的名字
    return axios({url:'http://hmajax.itheima.net/api/city', params:{pname}}).then(result => {
      const cname = result.data.list[0]
      document.querySelector('.city').innerHTML = cname
      // 3.获取默认第一个地区的名字
      return axios({url:'http://hmajax.itheima.net/api/area',params:{pname,cname}}).then(result => {
        const areaName = result.data.list[0]
        document.querySelector('.area').innerHTML = areaName
      })

    })
    
   })

async和await使用

概念;在async函数内,使用await关键字取代then函数,等待获取Promise对象成功状态的结果值

async函数和await捕获错误:使用 try...catch...

javascript 复制代码
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
  <script>
    /**
     * 目标:掌握async和await语法,解决回调函数地狱
     * 概念:在async函数内,使用await关键字,获取Promise对象"成功状态"结果值
     * 注意:await必须用在async修饰的函数内(await会阻止"异步函数内"代码继续执行,原地等待结果)
    */
  //  1.定义async修饰函数
  async function getData(){
   try {
   /*要执行的代码*/
    const pObj = await axios({url:'http://hmajax.itheima.net/api/province'})
    const pname = pObj.data.list[0]
    const cObj = await axios({url:'http://hmajax.itheima.net/api/city',params:{pname}})
    const cname = cObj.data.list[0]
    const aObj = await axios({url:'http://hmajax.itheima.net/api/area1',params:{pname,cname}})
    const areaName = aObj.data.list[0]
    document.querySelector('.province').innerHTML = pname
    document.querySelector('.city').innerHTML = cname
    document.querySelector('.area').innerHTML = areaName
    
   } catch (error) {
    /* error接收的是,错误信息
    try里代码,如果有错误,直接进入这里执行*/
    console.dir(error);
   }
  }
  getData()

  </script>

事件循环(EventLoop)

概念:JavaScript 有一个基于事件循环的并发模型,事件循环负责执行代码、收集和处理事件以及执行队列中的子任务。这个模型与其他语言中的模型截然不同,比如 C 和 Java。

原因;JavaScript单线程(某一时刻只能执行一行代码),为了让耗时代码不阻塞其他代码运行,设计了事件循环模型。

JavaScript内代码如何执行?

1.执行同步代码,遇到异步代码交给宿主浏览器环境执行

2.异步有了结果后,把回调函数放入任务队列排队

3.当调用栈空闲后,反复调用任务队列里的回调函数

javascript 复制代码
 <script>
    /**
     * 目标:阅读并回答执行的顺序结果
    */
    console.log(1)
    setTimeout(() => {
      console.log(2)
    }, 0)
    console.log(3)
    setTimeout(() => {
      console.log(4)
    }, 2000)
    console.log(5)
    
  </script>

事件循环练习

javascript 复制代码
 <script>
    /**
     * 目标:阅读并回答执行的顺序结果
     * 1 5 3 2 4 6(点击时触发)
    */
    console.log(1)
    setTimeout(() => {
      console.log(2)
    }, 0)
    function myFn() {
      console.log(3)
    }
    function ajaxFn() {
      const xhr = new XMLHttpRequest()
      xhr.open('GET', 'http://hmajax.itheima.net/api/province')
      xhr.addEventListener('loadend', () => {
        console.log(4)
      })
      xhr.send()
    }
    for (let i = 0; i < 1; i++) {
      console.log(5)
    }
    ajaxFn()
    document.addEventListener('click', () => {
      console.log(6)
    })
    myFn()
  </script>

事件·循环·练习

宏任务与微任务-执行任务

宏任务 :浏览器执行的异步代码,例如:JS执行脚本事件,setTimeout/setInterval,AJAX请求完成事件,用户交互事件等。

微任务:JS引擎执行的异步代码,例如:Promise对象.then()的回调

JavaScript内代码如何执行?

1.执行第一个script脚本时间宏任务,里面同步代码

2.遇到宏任务/微任务交给宿主环境,有结果回调函数进入对应队列

当执行栈空闲时,清空微任务队列,再执行下一个宏任务,从1再来

javascript 复制代码
  <script>
    // 目标:回答代码执行顺序
    console.log(1)
    setTimeout(() => {
      console.log(2)
      const p = new Promise(resolve => resolve(3))
      p.then(result => console.log(result))
    }, 0)
    const p = new Promise(resolve => {
      setTimeout(() => {
        console.log(4)
      }, 0)
      resolve(5)
    })
    p.then(result => console.log(result))
    const p2 = new Promise(resolve => resolve(6))
    p2.then(result => console.log(result))
    console.log(7)
  </script>

事件循环-执行过程

Promise.all静态方法

概念:合并多个Promise对象,等待所有提示成功完成(或某一个失败),做后续逻辑

javascript 复制代码
 <script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
  <script>
    /**
     * 目标:掌握Promise的all方法作用,和使用场景
     * 业务:当我需要同一时间显示多个请求的结果时,就要把多请求合并
     * 例如:默认显示"北京", "上海", "广州", "深圳"的天气在首页查看
     * code:
     * 北京-110100
     * 上海-310100
     * 广州-440100
     * 深圳-440300
    */
  //  1.请求城市天气,得到Promise对象
   const bjObj = axios({url:'http://hmajax.itheima.net/api/weather',params:{city:'110100'}})
   const shObj = axios({url:'http://hmajax.itheima.net/api/weather',params:{city:'310100'}})
   const gzObj = axios({url:'http://hmajax.itheima.net/api/weather',params:{city:'440100'}})
   const szObj = axios({url:'http://hmajax.itheima.net/api/weather',params:{city:'440300'}})
  //  console.log(bjObj,shObj, gzObj,szObj);
  // 2.使用 Promise.all,合并对各Promise对象
   const p = Promise.all([bjObj,shObj, gzObj,szObj])
   p.then(result => {
    console.log(result);
    // 注意:结果数组顺序和合并时顺序是一致的
    const htmlStr = result.map(item => {
      // 解构赋值
      const {area,weather}=item.data.data
      return `<li>${area}-----${weather}</li>`  
    }).join('')
    document.querySelector('.my-ul').innerHTML = htmlStr

   }).catch(error => {
    console.dir(eerror)

   })
  </script>

商品分类

复制代码
   目标:把所有商品分类"同时"渲染到页面上
    1. 获取所有一级分类数据
    2. 遍历id,创建获取二级分类请求
    3. 合并所有二级分类Promise对象
    4. 等待同时成功后,渲染页面
javascript 复制代码
 <script>

    // 1. 获取所有一级分类数据
   axios({url:'http://hmajax.itheima.net/api/category/top'}).then(result => {
    console.log(result);
    // 2. 遍历id,创建获取二级分类请求
    const promiseList = result.data.data.map(item =>{
       return axios({url:'http://hmajax.itheima.net/api/category/sub',params:{id:item.id}})
    })
    console.log(promiseList);
    // 3. 合并所有二级分类Promise对象
    const p = Promise.all(promiseList)
    p.then(result => {
      console.log(result);
      // 4. 等待同时成功后,渲染页面
      const htmlStr = result.map(item => {
        const obj = item.data.data
        return`<div class="item">
          
        <h3>一级分类名字:${obj.name}</h3>
        <ul>
          ${obj.children.map(item => {
             return `  <li>
            <a href="javascript:;">
              <img src=${item.picture}">
              <p>${item.name}</p>
            </a>
          </li>`
          }).join('')}
        
    
        </ul>
      </div>`
      }).join('')
      document.querySelector('.sub-list').innerHTML = htmlStr
    })
   

   })
  </script>

学习反馈

复制代码
 目标1:完成省市区下拉列表切换
  1.1 设置省份下拉菜单数据
  1.2 切换省份,设置城市下拉菜单数据,清空地区下拉菜单
  1.3 切换城市,设置地区下拉菜单数据


复制代码
  目标2:收集数据保存
  2.1 监听提交的点击事件
  2.2 依靠插件收集表单数据
  2.3 基于axios提交保存
javascript 复制代码
/**
 * 目标1:完成省市区下拉列表切换
 *  1.1 设置省份下拉菜单数据
 *  1.2 切换省份,设置城市下拉菜单数据,清空地区下拉菜单
 *  1.3 切换城市,设置地区下拉菜单数据
 */
// 1.1 设置省份下拉菜单数据
axios({url:'http://hmajax.itheima.net/api/province'}).then(result => {
    const optionStr = result.data.list.map(item => {
        return `  <option value="${item}">${item}</option>`
    }).join('')
    document.querySelector('.province').innerHTML=`<option value="">省份</option>`+optionStr
})

// 1.2 切换省份,设置城市下拉菜单数据,清空地区下拉菜单
document.querySelector('.province').addEventListener('change',async e => {
    // 获取用户选择的省份名字
    console.log(e.target.value);
    const result = await axios({url:'http://hmajax.itheima.net/api/city',params:{pname:e.target.value}}).then(result =>{
        const optionStr = result.data.list.map(item => {
            return `  <option value="${item}">${item}</option>`
        }).join('')
          // 把默认初始选项+下属城市数据插入select中   
        document.querySelector('.city').innerHTML=`<option value="">城市</option>`+optionStr 
          //    清空地区数据
        document.querySelector('.area').innerHTML= `<option value="">地区</option>`
    })
})

// 1.3 切换城市,设置地区下拉菜单数据

document.querySelector('.city').addEventListener('change',async e => {
    console.log(e.target.value);
    const result = await axios({url:'http://hmajax.itheima.net/api/area',
    params:{pname: document.querySelector('.province').value,
    cname:e.target.value}}).then(result =>{
        const optionStr = result.data.list.map(item => {
            return `  <option value="${item}">${item}</option>`
        }).join('')
            
        document.querySelector('.area').innerHTML=`<option value="">地区</option>`+optionStr 
         
    })
})
/* 
  目标2:收集数据保存
  2.1 监听提交的点击事件
  2.2 依靠插件收集表单数据
  2.3 基于axios提交保存
*/
// 2.1 监听提交的点击事件
document.querySelector('.submit').addEventListener('click',async ()=> {
    // 2.2 依靠插件收集表单数据
    const form =document.querySelector('.info-form')
    const data = serialize(form,{hash:true,empty:true})
    console.log(data);
    // 2.3 基于axios提交保存
    try {
        const result = await axios({
            url:'http://hmajax.itheima.net/api/feedback',
            method:'post',
            data 
        })
        console.log(result);
        alert(result.data.message)
        
    } catch (error) {
        console.dir(error);
        alert(error.response.data.message)
        
    }

})

总结

学习了这门课程,AJAX的大概知识我都清楚了,也在学习过程中,我得到了一些学习经验,比如,看完一天的视频,要回去复习,不然容易忘记,边看视频边敲代码边理解或者看完一天视频再敲代码,可能带着回忆的状态,这样子可以检验自己是否真的懂(可能这个方法会好一点,因人而异),还有就是代码也不是敲一遍就行的,最多敲三遍,最后一遍一定是自己明白了,在不借助外力的情况下,自己敲(虽然但是,我还没达到那种境界,在努力中)。

最后送大家一句话:博学之,审问之,慎思之,明辨之,笃行之。

相关推荐
诗句藏于尽头30 分钟前
内网使用rustdesk搭建远程桌面详细版
笔记
蜡笔小电芯30 分钟前
【C语言】指针与回调机制学习笔记
c语言·笔记·学习
丰锋ff43 分钟前
瑞斯拜考研词汇课笔记
笔记
DKPT2 小时前
Java享元模式实现方式与应用场景分析
java·笔记·学习·设计模式·享元模式
KoiHeng5 小时前
操作系统简要知识
linux·笔记
巴伦是只猫6 小时前
【机器学习笔记Ⅰ】11 多项式回归
笔记·机器学习·回归
DKPT10 小时前
Java桥接模式实现方式与测试方法
java·笔记·学习·设计模式·桥接模式
巴伦是只猫12 小时前
【机器学习笔记Ⅰ】13 正则化代价函数
人工智能·笔记·机器学习
X_StarX17 小时前
【Unity笔记02】订阅事件-自动开门
笔记·学习·unity·游戏引擎·游戏开发·大学生
MingYue_SSS17 小时前
开关电源抄板学习
经验分享·笔记·嵌入式硬件·学习