AJAX day1

109 阅读4分钟

1、AJAX的概念

什么是 Ajax

Ajax 是浏览器中的技术:用来实现客户端网页请求服务器的数据。
它的英文全称是 Asynchronous Javascript And XML,简称 Ajax。

image.png

1.1 什么是服务器

  • 服务器就是一台电脑,一台能为客户端提供资源服务的电脑
  • 服务器的作用:
    • 用于存储一个网站的文件(HTML、CSS、JS、图片、音乐...)
  • 如何获取服务器
    • 购买(京东、淘宝...)
    • 租赁(阿里云、腾讯云...)

1.2 资源

  • 服务器上的网面(HTML文件)、图片、音乐、视频、字体文件、css文件、JS文件等等称之为资源。所以资源指的是服务器上存储的内容
  • 通俗的讲,我们浏览页面时,从网络当中看到的内容都叫资源。
资源分为静态资源和动态资源:
1、页面可以看到的内容叫静态资源
2、后台获取过来的数据叫动态资源

image.png

1.3 客户端

  • 概念:在前端开发中,客户端特指“Web 浏览器”。
  • 作用:将互联网世界中的 Web 资源加载、并呈现到浏览器窗口中供用户使用。
客户端在前端主要是指浏览器,客户端可以通过浏览器向服务器发起资源请求

1.4 交互方式

  • 1.4.1 客户端向服务器发起资源请求
  • 1.4.2 服务器进行处理
  • 1.4.3 服务器将处理结果响应给客户端
  • 1.4.4 前端主要关注的是:
    • 如何向服务器发起AJAX请求
    • 如果通过AJAX接收服务器处理完成响应回来的数据并进行处理

1.5 url

  • 统一资源定位,用来描述资源在服务器中的唯一地址
  • 通过url地址可以找到具体的资源
  • 资源地址的组成:
    • 服务器路径---基地址---基准路径--根路径(www.itcbc.com:3006) +
    • 资源路径(/api/getbooks)

2、请求方式

使用 Ajax 请求数据的 5 种方式

生活中,去银行办理业务有很多种类,比如有的客户去办卡,有的客户去销户,有的存钱,有的取钱。
Ajax中,客户端浏览器在请求服务器上的数据时,根据操作性质(增删改查)的不同,可以分为以下 5 种常见的操作。

image.png

2.1 GET请求

  • GET 请求用于从服务器获取(查询)数据

image.png

2.2 POST 请求

  • POST 请求用于向服务器新增数据
POST 请求一般用于表单登录、注册或者是上传大量数据

image.png

2.3 DELETE 请求

  • DELETE 请求用于删除服务器上的数据

image.png

2.4 PUT 请求

  • PUT 请求用于更新服务器上的数据(侧重于完整更新:例如更新用户的完整信息)

image.png

2.5 PATCH 请求

  • PATCH 请求用于更新服务器上的数据(侧重于部分更新:例如只更新用户的手机号)

image.png

3、axios发起请求

axios(发音:艾克C奥斯) 是前端圈最火的、专注于数据请求的库。

网站入口:

中文官网地址:www.axios-http.cn/

英文官网地址:www.npmjs.com/package/axi… image.png

3.1 使用步骤

  • 引入资源:在全局挂载一个axios,在js中可以直接使用
  • 调用axios的api发起请求
<script src="./lib/axios.js"></script>
axios({
    // 配置
    method: '请求方式',
    url: '请求的资源的完整地址:服务器地址+资源路径'
}).then(请求成功的回调函数(服务器响应的内容)=>{})

3.2 基于 axios 发起 GET 请求

axios({
  method: 'GET',
  url: 'http://www.itcbc.com:3006/api/getbooks'
}).then((result) => {
  console.log(result)
})
  • result的数据对象:
    • result是一个对象result.data 才是服务器返回的结果
{
  config: { url: 'http://xxxx', ss: 'xx' },
  data: { code: 0, message: '成功', data: ['xx', 'yy'] },
  headers: { 'content-length': '1054', },
  request: { readyState: 4 },
  status: 200,
  statusText: 'OK'
}
  • 刚才查询回来的是所有图书的列表数据,如果想指定查询的条件,可以通过 params 选项来指定查询的参数:

