首页

ajax详细介绍

kkcode
2018-05-20  阅读 790

远古时代的AJAX

需求:做一个在线投票,要求无刷新投票(不许使用XMLHttpRequest对象)

分析:在XHR对象没有流行之前,我们已经有“无刷新”这种效果的要求。

方法1:利用HTTP 204 状态码

利用HTTP 204 No Content状态码,当浏览器收到204时,页面不做跳转。

// html
<div>
    <p>
        <img width="200px" src="./wmc.jpg">
    </p>
    <a href="01-vote.php">投票方法1</a>
    <button onclick="vote()">投票方法2</button>
    <button onclick="loadCss()">投票方法3</button>
    <button onclick="loadJs()">投票方法3</button>
    <button onclick="ifra()">投票方法4</button>
</div>复制代码
// 01-vote.php
$cnt = file_get_contents('./res.txt');
$cnt += 1;
file_put_contents('./res.txt',$cnt);

// 利用HTTP协议的 204 特性
header('HTTP/1.1 204 No Content');复制代码

方法2:利用图片加载的特性,来完成请求

function vote() {
    var wmc = document.createElement('img');
    wmc.src = './01-vote.php';
}复制代码

方法3:利用css,javascript加载的特性,完成请求。

function loadCss() {
    var link = document.createElement('link');
    link.rel="stylesheet"; // 如果不加此属性,css文件不会加载
    link.href = './01-vote.php';
    link.id = 'css';
    document.body.appendChild(link);
    setTimeout(function(){
        document.body.removeChild(document.getElementById('css'));
    },300)
}

function loadJs() {
    var script = document.createElement('script');
    script.src = './01-vote.php';
    script.id = 'js';
    document.body.appendChild(script);
    setTimeout(function(){
        document.body.removeChild(document.getElementById('js'));
    },300)
}复制代码

方法4:利用iframe的特性

function ifra() {
    var iframe = document.createElement('iframe');
    iframe.src = './01-vote.php';
    iframe.id = 'iframe';
    document.body.appendChild(iframe);
    setTimeout(function(){
        document.body.removeChild(document.getElementById('iframe'));
    },300)
}复制代码

应用iframe无刷新注册

输入用户名,密码。点击提交。页面无刷新,显示注册成功。

// html
<div id="msg"></div>
<form action="./02-reg.php" method="post" target="regzone">
    <p><label>用户名:</label><input type="text" name="username"></p>
    <p><label>密码:</label><input type="password" name="password"></p>
    <p><input type="submit" value="提交"></p>
</form>

<iframe width="0" height="0" name="regzone" frameborder="0"></iframe>复制代码
// 02-reg.php
<?php
// 1. 校验数据的合法性
// 2. 写入数据库等业务逻辑
// 3. 经过运算,注册成功,$res=1
$res = 1;
?>
<script>
parent.document.getElementById('msg').innerHTML = '注册成功';
</script>复制代码

现代化的AJAX

XMLHTTPRequest对象,一个专门的HTTP请求工具。

如何使用XMLHttpRequestAJAX请求?

// 分析
1.如何创建该对象?
2.如何请求后台服务器资源?
3.请求的结果如何在`JS`拿到?复制代码

如何创建XHR对象

使用 new 操作符,在W3C标准下,可以通过 new XMLHttpRequest() 得到。考虑低版本的IE,可以使用 new ActiveXObject('Microsoft.XMLHTTP')得到。

function createXHR(){
    return window.XMLHttpRequest ? new XMLHttpRequest() : new ActiveXObject('Microsoft.XMLHTTP');
}复制代码

如何利用XHR来发送请求

根据http协议,要请求需要明确这样几个因素:

1.用什么方法来请求?

GET POST PUT DELETE HEAD

2.请求哪个资源(URL)?

3.请求方式?-同步/异步

4.如何获取请求的返回数据?

答:XHR对象本身有一个属性,responseText就代表返回值。

5.引起的疑问?

如果是异步,下面的代码继续执行,等你的请求最终完成了。我该怎么知道这个变化呢?

答:XHR对象在请求与响应的过程中,状态不断变化(0-4)。我们可以绑定一个函数来监听状态的变化,只要状态变化就触发函数。XHR的readyState状态最终要变到4,当变到4时,意味着请求结束了。

6.如何绑定状态变化的回调函数?

xhr.onreadystatechange = function(){
    var pg = document.getElementById('progress');
    pg.innerHTML = pg.innerHTML + '状态已经变成' + this.readyState + '<br>';
}复制代码

