笔记-Ajax

不是原创哦,笔记是照着关注的微信公众号Web前端之巅记下来的,大家去关注吧!她的博客地址是https://blog.csdn.net/lvonve/,非常感谢她!

服务器和客户端

网路相关概念

IP地址:
通过IP地址可以找到特定的服务器。可以通过ipconfig 查看本机的IP。
域名:
由于IP地址是一串数字,比较难记,所以用域名代替IP地址。
DNS域名解析器:
DNS又叫做域名解析服务器,提供域名和ip地址的映射关系。

一台电脑访问服务器的过程如下:
比如访问百度服务器:当在地址栏输入www.baidu.com点击回车的时候,浏览器会将域名发送到DNS域名解析器,解析出www.baidu.com对应的ip是123.125.114.114,然后再将这个域名返回个浏览器,浏览器从这个ip访问百度服务器。

一般我们的电脑上有一个hosts文件,里面保存着域名和ip地址的映射关系,当我们访问百度的时候,现在hosts中读取是否有域名对应的ip,没有的话再通过DSN 域名解析器。
本机 hosts 文件的路径:C:\Windows\System32\drivers\etc\hosts
端口:
当我们电脑找到一台服务器时,这台服务器可能会提供很多服务,如何区分客户端需要哪种服务就需要端口来区分。

比如:我们在访问百度提供的网页服务时,完整的写法为:www.baidu.com:80,80 这个端口就是百度提供网页服务的,但是80这个端口比较特殊,可以省略不写。

再比如我们在设置邮箱客户端的时候,也需要指定端口号。

通信协议

通信协议就是事先商量好的规则。而计算机之间的通信也需要规则。
常见的协议有:
HTTP、HTTPS:超文本传输协议
FTP:文件传输协议
SMTP:简单邮件传输协议

WAMP 的安装配置

什么是Wamp?
Wamp指的是:Windows、Apache、MySQL、PHP 几个服务器软件的缩写,类似的还有 LAMP,只不过把 Windows 换成了 Linux。
为什么要安装 Wamp?
以前我们写的 html 文件都是在本地执行的,现在我们想把我们的电脑变成一台服务器,然后将我们的 html 界面以服务的方式提供给别的客户机访问。
Wamp 的简单配置:
配置访问权限:
默认情况下,apache 提供的网页服务只允许 localhost 和 127.0.0.1 (其实这两个是一个映射关系,在 hosts 里面有写)访问,如果我们想让别的客户机访问,就需要对配置文件进行修改。配置文件位于:C:\wamp\bin\apache\Apache2.4.4\conf\httpd.conf 将 268 行的 Deny from all 改成 Allow from all。
注意:在修改所有配置文件之前,都应该先做备份。
网站根路径的配置
默认情况下,网站的根路径为 c:\wamp\www ,在此目录下的文件才可以以服务的方式提供给别人访问,如果想更改这个路径,也需要修改 C:\wamp\bin\apache\Apache2.4.4\conf\httpd.conf 文件,将 DocumentRoot 修改为自己想要的目录。
注意:修改之后,原路径 c:\wamp\www 将不可访问。

静态网站和动态网站

静态网站

所有的 HTML 代码全部都已经写好,任何人访问都是相同的。每次网页的改变,都需要修改 HTML 源码,而且如果有1000个 HTML 文件,就需要修改 1000 个 HTML代码,工作量巨大。

动态网站

一般动态网站通过数据库进行架构,动态网站的内容可以根据不同用户的不同需求展示不同的页面。一般是以 asp、jsp、php、aspx 等结尾。

php基础语法

基本结构
  • 所有代码都要写在<?php //内容 ?>里面
  • php文件可以和HTML文件结合进行使用
  • php文件的扩展名是’.php’
  • php代码必须在服务器上执行
打印语句

echo:在页面中输入字符串,只能打印字符串,数字等简单类型
print_r输出复杂类型
var_dump:输出复杂类型

<?php 
    echo 'hello lianlian.';
    echo '<br>';
    echo 123;
    echo '<br>';
    print_r([1,2,3,4,5]);
    echo '<br>';
    var_dump([1,2,3,4,5])
?>

打印结果:

hello lianlian.
123
Array ( [0] => 1 [1] => 2 [2] => 3 [3] => 4 [4] => 5 ) 
array (size=5)
  0 => int 1
  1 => int 2
  2 => int 3
  3 => int 4
  4 => int 5
变量的声明和使用

前面要加$

$str = 'Hello';
echo $str;
字符串拼接

使用’.’,不使用’+’

$str1 ="Hello";
$str2 ="world";
echo $str1." ".$str2;
php执行原理

浏览器是不识别PHP文件的,用浏览器打开php文件,之后显示php源代码,所以php文件必须在服务器中执行。其实Apache服务器也识别不了PHP文件,是Apache将php文件交给php模块处理的,最后Apache将处理之后的网页内容返回。

数组

一维数组的定义:

$arr = array();
$arr[0] = "10";
$arr[1] = "20";
$arr[2] = "30";

或者
$arr = array("10", "20", "30");

数组是复杂类型,不能食用echo打印,智能打印其中的某个元素,复杂类型使用print_r或者var_dump。
示例:

$arr1 = array();
$arr1[0] = "10";
$arr1[1] = "20";
$arr1[2] = "30";

$arr2 = array("40", "50", "60");