image.png

  • 如果要携带多个参数,只需要在 params 对象中指定多个查询参数项即可。示例代码如下:

image.png

3.3 基于 axios 发起 POST 请求

  • 使用 axios 发起 POST 请求时,只需要将 method 属性的值设置为 'POST' ,URL地址改为 '/api/addbook':
GET请求提交数据用 params
POST请求提交数据用 data

image.png

4、图书管理案例

图书管理实现步骤
        1. 实现图书管理页面的功能,包括:
           1.1 图书列表,包括:图书名称、作者、出版社、操作(添加、删除、编辑)
           1.2 图书列表的添加功能,添加的内容包括:图书名称、作者、出版社
           1.3 图书列表的删除功能,删除的内容包括:图书名称、作者、出版社
           1.4 图书列表的编辑功能,编辑的内容包括:图书名称、作者、出版社

image.png

image.png

HTML结构:

<!-- 栅格系统 -->
<div class="container-fluid">
  <!-- <button class="btn-success loadBook">加载图书数据</button> -->
  <!-- 栅格系统中的一行 -->
  <div class="row">
    <div class="col-sm-8">
      <table
        class="table table-bordered table-striped table-dark table-hover text-center"
      >
        <thead>
          <!-- 表头行 -->
          <tr>
            <th scope="col">Id</th>
            <th scope="col">书名</th>
            <th scope="col">作者</th>
            <th scope="col">出版社</th>
            <th scope="col">操作</th>
          </tr>
        </thead>
        <tbody>
          <!-- 表格中的每一行 -->
          <!-- <tr>
            <th scope="row">xxx</th>
            <td>xxx</td>
            <td>xxx</td>
            <td>xxx</td>
            <td>
              <button type="button" class="btn btn-link btn-sm">
                删除
              </button>
            </td>
          </tr> -->
        </tbody>
      </table>
    </div>

    <!-- 右侧的添加区域,占了 4 列 -->
    <div class="col-sm-4">
      <!-- 添加图书的卡片 -->
      <div class="card text-white bg-secondary sticky-top">
        <div class="card-header">添加新图书</div>
        <form class="card-body bg-light" id="addForm">
          <!-- 书名 -->
          <div class="input-group mb-3">
            <div class="input-group-prepend">
              <span class="input-group-text">书名</span>
            </div>
            <input
              type="text"
              class="form-control bookname"
              placeholder="请输入图书名称"
              name="bookname"
            />
          </div>
          <!-- 作者 -->
          <div class="input-group mb-3">
            <div class="input-group-prepend">
              <span class="input-group-text">作者</span>
            </div>
            <input
              type="text"
              class="form-control"
              placeholder="请输入作者名字"
              name="author"
            />
          </div>
          <!-- 出版社 -->
          <div class="input-group mb-3">
            <div class="input-group-prepend">
              <span class="input-group-text">出版社</span>
            </div>
            <input
              type="text"
              class="form-control"
              placeholder="请输入出版社名称"
              name="publisher"
            />
          </div>
          <!-- 添加按钮 -->
          <button class="btn btn-dark btnadd" type="submit">添加</button>
        </form>
      </div>
    </div>
  </div>
</div>

<!-- 编辑模态框 -->
<div
  class="modal fade"
  id="editModal"
  tabindex="-1"
  aria-labelledby="exampleModalLabel"
  aria-hidden="true"