状态值:

  • 0:XHR对象刚创建成功时。(请求未初始化,在调用 open() 之前)
  • 1:open成功后为1(此时已成功建立连接)(请求已提出,调用 send() 之前)
  • 2:接收头信息完毕后,为数字2(请求已发送,这里通常可以从响应得到内容头部)
  • 3:接收body信息后状态为3(请求处理中,响应中通常有部分数据可用,但是服务器还没有完成响应)
  • 4:可以获取responseText数据。(请求已完成,可以访问服务器响应并使用它)

简单AJAX请求

// 03-vote.php
sleep(3);

if(rand(1,10) < 4) {
    echo '0';
} else {
    $cnt = file_get_contents('./res.txt');
    $cnt += 1;
    file_put_contents('./res.txt',$cnt);
    echo '1';
}复制代码

重写投票方法2的vote函数:

function vote() {
    // 1:制造xhr
    var xhr = createXHR();
    // 2: 打开连接
    xhr.open('GET','./03-vote.php',true);
    // 3: 发请求
    xhr.send(null);

    // 绑定状态变化的回调函数
    xhr.onreadystatechange = function () {
        if(this.readyState == 4) {
            if(this.responseText == '1') {
               document.getElementById('progress').innerHTML = '投票成功';
            } else if(this.responseText == '0'){
               document.getElementById('progress').innerHTML = '投票失败';
            } else {
               document.getElementById('progress').innerHTML = this.responseText;
            }
        }
        var pg = document.getElementById('progress');
        pg.innerHTML = pg.innerHTML + '状态现在变成' + this.readyState + '<br />';
    }

    alert('后面的代码继续执行');
}复制代码

XHR属性详解

  • responseText 服务器响应的主题信息,body信息
  • responseXML 对于大量的格式化文档,可以用XML来传输或交换。由后台程序把数据封装在XML文档。js接收XML对象并解析该内容。
  • status 是服务器返回的状态码,例如:200 success 成功,403 forbidden 禁止,404 not found 未找到,50X 系列 服务器错误。
  • statusText 状态码对应的文字描述。
  • readyState XHR对象的自身状态码。
  • onreadystatechange 事件属性,是一个函数,xhr对象的状态码发生变化时,触发该事件属性绑定的函数。
// 06-vote.php
sleep(5);

$str = 'abcdefg';
echo str_shuffle($str);复制代码

重写投票方法2的vote函数:

function vote() {
    var xhr = createXHR();
    xhr.open('GET','./06-vote.php',true);
    xhr.send(null);

    // 绑定状态变化的回调函数
    xhr.onreadystatechange = function () {
        if(this.readyState == 4 && this.status == 200) {
            var str = '';
            str = '状态码是' + this.status + '<br>';
            str = str + '状态文字是' + this.statusText + '<br>';
            str = str + '返回类型是:' + this.getResponseHeader('Content-Type') + '<br>';

            str = str + '返回的主体长度是' + this.getResponseHeader('Content-Length') + '<br>';
            str = str + '返回的主体内容是' + this.responseText + '<br><br>';

            str = str + '所有头信息' + this.getAllResponseHeaders();
            document.getElementById('progress').innerHTML = str;
        }
    }
}
/**
状态码是200
状态文字是OK
返回类型是:text/html; charset=utf-8
返回的主体长度是7
返回的主体内容是dbafgce

所有头信息
connection: Keep-Alive 
content-length: 7 
content-type: text/html; 
charset=utf-8 
date: Wed, 11 Dec 2019 13:25:06 GMT 
keep-alive: timeout=5, max=98 
server: Apache/2.4.9 (Win64) PHP/5.5.12 
x-powered-by: PHP/5.5.12
*/复制代码

XHR方法详解

  • open(requestMethod,url,sync/async) sync(同步:false) async(异步:true)
  • send(null/params) params的写法: k1=v1&k2=v2&kn=vn 即键值对
  • setRequestHeader(key,value) 设置请求的头信息。
  • abort() 中断当前的AJAX请求
  • getResponseHeader() 获取响应的头信息。
  • getAllResponseHeader() 获取所有的头信息。

如何POST数据

通过一个例子说明。
get方式提交数据是明文可见的,当用户提交的信息比较私密的情况下,这时我们需要使用POST的方式提交数据。

<!-- 用户注册表单 -->
<div id="regres"></div>
<form action="07-ajaxreg.php" method="post" onsubmit="return ajaxreg();">
    <p>用户名:<input type="text" name="username" /></p>
    <p>邮件地址:<input type="text" name="email" /></p>
    <p><input type="submit" name="注册" /></p>