// echo $arr1; // 不能直接打印数组

print_r($arr1);
var_dump($arr2);
echo json_encode($arr1); // 将数组转化成 json 格式打印,转化后是 字符串格式,可以使用echo。

打印结果:

Array ( [0] => 10 [1] => 20 [2] => 30 )

array (size=3)
  0 => string '40' (length=2)
  1 => string '50' (length=2)
  2 => string '60' (length=2)

["10","20","30"]

数组的下标索引自定义:

$arr = array("index1"=>"40", "index2"=>"50", "index3"=>"60");

或者只定义其中的几个:

$arr = array("40", "index"=>"50", "60");

此时,40的下标是0,60的下标是1.这种方式不可以使用for循环遍历数组,因为下标不是1,2,3了,要用foreach的方式(key索引,value为索引对应的值)

foreach($arr as $key => $value) {
    echo $key . "---" . $value . "<br>";
}

二维数组的定义

$arr = array();
$arr[0] = array("1", "2", "3");
$arr[1] = array("4", "5", "6");

var_dump($arr);
echo json_encode($arr);

打印结果:

array (size=2)
  0 => 
    array (size=3)
      0 => string '1' (length=1)
      1 => string '2' (length=1)
      2 => string '3' (length=1)
  1 => 
    array (size=3)
      0 => string '4' (length=1)
      1 => string '5' (length=1)
      2 => string '6' (length=1)

[["1","2","3"],["4","5","6"]]
函数

系统函数
json_encode:php中将数组转化为json格式的字符串
var_dump:输出复杂的数据类型
print_r:输出复杂的数据类型
count:得到数组的长度
自定义函数

function add($num1,$num2){
    return $num1+$num2;
}
预定义变量

我们知道,动态网页会根据不同的需求展示不同的页面,那么是怎么做到的呢?
请求类型
请求的时候是要携带参数的,用来表示不同的要求,根据参数的不同,而展示不同的界面。根据参数携带的位置不同,可以简单地把请求分为get和post。
get请求:跟在url后面,用?连接,多个参数之间用&连接
post请求:参数在请求体中
$_GET["属性名字"]:获取get请求的属性的值
$_POST["属性名字"]:获取post请求的属性的值

get请求

实例:php获取用户登录名和密码进行校验

<!--html代码-->
<!--省略代码-->
<body>
    <h1>登录界面</h1>
    <form action="check.php" method="GET">
        用户名:<input type="text" name="username"> <br>
        密 码:<input type="password" name="passwd"> <br>
        <input type="submit" value="提交">
    </form>
</body>
// php代码
<?php

    $username = $_GET["username"];
    $password = $_GET["passwd"];

    if(($username == "Daotin") && ($password == "123")) {
        echo "Login Success!";
    } else {
        echo "Login Failed!";
    }
?>

在form表单中可以进行get请求和post请求
我们在输入账号和密码并点击提交之后,在地址栏可以看出,参数跟在了地址栏后,用?连接,参数之间用&连接
通过$_GET[]可以获取参数的值。

post请求
<!--HTML主要代码-->
<h1>登录界面</h1>
    <form action="check.php" method="POST">
        用户名:<input type="text" name="username"> <br>
        密 码:<input type="password" name="passwd"> <br>
        <input type="submit" value="提交">
    </form>
<?php

    $username = $_POST["username"];
    $password = $_POST["passwd"];

    if(($username == "Daotin") && ($password == "123")) {
        echo "Login Success!";
    } else {
        echo "Login Failed!";
    }
?>

可以看见在地址栏中没有显示请求参数

get请求和post请求的区别
  • get请求会把请求参数放在url中,而post请求则放在请求体中,post更安全
  • 所以,一般get请求数获取服务器的数据,post请求时向服务器提交一些数据

Ajax概述

Ajax全称是Asynchronous JavaScript and XML(异步的JavaScript和XML)。它可以在无需加载整个页面的情况下,能够更新部分网页。

我们可以通过以下几种方式让浏览器发出对服务端的请求,获得服务端的数据
* 地址栏输入地址,回车,刷新
* 特定元素的href或src属性
* 表单提交
web运作的原理:一次HTTP请求对应一个页面
Ajax请求时异步的,也就是说,腰痛过回调函数获得相应。

Ajax快速上手

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

// 1.创建一个XMLHttpRequest类型的对象相当于打开了一个浏览器
var xhr = null;
if(window.XMLHttpRequest){
    xhr = new XMLHttpRequest();
}else{
    xhr = new ActiveObject("Microsoft.XMLHTTP");
}
// 2.打开与一个网址之间的连接,相当于在地址栏输入访问地址
xhr.open("get","checkusername.php?username="+uname,true);
// 3.通过连接发送一次请求相当于回车或者点击访问发送请求
xhr.send(null);
// 仅仅针对post请求
// xhr.setRequestHeader('Content-Type','application/x-www-from-urlencoded');
// 4.指定xhr状态变化事件处理函数相当于处理网页呈现后的操作
xhr.onreadystatechange = function(){
    if(this.readtState == 4){
        if(thid.status == 200){
            console.log(this.responseText);
        }
    }
}
创建对象

在IE6及以下的时候,是不支持 XMLHttpRequest 对象的,那么与之对应写法为:
var xhr = new ActiveXObject("Microsoft.XMLHTTP");
所以为了兼容性,上面的创建对象的方式改为:

var xhr = null;
if(window.XMLHttpRequest) {
    xhr = new XMLHttpRequest();
} else {
    xhr = new ActiveXObject("Microsoft.XMLHTTP");
}
open方法

第一个参数是请求的方式,是 get 请求还是 post 请求。一般取决后端开发的php文件里面写的是 get 还是 post。
第二个参数是需要请求的地址。如果是 get 请求,需要在地址后面加上 ? 进行连接操作,连接的是需要请求的你内容。(参考下面验证用户名示例),如果是 post 请求,只需要写请求的地址就可以了,它的请求内容是写在 send 中的。
第三个参数是同步或者异步,一般可以不写,不写默认异步,false:同步,true:异步。

send方法

对于 get 方式,参数为 null;
对于 post 方式,参数为请求的数据。

var param = "username=" + uname; // 和 get 地址后面 ? 链接请求内容一致
xhr.send(param);

对于 post 请求,还需要设置下请求头(post请求才有)

// 仅仅针对 post 请求才有
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
onreadystatechange 回调函数

之所以是回调函数,这样不会阻塞当前的操作,什么时候服务器返回数据,什么时候使用。这就是异步。

status:服务器返回的状态码
this.status == 200:表示响应成功;404 表示没有找到请求的资源;500 表示服务器端错误。
readyState:xhr对象的状态改变时,readyState的值也会相应的改变。具体数值的含义见下表:

readyStatexhr状态说明
0UNSENT代理(xhr)被创建,但尚未调用 open 方法
1OPENEDopen 方法已经被调用,建立了连接
2HEADERS_RECEIVEDsend 方法已经被调用,已经可以获取状态行和响应头
3LOADING响应体下载中,responseText 属性可能已经包含部分数据
4DONE响应体下载完成,可以直接调用 responseText 获取数据

当 readyState == 2 时,只获取到数据头,这时不能使用 responseText 获取,而是用 getResponseHeader 来获取数据头信息。
当 readyState == 3 时,可能已经获取部分数据体,但是处理数据是不可靠的,所以一般一般我们都是在 readyState 值为 4 时,执行响应的后续逻辑 。

案例:点击按钮验证用户名是否存在

<div>
    <h1>用户注册</h1>
    用户名:
    <input type="text" name="username">
    <input type="button" value="验证用户名" id="btn">
    <span></span>
    <br> 密码:
    <input type="password" name="passwd">
    <br>
    <input type="submit" value="注册提交">
</div>

<script>
    var spanObj = document.getElementsByTagName("span")[0];
    document.getElementById("btn").onclick = function () {
        // 获取用户名
        var uname = document.getElementsByName("username")[0].value;

        // 发送给服务器处理
        var xhr = new XMLHttpRequest();
        xhr.open("get", "tt.php?username=" + uname, true);
        xhr.send(null);
        xhr.onreadystatechange = function () {
            if (this.readyState == 4) {                    
                spanObj.innerText = xhr.responseText;

                if (xhr.responseText == "用户名已存在!") {
                    spanObj.style.color = "red";
                } else {
                    spanObj.style.color = "green";
                }
            }
        };
    };
</script>

后台php代码

<?php
    $user = $_GET["username"];
    if($user == "lvonve") {     // 这里仅仅只判断一个用户名,实际上是由数据库提供
        echo "用户名已存在!";
    } else {
        echo "用户名可以使用!";
    }
?>

接口文档的使用

需求:使用接口文档验证用户名,邮箱,手机的唯一性

接口文档

当前端页面 要从服务器获取数据的时候,其实就是访问一个url地址,指定特定的参数即可。这个url对应的php或者jsp等都是服务器开发人员已经开发好的。服务器开发人员开发好相关的接口之后,会提供一份接口文档给前端人员,在接口中会详细说明你要获取什么数据,访问什么网址,传入什么参数等等内容,下面就是一个简单地接口文档内容:
验证用户唯一性的接口

地址/server/checkUsername.php
作用描述验证用户是否可用
请求类型get 请求
参数uname
返回的数据格式普通字符串
返回数据说明返回 ok:代表用户名可用; 返回 error:代表用户名不可用。

验证邮箱唯一性的接口

地址/server/checkEmail.php
作用描述验证邮箱是否可用
请求类型post 请求
参数e
返回的数据格式数字
返回数据说明返回 0:代表邮箱可用; 返回 1:代表邮箱不可用

验证手机号唯一性的接口

地址/server/checkPhone.php
作用描述验证手机号是否可用
请求类型post 请求
参数phonenumber
返回的数据格式json格式
返回数据说明如下:
//手机号可用情况下返回
{
    "status":0,
    "message":{
        "tips":"手机号可用",
        "phonefrom":"中国电信"
    }
}
//手机号可用情况下返回
{
    "status":1,
    "message":"手机号已经被注册"
}
实例代码
// 获取所有元素
var userObj = document.getElementByName("username")[0];
var emailObj = document.getElementByName("email")[0];
var phoneObj = document.getElementByName("phone")[0];

var userSpanObj = document.getElementByName("user-span")[0];
var emailSpanObj = document.getElementByName("email-span")[0];
var phoneSpanObj = document.getElementByName("phone-span")[0];

