Ajax学习-上(基本用法)

Ajax

1.概述

web程序最初的目的就是将信息(数据)放到公共的服务器,让所有网络用户都可以通过浏览器访问。

在此之前,我们可以通过以下几种方式让浏览器发出对服务器的请求,获得服务器的数据:

  • 地址栏输入地址,回车,刷新
  • 特定元素的href或src属性
  • 表单提交
    这些方案都是我们无法通过或很难通过代码的方式进行编程(对服务器发出请求并且接受服务器返回的响应),如果我们可以通过javaScript直接发送网络请求,那么web的可能就会更多,随之能够实现的功能也会更多,至少不是“单机游戏”。

AJAX(Asynchronous JavaScript and XML) ,最早出现在2005年的Google Suggest ,实在浏览器进行网络编程(发送请求、接收响应)的技术方案,它使我们可以通过JavaScript直接获取服务器最新的内容而不必重新加载页面,让web更接近桌面应用的用户体验,

说白了,AJAX就是浏览器提供的一套API,可以通过JavaScript调用,从而实现通过代码控制请求与响应,实现网络编程。

2.快速上手

使用Ajax的过程可以类比平常我们访问网页过程

// 涉及到 AJAX 操作的页面“不能”使用文件协议访问(文件的方式访问)

    // AJAX 是一套 API 核心提供的类型:XMLHttpRequest
    // 1. 安装浏览器(用户代理)
    //  xhr 就类似于浏览器的作用(发送请求接收响应)
    
    var xhr = new XMLHttpRequest()

    // 2. 打开浏览器 输入网址
    
    xhr.open('GET', 'http://day-11.io/time.php')
    
    // 3. 敲回车键 开始请求
    
    xhr.send()
     // 因为客户端永远不知道服务端何时才能返回我们需要的响应
    // 所以 AJAX API 采用事件的机制(通知的感觉)
    // 4. 等待响应
    // 5. 看结果
xhr.onreadystatechange = function () {
      // 这个事件并不是只在响应时触发,XHR 状态改变就触发
      // console.log(1)
      if (this.readyState !== 4) return
      // 获取响应的内容(响应体)
      console.log(this.responseText)
    }

    // 因为响应需要时间,所以无法通过返回值的方式返回响应
    // var response = xhr.send()
    // console.log(response)
2.1 readyState

由于readyStateChange事件是在xhr对象状态变化时触发(不单是在得到响应时),也就意味着这个事件会被触发多次,所以我们有必要了解每一个状态值代表的含义:

readyState状态描述说明
0UNSENT代理(XHR)被创建,但尚未调用open()方法。
1OPENEDopen()方法已经被调用,建立了连接。
2HEADERS_RECEIVEDsend()方法已经被调用,并且已经可以获取状态行和响应头。
3LOADING响应体下载中,responseText属性可能已经包含部分数据。
4DONE响应体下载完成,可以直接使用responseText。
    var xhr = new XMLHttpRequest()
    console.log(xhr.readyState)
    // => 0
    // 初始化 请求代理对象

    xhr.open('GET', 'demo.php')
    console.log(xhr.readyState)
    // => 1
    // open 方法已经调用,建立一个与服务端特定端口的连接

    xhr.send()

    xhr.addEventListener('readystatechange', function () {
      switch (this.readyState) {
        case 2:
          // => 2
          // 已经接受到了响应报文的响应头

          // 可以拿到头
          // console.log(this.getAllResponseHeaders())
          console.log(this.getResponseHeader('server'))
          // 但是还没有拿到体
          console.log(this.responseText)
          break

        case 3:
          // => 3
          // 正在下载响应报文的响应体,有可能响应体为空,也有可能不完整
          // 在这里处理响应体不保险(不可靠)
          console.log(this.responseText)
          break

        case 4:
          // => 4
          // 一切 OK (整个响应报文已经完整下载下来了)
          console.log(this.responseText)
          break
      }
    })

通过理解每一个状态值的含义得出一个结论:一般我们都是在readyState值为4时,执行响应的后续逻辑。

xhr.onreadystatechange = function () {   
     if (this.readyState === 4) {  
   // 后续逻辑......   
     } 
 }
2.2 遵循HTTP