</form>
<script>
    /*
    步骤1: 打开到后台服务器连接(POST连接)
    步骤2: 收集表单的数据
    步骤3: 发送数据
    步骤4: 监听,回调等
    */
    function ajaxreg() {
        // 0:制造xhr
        var xhr = createXHR();
        // 1: 打开POST连接
        xhr.open('POST','./07-ajaxreg.php',true);
        // 4. 监听回调
        xhr.onreadystatechange = function() {
            if(this.readyState == 4) {
                alert(this.responseText);
            }
        }
        // 2: 收集表单数据
        var un = document.getElementsByName('username')[0].value;
        var eml = document.getElementsByName('email')[0].value;
        // 3: send
        xhr.setRequestHeader('Content-Type','application/x-www-form-urlencoded');
        xhr.send('username='+un+'&email=' + eml);

        return false;
    }
</script>复制代码
print_r($_POST);复制代码

返回值类型

不考虑HTML5,严格来说,只有普通文本和XML两种类型。

作为普通文件返回类型时,又有以下几种常用的变通形式:

  • 返回简短的标志字符串,如:0 1 OK
  • 后台返回dad大段的HTML代码,前端直接innerHTML到页面中。
  • JSON格式,再用js解析。
  • 返回JSONP跨域

测试各种返回值:

书名:<input type="text" id="btitle" /><br>
简介:<input type="text" id="bintro" /><br>

<input type="button" value="测试返回XML" onclick="test1();">
<input type="button" value="测试返回html代码" onclick="test2();">
<input type="button" value="测试返回json格式" onclick="test3();">

<div id="news"></div>
<script>
    function test1() {
        var xhr = createXHR();
        xhr.open('GET','08-returntype.php',true);

        xhr.onreadystatechange = function() {
            if(this.readyState == 4) {
                var xmldom = this.responseXML;
                var chs = xmldom.getElementsByTagName('book')[0];
                document.getElementById('btitle').value = chs.firstChild.firstChild.wholeText;
                document.getElementById('bintro').value = chs.lastChild.firstChild.wholeText;
            }
        }

        xhr.send(null);
    }


    function test2() {
        var xhr = createXHR();
        xhr.open('GET','08-returnhtml.php',true);

        xhr.onreadystatechange = function() {
            if(this.readyState == 4) {
                document.getElementById('news').innerHTML = this.responseText;
            }
        }

        xhr.send(null);
    }


    function test3() {
        var xhr = createXHR();
        xhr.open('GET','08-returnjson.php',true);

        xhr.onreadystatechange = function() {
            if(this.readyState == 4) {           
                var book = eval('('+this.responseText+')');
                document.getElementById('btitle').value = book.title;
                document.getElementById('bintro').value = book.intro;

            }
        }

        xhr.send(null);
    }
</script>复制代码
// 08-returntype.php
<?php
header('Content-Type: text/xml');
?>
<?xml version="1.0" encoding="utf-8"?>
<bookstore><book bid="b008"><title>天龙八部</title><intro>人生太苦了</intro></book></bookstore>
复制代码
// 08-returnhtml.php

// 从数据库取出N条数据
foreach(array('新闻1','新闻2','新闻3') as $v) {
    echo '<li>',$v,'</li>';
}
复制代码
// 08-returnjson.php

// 从数据库取出N条数据
$book = array('title'=>'天龙八部','intro'=>'人生八苦');
echo json_encode($book);
复制代码

跨域JSONP

通过js创建script标签,来实现跨域。

<input type="text" name="keyword" /><br />
<input type="button" value="搜索" onclick="cors();" />
<div id="szone"></div>
<script>
    function cors() {
        var kw = document.getElementsByName('keyword')[0].value;
        var url = 'https://www.baidu.com/sugrec?ie=utf-8&json=1&prod=pc&from=pc_web&wd='
        + encodeURI(kw) + '&req=2&csor=2&cb=callback';

        var scr = document.createElement('script');
        scr.setAttribute('type','text/javascript');
        scr.setAttribute('src',url);

        document.getElementsByTagName('head')[0].appendChild(scr);
    }

    function callback(res) {
        var results = res.g;

        var szone = document.getElementById('szone');
        var str = '';
        for(var i in results) {
            str += '<p>'+ results[i].q + '<p/>';
        }

        szone.innerHTML = str;
    }
</script>复制代码

参考

本文为作者原创文章,转载无需和我联系,但请注明转载链接。 【前端黑猫】