// 用户名文本框失去焦点事件
userObj.onblur = function(){
    // 获取文本内容
    var userText = this.value;

    var xhr = new XMLHttpRequest();
    xhr.open("get","./server/checkUsername.php?username="+userText,true);
    xhr.send(null);
    xhr.onreadystatechange = function(){
        if(this.readyState == 4){
            if(this.status == 200){
                if(this.responseText == "ok"){
                    userSpanObj.innerHTML = "用户名可用";
                }else if(this.responseText = "error"){
                    userSpanObj.innerHTML = "用户名不可用";
                }
            }
        }
    }
}
// 密码文本框失去焦点事件
emailObj.onblur = function(){
    // 获取文本内容
    var emailText = this.value;

    var xhr = new XMLHttpRequest();
    xhr.open("post","./server/checkEmail.php",true);
    xhr.setRequestHeader('Content-Type','application/x-www-form-urlencoded');
    xhr.send("e="+emailText);
    xhr.onreadystatechange = function(){
        if(this.readyState == 4){
            if(this.status == 200){
                console.log(this.responseText);
                if(this.responseText == 0){
                    emailSpanObj.innerHTML = "邮箱可用";
                }else if(this.responseText == 1){
                    emailSpanObj.innerHTML = "邮箱不可用"
                }
            }
        }
    }
}
// 手机号文本框失去焦点事件
phoneObj.onblur = function(){
    // 获取文本内容
    var phoneText = this.value;

    var xhr = new XMLHttpRequest();
    xhr.open("post","./server/phoneEmail.php",true);
    xhr.setRequestHeader('Content-Type','application/x-www-form-urlencoded');
    xhr.send("phonenumber="+phoneText);
    xhr.onreadystatechange = function(){
        if(this.readyState == 4){
            if(this.status == 200){
                var val = JSON.parse(this.responseText);
                if(val.status == 0){
                    phoneSpanObj.innerHTML = val.message.tips" "+val.message.phonefrom;
                }else if(this.responseText == 1){
                    phoneSpanObj.innerHTML = val.message;
                }
            }
        }
    }
}

书写以上代码的过程中,完全不需要查看对应的php文件,只需要查看接口文档即可。

代码封装

上面的验证过程中,都是用到了Ajax的四部操作,有代码冗余,所以将Ajax的四部操作封装在一个函数内。

// Ajax的四部操作
function myAjax(type,url,param,async,dataType,callback){
    var xhr = null;
    // 兼容性处理
    if(window.XMLHttpRequest){
        xhr = new XMLHttpRequest();
    }else{
        xhr = new ActiveXObject("Microsoft.XMLHTTP");
    }
    if((type=="get")||(type=="GET")){
        if(param&&param!=""){
            url+="?"+param;
        }
        xhr.open(type,url,async);
        xhr.send(null);
    }else if((type=="post")||(type=="POST")){
        xhr.open(type,url,async);
        xhr.setRequestHeader('Content-Type','application/x-www-form-urlencoded')
        xhr.send(param);
    }

    if(async){
        xhr.onreadystatechange = function(){
            if(this.readyState == 4){
                if(this.status == 200){
                    if(dataType == "xml"){
                        callback(this.responseXML);
                    }else if(dataType == "json"){
                        callback(JSON.parse(this.responseText));
                    }else{
                        callback(this.responseText);
                    }
                }
            }
        }
    }else{
        if(this.readyState == 4){
            if(this.status == 200){
                if(dataType == "xml"){
                    callback(this.responseXML);
                }else if(dataType == "json"){
                    callback(JSON.parse(this.responseText));
                }else{
                    callback(this.responseText);
                }
            }
        }
    }
}


// 获取所有元素
var userObj = document.getElementByName("username")[0];
var emailObj = document.getElementByName("email")[0];
var phoneObj = document.getElementByName("phone")[0];

var userSpanObj = document.getElementByName("user-span")[0];
var emailSpanObj = document.getElementByName("email-span")[0];
var phoneSpanObj = document.getElementByName("phone-span")[0];

// 用户名文本框失去焦点事件
userObj.onblur = function(){
    // 获取文本内容
    var userText = this.value;

    myAjax("get","./server/checkUsername.php","username="+userText,"true","text",function(result){
        if(result == "ok"){
            userSpanObj.innerHTML = "用户名可用";
        }else if(result = "error"){
            userSpanObj.innerHTML = "用户名不可用";
        }
    })
}
// 密码文本框失去焦点事件
emailObj.onblur = function(){
    // 获取文本内容
    var emailText = this.value;
    myAjax("post","./server/checkEmail.php","e="+emailText,"true","true",function(result){
            if(result == 0){
                emailSpanObj.innerHTML = "邮箱可用";
            }else if(result == 1){
                emailSpanObj.innerHTML = "邮箱不可用"
            }
    })
}
// 手机号文本框失去焦点事件
phoneObj.onblur = function(){
    // 获取文本内容
    var phoneText = this.value;
    myAjax("post","./server/checkPhone.php","e="+emailText,"true","true",function(result){
            if(result.status == 0){
                phoneSpanObj.innerHTML = val.message.tips" "+val.message.phonefrom;
            }else if(result.responseText == 1){
                phoneSpanObj.innerHTML = val.message;
            }
    })
}

仍存在的问题:
* 参数的顺序不可改变
* 参数没有设置默认值,所有的参数必须传递

代码进一步封装

将需要传递的参数做成一个对象,里面有所有参数的默认值,如果没有传入参数就使用默认值,如果传入了,覆盖掉默认参数。