本质上XMLHttpRequest就是JavaScript在web平台中发送HTTP请求的手段,所以我们发送出去的请求仍然HTTP请求,同样符合HTTP约定的格式:

var xhr = new XMLHttpRequest()

    xhr.open('POST', '/add.php') // 设置请求行

    xhr.setRequestHeader('Foo', 'Bar') // 设置一个请求头
    // 一旦你的请求体是 urlencoded 格式的内容,一定要设置请求头中 Content-Type 'application/x-www-form-urlencoded'
    xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded')

    xhr.send('key1=value1&key2=value2') // 以 urlencoded 格式设置请求体

参考链接:

3.具体用法

3.1 GET请求

通常在一次GET请求过程中,参数传递都是通过URL地址中的?参数传递。

var listElement = document.getElementById('list')

    // 发送请求获取列表数据呈现在页面
    // =======================================

    var xhr = new XMLHttpRequest()

    xhr.open('GET', 'users.php')

    xhr.send()

    xhr.onreadystatechange = function () {
      if (this.readyState !== 4) return
      var data = JSON.parse(this.responseText)
      // data => 数据

      for (var i = 0; i < data.length; i++) {
        var liElement = document.createElement('li')
        liElement.innerHTML = data[i].name
        liElement.id = data[i].id

        listElement.appendChild(liElement)

        liElement.addEventListener('click', function () {
          // TODO: 通过AJAX操作获取服务端对应数据的信息
          // 如何获取当前被点击元素对应的数据的ID
          // console.log(this.id)
          var xhr1 = new XMLHttpRequest()
          xhr1.open('GET', 'users.php?id=' + this.id)
          xhr1.send()
          xhr1.onreadystatechange = function () {
            if (this.readyState !== 4) return
            var obj = JSON.parse(this.responseText)
            alert(obj.age)
          }
        })
      }
    }

    // 给每一个 li 注册点击事件
    // 因为 li 后来动态创建,所以不能这样注册事件
    // for (var i = 0; i < listElement.children.length; i++) {
    //   listElement.children[i].addEventListener('click', function () {
    //     console.log(111)
    //   })
    // }


    // var xhr = new XMLHttpRequest()
    // // 这里任然是使用URL中的问号参数传递数据
    // xhr.open('GET', 'users.php?id=2')
    // xhr.send(null)

    // xhr.onreadystatechange = function () {
    //   if (this.readyState !== 4) return
    //   console.log(this.responseText)
    // }

users.php:

<?php

header('Content-Type: application/json');
/**
 * 返回的响应就是一个 JSON 内容(返回的就是数据)
 * 对于返回数据的地址一般我们称之为接口(形式上是 Web 形式)
 */

// `/users.php?id=1` => id 为 1 的用户信息

$data = array(
  array(
    'id' => 1,
    'name' => '张三',
    'age' => 18
  ),
  array(
    'id' => 2,
    'name' => '李四',
    'age' => 20
  ),
  array(
    'id' => 3,
    'name' => '二傻子',
    'age' => 18
  ),
  array(
    'id' => 4,
    'name' => '三愣子',
    'age' => 19
  )
);


if (empty($_GET['id'])) {
  // 没有 ID 获取全部
  // 因为 HTTP 中约定报文的内容就是字符串,而我们需要传递给客户端的信息是一个有结构的数据
  // 这种情况下我们一般采用 JSON 作为数据格式
  $json = json_encode($data); // => [{"id":1,"name":"张三"},{...}]
  echo $json;
} else {
  // 传递了 ID 只获取一条
  foreach ($data as $item) {
    if ($item['id'] != $_GET['id']) continue;
    $json = json_encode($item); // => [{"id":1,"name":"张三"},{...}]
    echo $json;
  }
}

3.2 POST请求