>
  <div class="modal-dialog">
    <div class="modal-content">
      <div class="modal-header">
        <h5 class="modal-title" id="exampleModalLabel">图书编辑</h5>
        <button
          type="button"
          class="close"
          data-dismiss="modal"
          aria-label="Close"
        >
          <span aria-hidden="true">&times;</span>
        </button>
      </div>
      <div class="modal-body">
        <form class="card-body bg-light" id="editForm">
          <!-- 书名 -->
          <div class="input-group mb-3">
            <div class="input-group-prepend">
              <span class="input-group-text">书名</span>
            </div>
            <input
              type="text"
              class="form-control bookname"
              placeholder="请输入图书名称"
              name="editbookname"
            />
          </div>
          <!-- 作者 -->
          <div class="input-group mb-3">
            <div class="input-group-prepend">
              <span class="input-group-text">作者</span>
            </div>
            <input
              type="text"
              class="form-control"
              placeholder="请输入作者名字"
              name="editauthor"
            />
          </div>
          <!-- 出版社 -->
          <div class="input-group mb-3">
            <div class="input-group-prepend">
              <span class="input-group-text">出版社</span>
            </div>
            <input
              type="text"
              class="form-control"
              placeholder="请输入出版社名称"
              name="editpublisher"
            />
          </div>
        </form>
      </div>
      <div class="modal-footer">
        <button
          type="button"
          class="btn btn-secondary"
          data-dismiss="modal"
        >
          取消
        </button>
        <button type="button" class="btn btn-primary btnConfirm">
          确定
        </button>
      </div>
    </div>
  </div>
</div>

CSS代码:

<style>
  :root {
    font-size: 15px;
  }

  body {
    padding-top: 15px;
  }

  img {
    position: absolute;
    left: 400px;
    top: 100px;
    display: none;
  }
</style>

JS代码:

<script>
    // 事件委托
    let tbody = document.querySelector('tbody');
    // 获取添加按钮
    let btn = document.querySelector('button')
    // 获取新增的书名表单
    let bname = document.querySelector('#addForm [name="bookname"]')
    // 获取新增的作者表单
    let bauthor = document.querySelector('#addForm [name="author"]')
    // 获取新增的出版社表单
    let bpublisher = document.querySelector('#addForm [name="publisher"]')

    // 获取模块框的书名表单
    let editbookname = document.querySelector('#editForm [name="editbookname"]')
    // 获取模块框的作者表单
    let editauthor = document.querySelector('#editForm [name="editauthor"]')
    // 获取模块框的出版社表单
    let editpublisher = document.querySelector('#editForm [name="editpublisher"]')
    // 获取确定修改按钮
    let btnConfirm = document.querySelector('.btnConfirm')

    // 数据渲染
    function init() {
      // 发送请求
      axios({
        method: "get",
        url: "http://www.itcbc.com:3006/api/getbooks"
      }).then(res => {
        // 动态生成页面结构
        let html = "";
        res.data.data.forEach((value, index) => {
          html += `<tr>
                    <th scope="row">${index + 1}</th>
                    <td>${value.bookname}</td>
                    <td>${value.author}</td>
                    <td>${value.publisher}</td>
                    <td>
                      <button data-id="${value.id}" type="button" class="btn btn-link btn-sm btndel">
                        删除
                      </button>
                      <button type="button" data-id="${value.id}" data-bookname="${value.bookname}" data-author="${value.author}" data-publisher="${value.publisher}" class="btn btn-link btn-sm edit" >
                        编辑
                      </button>
                    </td>
                  </tr>
                `;
        });
        tbody.innerHTML = html;
      });
    }
    // 重新渲染页面
    init();

    // 新增数据
    btn.addEventListener('click', function(e) {
      // 阻止默认行为,让submit按钮不要实现页面跳转
      e.preventDefault()
      // 把新增书名的表单value值存到变量bookname里面
      let bookname = bname.value
      // 把新增作者的表单value值存到变量author里面
      let author = bauthor.value
      // 把新增出版社的表单value值存到变量author里面
      let publisher = bpublisher.value

      // 把表单的数据新增到后台数据
      let data = {
        bookname,
        author,
        publisher
      }
      // 发送请求
      axios({
        method: 'post',
        url: 'http://www.itcbc.com:3006/api/addbook',
        data
      }).then(res => {
        // 判断status的值如果是0表示成功
        if(res.data.status == 0) {
          // 弹出成功的文本
          alert(res.data.message);
          // 重新渲染页面
          init()
        }
      })
    })

    // 数据删除
    tbody.addEventListener('click', function(e) {
      // 事件委托,判断是否点了删除按钮
      if(e.target.classList.contains('btndel')) {
        // 获取删除按钮的自定义id
        let id = e.target.dataset.id;
        // 发起请求
        axios({
          method: 'delete',
          url: `http://www.itcbc.com:3006/api/delbook`,
          // 传递所要删除的内容对应的id
          params: {id}
        }).then(res => {
          if(res.data.status == 0) {
            alert(res.data.message);
            init();
          }
        })
      }
    })

    // 数据编辑
    let editId;
    // 事件委托
    tbody.addEventListener('click', function(e) {
      // 判断是否点击了编辑按钮
      if(e.target.classList.contains('edit')){
        // 让模态框显示
        $('#editModal').modal('show')
        // 获取自定义data属性
        let data = e.target.dataset
        // 确定编辑按钮也需要用到id,所以需要将它暴露到外部
        editId = data.id
        // 数据回填
        // 将书名填入模块框对应的书名表单
        editbookname.value = data.bookname
        // 将作者填入模块框对应的作者表单
        editauthor.value = data.author
        // 将出版社填入模块框对应的出版社表单
        editpublisher.value = data.publisher
      }
    })

    // 编辑修改数据
    btnConfirm.addEventListener('click', function() {
      // 将模块框表单修改之后的内容重新赋值给数据对象,定义一个data把它们存起来
      let data = {
        id: editId,
        bookname: editbookname.value,
        author: editauthor.value,
        publisher: editpublisher.value
      }
      // 发起请求
      axios({
        method: 'put',
        url: 'http://www.itcbc.com:3006/api/updatebook',
        // 把修改之后的数据存回数据库
        data
      }).then((res) => {
        if(res.data.status == 0) {
          alert(res.data.message);
          // 点击确定之后让模块框隐藏
          $('#editModal').modal('hide')
          init()
        }
      })
    })