function myAjax2(obj){
    var defaults = {
        type:"get",
        url:"#",
        dataType:"",
        data:{}, //参数可能有多个,用对象保存
        async:true,
        success:function(result){
            console.log(result);
        }
    };
    for(var key in obj){
        defaults[key] = obj[key];
    }
    var xhr = null;
    // 兼容性处理
    if(window.XMLHttpRequest){
        xhr = new XMLHttpRequest();
    }else{
        xhr = new ActiveXObject("Microsoft.XMLHTTP");
    }

    var param = "";
    for(var attr in defaults.data){
        param += attr + "=" +defaults.data[attr] + "&"
    }
    // 去掉最后一个&
    if(param){
        param = param.substring(0, param.length-1);
    }

    if((defaults.type=="get")||(defaults.type=="GET")){
        defaults.url+="?"+param;
    }

    xhr.open(defaults.type,defaults.url,defaults.async);

    if((defaults.type=="get")||(defaults.type=="GET")){
        xhr.send(null);
    }else if((defaults.type=="post")||(defaults.type=="POST")){
        xhr.setRequestHeader('Content-Type','application/x-www-form-urlencoded');
        xhr.send(param);
    }

    if(async){
        xhr.onreadystatechange = function(){
            if(this.readyState == 4){
                if(this.status == 200){
                    if(dataType == "xml"){
                        callback(this.responseXML);
                    }else if(dataType == "json"){
                        callback(JSON.parse(this.responseText));
                    }else{
                        callback(this.responseText);
                    }
                }
            }
        }
    }else{
        if(this.readyState == 4){
            if(this.status == 200){
                if(dataType == "xml"){
                    callback(this.responseXML);
                }else if(dataType == "json"){
                    callback(JSON.parse(this.responseText));
                }else{
                    callback(this.responseText);
                }
            }
        }
    }
}

// 获取所有元素
var userObj = document.getElementByName("username")[0];
var emailObj = document.getElementByName("email")[0];
var phoneObj = document.getElementByName("phone")[0];

var userSpanObj = document.getElementByName("user-span")[0];
var emailSpanObj = document.getElementByName("email-span")[0];
var phoneSpanObj = document.getElementByName("phone-span")[0];

// 用户名文本框失去焦点事件
userObj.onblur = function(){
    myAjax2({
        url:"./server/checkUsername.php",
        type:"get",
        data:{uname:this.value},
        sucess:function(result){
            if(result == "ok"){
                userSpanObj.innerHTML = "用户名可用";
            }else if(result = "error"){
                userSpanObj.innerHTML = "用户名不可用";
            }
        }
    })
}
// 密码文本框失去焦点事件
emailObj.onblur = function(){
    myAjax2({
        url:"./server/checkEmail.php",
        type:"post",
        data:{e:this.value},
        sucess:function(result){
            if(result == 0){
                emailSpanObj.innerHTML = "邮箱可用";
            }else if(result = 1){
                emailSpanObj.innerHTML = "邮箱不可用";
            }
        }
    })
}
// 手机号文本框失去焦点事件
phoneObj.onblur = function(){
    myAjax2({
        url:"./server/checkPhone.php",
        type:"post",
        dataType:"json",
        data:{phonenumber:this.value},
        sucess:function(result){
            if(result.status == 0){
                phoneSpanObj.innerHTML = result.message.tips" "+result.message.phonefrom;
            }else if(result.status = 1){
                phoneSpanObj.innerHTML = result.message;
            }
        }
    })
}

进一步封装后的函数为:myAjax({}),里面是一个对象。使用默认的方式,不仅可以解决传入参数不一致的问题,还可以解决不传参数是默认值的问题。

同步请求和异步请求

同步请求:在用户发送请求之后,浏览器会一直等待服务器的数据返回,如果网络延迟比较高,浏览器就一直卡在当前的页面,直达服务器返回数据才进行其他的操作。
异步请求:在用户进行请求发送后,浏览器可以自由操作页面中的其他元素,当服务器返回数据的时候,才出发响应的是将,对返回的数据进行操作。

如果将Ajax请求改为同步的haul:
1.页面会卡顿,卡顿时间取决于网络的速度
2.xhr.onreadystatechange 的回调函数不会执行,因为在 xhr.send() 之后,xhr.readyState 就为 4 了,所以数据的处理,直接跟在xhr.send() 之后就可以了。

异步底层原理

js 中的异步实现原理是单线程+事件队列。js 的代码执行是单线程的,单线程的意思是代码从上到下按照顺序执行,而事件队列存储了一些回调函数,当 js 从上往下执行的时候,遇到回调函数就将其放到事件队列,在所有 js 代码执行完成之后处于空闲状态时,才会去事件队列看有没有回调函数达到触发条件,有的话就执行,没有的话就继续闲着。
Ajax 的四步操作中,同步和异步的区别:
如果是异步请求,在 send 的时候,会调用浏览器进行网络数据的请求,send 就执行完了,接着将第四步的回调函数存储在事件队列里面,浏览器数据请求完了,readyState 状态发生变化,触发第四步回调函数的执行。
而在同步请求中, send 时是自己进行网络数据的请求,这个时候非得请求到数据,才会接着将第四步的回调函数存储在事件队列里面,所以如果网络延时页面就会卡死,在 send 过后接受到数据的时候 readyState 已经为4了,不会再变化,所以第四步的回调函数不会执行。