POST请求过程中,都是采用请求体承载需要提交的数据。

    // 找一个合适的时机,做一件合适的事情
    var btn = document.getElementById('btn')
    // 1. 获取界面上的元素 value
    var txtUsername = document.getElementById('username')
    var txtPassword = document.getElementById('password')
    var loading = document.getElementById('loading')

    btn.onclick = function () {
      loading.style.display = 'block'
      var username = txtUsername.value
      var password = txtPassword.value
      // 2. 通过 XHR 发送一个 POST 请求
      var xhr = new XMLHttpRequest()
      xhr.open('POST', 'login.php')
      // !!! 一定注意 如果请求体是 urlencoded 格式 必须设置这个请求头 !!!
      xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded')
      // xhr.send('username=' + username + '&password=' + password)
      xhr.send(`username=${username}&password=${password}`)
      // 3. 根据服务端的反馈 作出界面提示
      xhr.onreadystatechange = function () {
        if (this.readyState !== 4) return
        console.log(this.responseText)
        loading.style.display = 'none'
      }
    }

login.php:

<?php

// 接收用户提交的用户名密码
if (empty($_POST['username']) || empty($_POST['password'])) {
  // echo ;
  exit('请提交用户名和密码');
}
// 校验
$username = $_POST['username'];
$password = $_POST['password'];
if ($username === 'admin' && $password === '123') {
  exit('恭喜你');
}

exit('用户名或者密码错误');
// 响应

3.3 同步与异步

关于同步与异步的概念在生活中有很多常见的场景,举例说明。

同步:一个人在同一个时刻只能做一件事情,在执行一些耗时的操作(不需要看管)不去做别的事,只是等 待
异步:在执行一些耗时的操作(不需要看管)去做别的事,而不是等待

xhr.open() 方法第三个参数要求传入的是一个 bool 值,其作用就是设置此次请求是否采用异步方式执行,默认 为 true ,如果需要同步执行可以通过传递 false 实现

var xhr = new XMLHttpRequest()
    xhr.open('GET', 'time.php', true)
    xhr.send()
    // 一定要注意事件注册时间问题
    xhr.onreadystatechange = function () {
      console.log(this.readyState)
    }

如果采用同步方式执行,则代码会卡死在 xhr.send() 这一步:

console.log('before ajax') 
var xhr = new XMLHttpRequest() 
// 同步方式
 xhr.open('GET', './time.php', false) /
 / 同步方式 执行需要 先注册事件再调用 send,否则 readystatechange 无法触发
  xhr.onreadystatechange = function () {   
  if (this.readyState === 4) {   
    // 这里的代码最后执行    
     console.log('request done')   
     } }
      xhr.send(null) 
      console.log('after ajax')

演示同步异步差异。
一定在发送请求 send() 之前注册 readystatechange (不管同步或者异步)

  • 为了让这个事件可以更加可靠(一定触发),一定是先注册

了解同步模式即可,切记不要使用同步模式。
至此,我们已经大致了解了 AJAX 的基本 API 。

3.4 响应数据格式

提问:如果希望服务端返回一个复杂数据,该如何处理?

关心的问题就是服务端发出何种格式的数据,这种格式如何在客户端用 JavaScript 解析。

3.4.1. XML

一种数据描述手段
老掉牙的东西,简单演示一下,不在这里浪费时间,基本现在的项目不用了。
淘汰的原因:数据冗余太多

var xhr = new XMLHttpRequest()
    xhr.open('GET', 'xml.php')
    xhr.send()
    xhr.onreadystatechange = function () {
      if (this.readyState !== 4) return
      // this.responseXML 专门用于获取服务端返回的 XML 数据,操作方式就是通过 DOM 的方式操作
      // 但是需要服务端响应头中的 Content-Type 必须是 application/xml
      console.log(this.responseXML.documentElement.children[0].innerHTML)
      console.log(this.responseXML.documentElement.getElementsByTagName('name')[0])
    }

xml.php:

<?php
header('Content-Type: application/xml');
?>
<?xml version="1.1" encoding="utf-8"?>
<person>
  <name>石羊</name>
  <age>16</age>
  <gender>男</gender>
</person>
3.4.2. JSON

也是一种数据描述手段,类似于 JavaScript 字面量方式
服务端采用 JSON 格式返回数据,客户端按照 JSON 格式解析数据。

不管是 JSON 也好,还是 XML,只是在 AJAX 请求过程中用到,并不代表它们之间有必然的联系,它们只是 数据协议罢了

3.5. 处理响应数据渲染

模板引擎:
artTemplate:https://aui.github.io/art-template/

模板引擎实际上就是一个 API,模板引擎有很多种,使用方式大同小异,目的为了可以更容易的将数据渲染到 HTML中

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值