</script>

完整代码:

<!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>Document</title>
    <!-- 引入 lib 目录下的 bootstrap 样式表 -->
    <link rel="stylesheet" href="./lib/bootstrap-v4.6.0.css" />
    <script src="./lib/axios.js"></script>
    <script src="./lib/jquery.js"></script>
    <script src="./lib/bootstrap-4.6.1-dist/js/bootstrap.js"></script>
    
    <style>
      :root {
        font-size: 15px;
      }

      body {
        padding-top: 15px;
      }

      img {
        position: absolute;
        left: 400px;
        top: 100px;
        display: none;
      }
    </style>
  </head>

  <body>
    <!-- 栅格系统 -->
    <div class="container-fluid">
      <!-- <button class="btn-success loadBook">加载图书数据</button> -->
      <!-- 栅格系统中的一行 -->
      <div class="row">
        <div class="col-sm-8">
          <table
            class="table table-bordered table-striped table-dark table-hover text-center"
          >
            <thead>
              <!-- 表头行 -->
              <tr>
                <th scope="col">Id</th>
                <th scope="col">书名</th>
                <th scope="col">作者</th>
                <th scope="col">出版社</th>
                <th scope="col">操作</th>
              </tr>
            </thead>
            <tbody>
              <!-- 表格中的每一行 -->
              <!-- <tr>
                <th scope="row">xxx</th>
                <td>xxx</td>
                <td>xxx</td>
                <td>xxx</td>
                <td>
                  <button type="button" class="btn btn-link btn-sm">
                    删除
                  </button>
                </td>
              </tr> -->
            </tbody>
          </table>
        </div>

        <!-- 右侧的添加区域,占了 4 列 -->
        <div class="col-sm-4">
          <!-- 添加图书的卡片 -->
          <div class="card text-white bg-secondary sticky-top">
            <div class="card-header">添加新图书</div>
            <form class="card-body bg-light" id="addForm">
              <!-- 书名 -->
              <div class="input-group mb-3">
                <div class="input-group-prepend">
                  <span class="input-group-text">书名</span>
                </div>
                <input
                  type="text"
                  class="form-control bookname"
                  placeholder="请输入图书名称"
                  name="bookname"
                />
              </div>
              <!-- 作者 -->
              <div class="input-group mb-3">
                <div class="input-group-prepend">
                  <span class="input-group-text">作者</span>
                </div>
                <input
                  type="text"
                  class="form-control"
                  placeholder="请输入作者名字"
                  name="author"
                />
              </div>
              <!-- 出版社 -->
              <div class="input-group mb-3">
                <div class="input-group-prepend">
                  <span class="input-group-text">出版社</span>
                </div>
                <input
                  type="text"
                  class="form-control"
                  placeholder="请输入出版社名称"
                  name="publisher"
                />
              </div>
              <!-- 添加按钮 -->
              <button class="btn btn-dark btnadd" type="submit">添加</button>
            </form>
          </div>
        </div>
      </div>
    </div>

    <!-- 编辑模态框 -->
    <div
      class="modal fade"
      id="editModal"
      tabindex="-1"
      aria-labelledby="exampleModalLabel"
      aria-hidden="true"
    >
      <div class="modal-dialog">
        <div class="modal-content">
          <div class="modal-header">
            <h5 class="modal-title" id="exampleModalLabel">图书编辑</h5>
            <button
              type="button"
              class="close"
              data-dismiss="modal"
              aria-label="Close"
            >
              <span aria-hidden="true">&times;</span>
            </button>
          </div>
          <div class="modal-body">
            <form class="card-body bg-light" id="editForm">
              <!-- 书名 -->
              <div class="input-group mb-3">
                <div class="input-group-prepend">
                  <span class="input-group-text">书名</span>
                </div>
                <input
                  type="text"
                  class="form-control bookname"
                  placeholder="请输入图书名称"
                  name="editbookname"
                />
              </div>
              <!-- 作者 -->
              <div class="input-group mb-3">
                <div class="input-group-prepend">
                  <span class="input-group-text">作者</span>
                </div>
                <input
                  type="text"
                  class="form-control"
                  placeholder="请输入作者名字"
                  name="editauthor"
                />
              </div>
              <!-- 出版社 -->
              <div class="input-group mb-3">
                <div class="input-group-prepend">
                  <span class="input-group-text">出版社</span>
                </div>
                <input
                  type="text"
                  class="form-control"
                  placeholder="请输入出版社名称"
                  name="editpublisher"
                />
              </div>
            </form>
          </div>
          <div class="modal-footer">
            <button
              type="button"
              class="btn btn-secondary"
              data-dismiss="modal"
            >
              取消
            </button>
            <button type="button" class="btn btn-primary btnConfirm">
              确定
            </button>
          </div>
        </div>
      </div>
    </div>

    <script>
        // 事件委托
        let tbody = document.querySelector('tbody');
        // 获取添加按钮
        let btn = document.querySelector('button')
        // 获取新增的书名表单
        let bname = document.querySelector('#addForm [name="bookname"]')
        // 获取新增的作者表单
        let bauthor = document.querySelector('#addForm [name="author"]')
        // 获取新增的出版社表单
        let bpublisher = document.querySelector('#addForm [name="publisher"]')

        // 获取模块框的书名表单
        let editbookname = document.querySelector('#editForm [name="editbookname"]')
        // 获取模块框的作者表单
        let editauthor = document.querySelector('#editForm [name="editauthor"]')
        // 获取模块框的出版社表单
        let editpublisher = document.querySelector('#editForm [name="editpublisher"]')
        // 获取确定修改按钮
        let btnConfirm = document.querySelector('.btnConfirm')
        
        // 数据渲染
        function init() {
          // 发送请求
          axios({
            method: "get",
            url: "http://www.itcbc.com:3006/api/getbooks"
          }).then(res => {
            // 动态生成页面结构
            let html = "";
            res.data.data.forEach((value, index) => {
              html += `<tr>
                        <th scope="row">${index + 1}</th>
                        <td>${value.bookname}</td>
                        <td>${value.author}</td>
                        <td>${value.publisher}</td>
                        <td>
                          <button data-id="${value.id}" type="button" class="btn btn-link btn-sm btndel">
                            删除
                          </button>
                          <button type="button" data-id="${value.id}" data-bookname="${value.bookname}" data-author="${value.author}" data-publisher="${value.publisher}" class="btn btn-link btn-sm edit" >
                            编辑
                          </button>
                        </td>
                      </tr>
                    `;
            });
            tbody.innerHTML = html;
          });
        }
        // 重新渲染页面
        init();

        // 新增数据
        btn.addEventListener('click', function(e) {
          // 阻止默认行为,让submit按钮不要实现页面跳转
          e.preventDefault()
          // 把新增书名的表单value值存到变量bookname里面
          let bookname = bname.value
          // 把新增作者的表单value值存到变量author里面
          let author = bauthor.value
          // 把新增出版社的表单value值存到变量author里面
          let publisher = bpublisher.value

          // 把表单的数据新增到后台数据
          let data = {
            bookname,
            author,
            publisher
          }
          // 发送请求
          axios({
            method: 'post',
            url: 'http://www.itcbc.com:3006/api/addbook',
            data
          }).then(res => {
            // 判断status的值如果是0表示成功
            if(res.data.status == 0) {
              // 弹出成功的文本
              alert(res.data.message);
              // 重新渲染页面
              init()
            }
          })
        })

        // 数据删除
        tbody.addEventListener('click', function(e) {
          // 事件委托,判断是否点了删除按钮
          if(e.target.classList.contains('btndel')) {
            // 获取删除按钮的自定义id
            let id = e.target.dataset.id;
            // 发起请求
            axios({
              method: 'delete',
              url: `http://www.itcbc.com:3006/api/delbook`,
              // 传递所要删除的内容对应的id
              params: {id}
            }).then(res => {
              if(res.data.status == 0) {
                alert(res.data.message);
                init();
              }
            })
          }
        })

        // 数据编辑
        let editId;
        // 事件委托
        tbody.addEventListener('click', function(e) {
          // 判断是否点击了编辑按钮
          if(e.target.classList.contains('edit')){
            // 让模态框显示
            $('#editModal').modal('show')
            // 获取自定义data属性
            let data = e.target.dataset
            // 确定编辑按钮也需要用到id,所以需要将它暴露到外部
            editId = data.id
            // 数据回填
            // 将书名填入模块框对应的书名表单
            editbookname.value = data.bookname
            // 将作者填入模块框对应的作者表单
            editauthor.value = data.author
            // 将出版社填入模块框对应的出版社表单
            editpublisher.value = data.publisher
          }
        })

        // 编辑修改数据
        btnConfirm.addEventListener('click', function() {
          // 将模块框表单修改之后的内容重新赋值给数据对象,定义一个data把它们存起来
          let data = {
            id: editId,
            bookname: editbookname.value,
            author: editauthor.value,
            publisher: editpublisher.value
          }
          // 发起请求
          axios({
            method: 'put',
            url: 'http://www.itcbc.com:3006/api/updatebook',
            // 把修改之后的数据存回数据库
            data
          }).then((res) => {
            if(res.data.status == 0) {
              alert(res.data.message);
              // 点击确定之后让模块框隐藏
              $('#editModal').modal('hide')
              init()
            }
          })
        })

    </script>
  </body>
</html>