数据格式

XML数据格式

XML数据格式是将数据以标签的凡是进行组装,必须以<? xml version="1.0" encoding="utf-8" ?>开头,标签必须成对出现,也就是有开始标签就必须有结束标签。

<? xml version="1.0" encoding="utf-8" ?>
<students>
    <student>
      <name>张三</name>
      <age>18</age>
      <sex></sex>
  </student>
</students>

缺点是体积太大,元数据(描述数据的数据)太多,解析不方便,目前很少使用

json数据格式

通过key-value的方式进行组装

{
   "student" : [
     {
       "name": "张三",
       "age": "18",
       "sex": "男"
     },
     {
       "name": "李四",
      "age": "23",
      "sex": "女"
    }
  ]
}

优点是体积小,传输快,解析方便

案例:获取读书信息

接口文档:

地址/server/getBooks/php
作用描述获取图书信息
请求类型get 请求
参数
返回数据格式xml 格式
返回数据说明如下
<?xml version="1.0" encoding="utf-8"?>
<booklist>
    <book>
        <name>三国演义</name>
        <author>罗贯中</author>
        <desc>一个杀伐纷争的年代</desc>
    </book>
    <book>
        <name>水浒传</name>
        <author>施耐庵</author>
        <desc>108条好汉的故事</desc>
   </book>
   <book>
        <name>西游记</name>
        <author>吴承恩</author>
        <desc>佛教与道教斗争</desc>
   </book>
   <book>
        <name>红楼梦</name>
        <author>曹雪芹</author>
        <desc>一个封建王朝的缩影</desc>
   </book>
</booklist>

源代码:

<!DOCTYPE html>
 <html lang="en">
 <head>
     <meta charset="UTF-8">
     <title>书籍列表</title>
     <style>
         div{
             width: 800px;
             margin: 20px auto;
        }
        table{
            width: 800px;
            margin: 20px auto;
            border-collapse: collapse;
        }
        th{
            background-color: #0094ff;
            color:white;
            font-size: 16px;
            padding: 5px;
            text-align: center;
            border: 1px solid black;
        }
        td{
            padding: 5px;
            text-align: center;
            border: 1px solid black;
        }
    </style>
    <script>
        window.onload = function () {  
            var xhr = new XMLHttpRequest();
            xhr.open("get", "tt.php", true);
            xhr.send(null);
            xhr.onreadystatechange = function () {  
                if(this.readyState == 4) {
                    if(this.status = 200) {
                        var booklists = this.responseXML.getElementsByTagName("booklist")[0].getElementsByTagName("book");

                        for(var i=0; i<booklists.length; i++) {
                            var name = booklists[i].getElementsByTagName("name")[0].textContent;
                            var author = booklists[i].getElementsByTagName("author")[0].textContent;
                            var desc = booklists[i].getElementsByTagName("desc")[0].textContent;

                            var trObj = document.createElement("tr");
                            trObj.innerHTML = "<td>"+name+"</td><td>"+author+"</td><td>"+desc+"</td>";
                            document.getElementsByTagName("table")[0].appendChild(trObj);
                        }
                    }
                }
            };


        };
    </script>
</head>
<body>
    <div>
        <table>
            <tr>
                <th>书名</th>
                <th>作者</th>
                <th>描述</th>
            </tr>
            <!-- <tr>
                <td>三国演义</td>
                <td>罗贯中</td>
                <td>一个杀伐纷争的年代</td>
           </tr> -->
        </table>
    </div>
</body>
</html>

XML数据的格式主要是通过:getElementByTagName来获取的。

案例:获取学生信息

接口文档:

地址/server/getStudents.php
作用描述获取学生信息
请求类型get 请求
参数
返回数据格式json 格式
返回数据说明如下
[
    {
        "name":"张三",
        "age":"18",
        "sex":"男"
    }
]

源代码:

<!DOCTYPE html>
 <html lang="en">
 <head>
     <meta charset="UTF-8">
     <title>书籍列表</title>
     <style>
         div{
             width: 800px;
             margin: 20px auto;
        }
        table{
            width: 800px;
            margin: 20px auto;
            border-collapse: collapse;
        }
        th{
            background-color: #0094ff;
            color:white;
            font-size: 16px;
            padding: 5px;
            text-align: center;
            border: 1px solid black;
        }
        td{
            padding: 5px;
            text-align: center;
            border: 1px solid black;
        }
    </style>
    <script>
        window.onload = function () {  
            var xhr = new XMLHttpRequest();
            xhr.open("get", "tt.php", true);
            xhr.send(null);
            xhr.onreadystatechange = function () {  
                if(this.readyState == 4) {
                    if(this.status = 200) {
                        var jsonObj = JSON.parse(this.responseText);

                        for(var i=0; i<jsonObj.length; i++) {
                            var name = jsonObj[i].name;
                            var age = jsonObj[i].age;
                            var sex = jsonObj[i].sex;

                            var trObj = document.createElement("tr");
                            trObj.innerHTML = "<td>"+name+"</td><td>"+age+"</td><td>"+sex+"</td>";
                            document.getElementsByTagName("table")[0].appendChild(trObj);
                        }
                    }
                }
            };


        };
    </script>
</head>
<body>
    <div>
        <table>
            <tr>
                <th>书名</th>
                <th>作者</th>
                <th>描述</th>
            </tr>
            <!-- <tr>
                <td>张三</td>
                <td>年龄</td>
                <td>性别</td>
           </tr> -->
        </table>
    </div>
</body>
</html>

只需要将获取的responseText转化为json格式的对象,使用JSON.parse(this.responseText);

jQuery中的Ajax

$.ajax()

$.ajax()和上面的myAjax2()使用起开非常相似。同样是传入一个对象,有些参数不传递的话也有默认值。

userObj.blur(function(){
    $.ajax({
        url:"./server/checkUsername.php",
        type:"get",
        data:{uname:this.value},
        success:functio(result){
            if(result == "ok"){
                userSpanObj.text("用户名可用");
            }else if(result == "error"){
                userSpanObj.text("用户名不可用");
            }
        }
    })
})
.get() . g e t ( ) 和 .post

只需要传两个参数,第一个参数是url(带param的,里面有参数和值),第二个参数是回调函数

$.get(url+"?"+param,function(result){});
$.post(url,{参数:值},function(result){});

实例:

<!DOCTYPE html>
 <html lang="en">
 <head>
     <meta charset="UTF-8">
     <title>书籍列表</title>
     <script>
    // 获取所有元素
    var userObj = $("input[name='username']");
    var emailObj = $("input[name='email']");
    var phoneObj = $("input[name='phone']");

  var userSpanObj = $("#user-span");
    var emailSpanObj = $("#email-span");
    var phoneSpanObj = $("#phone-span");

    //用户名文本框失去焦点事件
    userObj.blur(function () {
        $.get("./server/checkUsername.php?uname=" + $(this).val(), function (result) {
            if (result == "ok") {
                userSpanObj.text("用户名可用");
            } else if (result == "error") {
                userSpanObj.text("用户名不可用");
            }
        });
    });

    //邮箱文本框失去焦点事件
    emailObj.blur(function () {
        $.post("./server/checkEmail.php", {e: $(this).val()}, function (result) {
            if (result == 0) {
                emailSpanObj.text("邮箱可用");
            } else if (result == 1) {
                emailSpanObj.text("邮箱不可用");
            }
        });
    });

    //手机号文本框失去焦点事件
    phoneObj.blur(function () {
        $.post("./server/checkPhone.php", {phonenumber: $(this).val()}, function (result) {
            result = JSON.parse(result);
            if (result.status == 0) {
                phoneSpanObj.text(result.message.tips + " " + result.message.phonefrom);
            } else if (result.status == 1) {
                phoneSpanObj.text(result.message);
            }
        });
    });
</script>
</head>
<body>
    <div id="dv">
      <h1>用户注册</h1>
     用户名:<input type="text" name="username"><span id="user-span"></span><br>
      邮箱:<input type="text" name="email"><span id="email-span"></span><br>
      手机:<input type="text" name="phone"><span id="phone-span"></span><br>
   </div>
</body>
</html>

跨域

跨域这个概念来自一个叫“同源策略”的东西。同源策略是浏览器上为了安全考虑实施的非常重要的安全机制。
Ajax默认智能获取带同源的数据,对于非同源的数据,Ajax是获取不到的。
什么是同源?
协议,域名,端口全部相同。
比如一个界面地址为:http://www.example.com/dir/page.html ,在这个地址中取访问下面服务器的数据,会出现什么情况?

URL结果原因
https://www.example.com/dir/other.html不同源协议不同,https 和 http
http://en.example.com/dir/other.html不同源域名不同
http://www.example.com:81/dir/other.html不同源端口不同
http://www.example.com/dir/page2.html同源协议,域名,端口都相同
http://www.example.com/dir2/page.html同源协议,域名,端口都相同

如果使用Ajax获取非同源地址的数据,就要使用跨域。无论是Ajax还是跨域,都是为了访问服务器的数据(比如获取天气信息,航班信息等)

跨域的实现

引入外部js文件
我们可以通过script标签引入一个外部文件,这个外部文件是不涉及到同源策略的影响的。

<script src="http://www.example.com/dir/xxx.js"></script>

引入PHP文件
script引入的应该是js文件,如果我们要引入php文件的话,就要在php代码中,返回js格式的代码。

<?php
    echo "var str = 'hello'";
    echo "func(123)";
?>

在我们的html文件中:

<script>
    function func(data){ // 就为了获取参数
        console.log(data);
    }
</script>
<script src="http://www.example.com/dir/xxx.php"></script>

在进一步,如果我们在PHP地址中传入了参数

<?php
    $city = $_GET["city"];
    if($city == "beijng"){
        echo "func('获取到北京天气')"
    }else{
        echo "func('未获取到天气信息')"
    }
?>

html文件

<script>
    function func(data){ // 就为了获取参数
        console.log(data);
    }
</script>
<script src="http://www.example.com/dir/xxx.php?city=beijing"></script>

动态创建script标签
如果只是手动的在php问价后面传入参数,就太固定了,我们可以根据用户的输入来获取不同城市天气信息。

 <!DOCTYPE html>
 <html lang="en">
 <head>
     <meta charset="UTF-8">
     <title>Title</title>
 </head>
 <body>
 <h1>天气查询</h1><br>
 <input type="text" placeholder="请输入城市" id="txt"><br>
<input type="button" value="获取天气" id="btn">

<script>
    function func(data) {
        console.log(data);
    }

    document.getElementById("btn").onclick = function () {
        var city = document.getElementById("txt").value;

        var script = document.createElement("script");
        script.src = "http://hr.pcebg.efoxconn.com/checkUsername.php?city=" + city;

        document.getElementsByTagName("head")[0].appendChild(script);
    };
</script>
</body>
</html>

动态指定回调函数名称

script.src = "http://hr.pcebg.efoxconn.com/checkUsername.php?city=" + city + "&callback=foo";

外部php代码:

<?php
    $city = $_GET["city"];
    $callback = $_GET["callback"];
    if($city == "beijing") {
        echo $callback . "('获取到北京天气')";
    } else {
          echo $callback . "('为获取到天气信息')";
    }
?>

之后,再看我们在 script 里面写的 foo 函数的定义,会不会觉得很突兀?我们把它改成 window 的方法就可以了。

window["foo"] = function(data) { console.log(data); };

然后把它放到按钮的点击事件中,这样就和按钮的点击事件融为一体了。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<h1>天气查询</h1><br>
<input type="text" placeholder="请输入城市" id="txt"><br>
<input type="button" value="获取天气" id="btn">

<script>
    document.getElementById("btn").onclick = function () {
          window["foo"] = function(data) { console.log(data); };
        var city = document.getElementById("txt").value;

        var script = document.createElement("script");
        script.src = "http://hr.pcebg.efoxconn.com/checkUsername.php?city=" + city + "&callback=foo";

        document.getElementsByTagName("head")[0].appendChild(script);
    };
</script>
</body>
</html>

在修改回调函数的名称时,只需修改两个部分就可以了(window[“foo”] 和 “&callback=foo”;),php 的代码不需要修改。

淘宝提示词

淘宝提示词接口

地址https://suggest.taobao.com/sug
作用描述获取淘宝提示词接口
请求类型get 请求
参数q:关键词; callback:回调函数名称
返回数据格式jsonp格式
 <!DOCTYPE html>
 <html lang="en">
 <head>
     <meta charset="UTF-8">
     <title>Title</title>
 </head>
 <body>
    <div id="dv">
        <h1>淘宝提示词</h1>
        <input type="text" placeholder="请输入关键词" id="txt">
        <input type="button" value="查询" id="btn">
        <ul id="uu"></ul>
    </div>

<script>
    document.getElementById('btn').onclick = function(){
        var script = document.createElement("script");
        var txt = document.getElementById('txt').value;
        script.src = "https://suggest.taobao.com/sug?q="+txt+"&callback=sug";
        window["sug"] = function(data){
            var str = "";
            if(data.result.length !== 0){
                for(var i=0; i<data.result.length; i++){
                    str += "<li>" + data.result[i] + "</li>";
                }
                document.getElementById('uu').innerHTML = str;
            }else{
                str = "<li>未找到关键词</li>";
                document.getElementById('uu').innerHTML = str;
            }
        }
        document.querySelector("head").appendChild(script);
    }
</script>
</body>
</html>

案例:百度提示词

百度提示词接口

地址http://suggestion.baidu.com/su
作用描述获取百度提示词接口
请求类型get 请求
参数web:关键词; cb:回调函数名称
返回数据格式jsonp格式

我们将实现的代码封装成一个js文件

function myAjaxCross(obj){
    var defaults = {
        url:"#", //地址
        data:{}, //业务逻辑参数
        success:function(data){}, //参数传递回来的处理函数
        jsonp:"callback", //获取方法名的key值,是一个回调函数,由后端接口文档指定
        jsonpCallback:"sug" // 获取方法名的value值,也就是方法名字
    }
    //由obj传入的对象覆盖defaults
    for(var key in obj){
        defaults[key] = obj[key];
    }

    var script = document.createElement('script');

    var params = "";
    for(var attr in defaults.data){
        params += attr + "=" + defaults.data[attr] + "&";
    }
    if(params&&(params!=="")){
        params = params.substring(0,params.length-1);
    }

    script.src = defaults.url + "?" +params + "&" + defaults.jsonp + "=" +defaults.jsonpCallback;
    console.log(script.src);

    window[defaults.jsonpCallback] = function(data){
        defaults.success(data);
    }
    document.querySelector("head").appendChild(script);
}

百度提示词使用这个封装好的js

 <!DOCTYPE html>
 <html lang="en">
 <head>
     <meta charset="UTF-8">
     <title>Title</title>
 </head>
 <body>
    <div id="dv">
        <h1>百度提示词</h1>
        <input type="text" placeholder="请输入关键词" id="txt">
        <input type="button" value="查询" id="btn">
        <ul id="uu"></ul>
    </div>
    <script type="text/javascript" src="my-sug.js"></script>>
    <script>
        document.getElementById('btn').onclick = function(){
            myAjaxCross({
                url:"http://suggestion.baidu.com/su",
                data:{wd:document.getElementById('txt').value},
                success:function(data){
                    console.log(data);

                    var str = "";
                    if(data.s.length !== 0){
                        for(var i=0; i<data.s.length;i++){
                            str += "<li>"+data.s[i]+"</li>";
                        }
                        document.getElementById("uu").innerHTML = str;
                    }else{
                        str="<li>未找到关键词</li>";
                        document.getElementById("uu").innerHTML = str;
                    }
                },
                jsonp:"cb",
                jsonpCallback:"sug"
            })
        }
    </script>
</body>
</html>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值