菜单 学习猿地 - LMONKEY

VIP

开通学习猿地VIP

尊享10项VIP特权 持续新增

知识通关挑战

打卡带练!告别无效练习

接私单赚外块

VIP优先接,累计金额超百万

学习猿地私房课免费学

大厂实战课仅对VIP开放

你的一对一导师

每月可免费咨询大牛30次

领取更多软件工程师实用特权

入驻
0
0

Ajax基础和手写封装Ajax函数

原创
05/13 14:22
阅读数 160

ajax概述

背景

在了解 AJAX 之前我们可以简单的认为「JavaScript 能力有限」,因为在此之前 Web 平台提供所有的 API 都只停留在「单机」的阶段。

这样就会造成一些无法实现的功能,例如:

● 无法在实现用户登录功能时,当用户输入邮箱地址显示用户对应的头像。
● 无法在实现用户注册功能时,当用户输入邮箱或用户名就提示是否存在
● 无法在实现留言板功能时,实时看到最新的用户留言。

这些功能的开发都卡在一个相同的问题

● 数据存放在服务端,无法通过已知的API获取

需求

● 对服务端发出请求并且接受服务端的响应
● 如果可以通过JS直接发送网络请求,那么web的可能就会更多,随之能够实现的功能也会更多,至少不再是只能开发[单机游戏]

Google Suggest

● AJAX(Asynchronous JavaScript and XML),最早出现在 2005 年的 Google Suggest
● 它不是像 HTML、JavaScript 或 CSS 这样的一种“正式的”技术
● 它是在浏览器端进行网络编程(发送请求、接收响应)的技术方案
● 它使我们可以通过 JavaScript 直接获取服务端最新的内容而不必重新加载页面
● 让 Web 更能接近桌面应用的用户体验

AJAX

● AJAX 就是浏览器提供的一套 API,可以通过 JavaScript 调用,从而实现通过代码控制请求与响应。实现通过 JavaScript 进行网络编程。
● XML:最早在客户端与服务端之间传递数据时所采用的数据格式。

应用场景

● 按需获取数据
● 对用户数据校验
● 自动更新页面内容
● 提升用户体验,无刷新的体验

体验ajax

● 使用 jQuery 中封装的 Ajax,快速体验带来.
● 免费接口:https://jsonplaceholder.typicode.com/

原生AJAX

发送ajax请求步骤

1.创建XMLHttpRequest类型的对象
2.准备发送,打开与一个网址之间的连接
3.执行发送动作
4.指定xhr状态变化事件处理函数

XMLHttpRequest类型对象

● AJAX API中核心提供的是一个XMLHttpRequest类型,所有的AJAX操作都需要使用这个类型。

兼容问题

● var xhr = new XMLHttpRequest();
● IE6兼容:xhr = new ActiveXObject(“Microsoft.XMLHTTP”);
● 代码演示

//1.获取XMLHttpRequest类型的对象
// 兼容问题
var xhr;
if(window.XMLHttpRequest){
    xhr = new XMLHttpRequest();
}else {
    // IE6兼容
    xhr = ActiveXObject("Microsoft.XMLHTTP");
}

open方法开启请求

● 本质上XMLHttpRequest就是JavaScript在web平台中发送HTTP请求的手段,因此发送出去的请求仍然是HTTP请求,同样符合HTTP约定的格式。

语法:xhr.open(method,url);

● method: 要使用的HTTP方法。

比如 [ GET ] (获取数据) 、 [POST] (提交新的数据) 、 [PUT] (数据中进行更改)、 [DELETE] (删除数据) 等。

● url: 要向其发送请求的url地址,字符串格式。
● 代码演示

// 2.打开连接
// get方式:可在地址后面追加信息,多条用&连接
// post方式,必须通过send方法进行传递数据
xhr.open("get","https://jsonplaceholder.typicode.com/users?id=1");
xhr.open("post","https://jsonplaceholder.typicode.com/users");

setRequestHeader()方法设置请求头

● 此方法必须在 open() 方法和 send() 之间调用

语法:xhr.setRequestHeader(header,value)

● header: 一般设置"Content-Type",传输数据类型,即:服务器需要我们传送的数据类型。
● value: 具体的数据类型,常用"application/x-www-form-urlencoded"和"application/json"。
● 代码演示

// 设置响应头
// get方式不用设置,而post必须设置
xhr.setRequestHeader("Content-Type","application/x-www-form-urlencoded");

send方法和请求头

● 用于发送HTTP请求

语法:xhr.send(body)

● body: 在XHR请求中要发送的数据体,根据请求头中的类型进行传参。
● 如果是GET方法,无需设置数据体,可以传null或者不传参。
● 代码演示

// 3.执行发送动作
// get方式
// xhr.send(null);
// post方式
xhr.send("name=mh&age=18");

readyState属性

● readyState 属性返回一个 XMLHttpRequest 代理当前所处的状态,由于 readystatechange 事件是在 xhr 对象状态变化时触发(不单是在得到响应时),也就意味着这个事件会被触发多次。
● 如图所示
图片.png
图片.png
● 代码演示

//1.获取XMLHttpRequest类型的对象
// 兼容问题
var xhr;
if(window.XMLHttpRequest){
    xhr = new XMLHttpRequest();
}else {
    // IE6兼容
    xhr = ActiveXObject("Microsoft.XMLHTTP");
}
// 初始化
console.log("UNSEND",xhr.readyState);

// 2.打开连接
xhr.open("post","https://jsonplaceholder.typicode.com/users");
// 创建连接
console.log("OPENED",xhr.readyState);

// 设置响应头
xhr.setRequestHeader("Content-Type","application/x-www-form-urlencoded");

// 3.执行发送动作
// post方式
xhr.send("name=mh&age=18");

// 4.指定xhr状态变化事件处理函数
xhr.onreadystatechange = function (){
    if(this.readyState === 2){
       // 接收到响应头
       console.log("HEADERS_RECEIVED",xhr.readyState);
    }else if(this.readyState === 3){
        // 响应体加载中
       console.log("LOADING",xhr.readyState);
    }else if(this.readyState === 4){
        // 加载完成
        console.log("DONE",xhr.readyState);
    }
}

事件处理函数

● 一般都是在readyState值为4时,执行响应的后续逻辑。
● 代码演示

// 4.指定xhr状态变化事件处理函数
xhr.onreadystatechange = function (){
    if(this.readyState === 4){
        console.log(this.responseText);
    }
}

同步与异步

显示场景理解

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

ajax中的实现

● xhr.open()方法第三个参数要求传入的是一个boolean值,其作用就是设置此次请求是否采用异步方式执行。
● 默认:true 异步,如果需要同步执行可以通过传递false实现。
● 同步执行,代码会卡在xhr.send()这一步,等到所有的数据都传输完成,才会往下执行。

建议

● 问题:同步执行的时候,为什么onreadystatechange事件不会被触发

因为:onreadystatechange事件,只有在readystate变化的时候才会被触发。当同步执行的时候,全部的数据传输完成后,那么readystate将不会再变化,那么此时注册了事件,也不会再被触发。
解决方法:为了让事件更加可靠(一定触发),再发送请求send()之前,一定是先注册onreadystatechange事件。

● 代码演示(不论是同步还是异步都能触发成功)

 //1.获取XMLHttpRequest类型的对象
// 兼容问题
var xhr;
if(window.XMLHttpRequest){
    xhr = new XMLHttpRequest();
}else {
    // IE6兼容
    xhr = ActiveXObject("Microsoft.XMLHTTP");
}

// 2.打开连接
// 异步执行
// xhr.open("post","https://jsonplaceholder.typicode.com/users",true);
// 同步执行
xhr.open("post","https://jsonplaceholder.typicode.com/users",false);

// 设置响应头
// get方式不用设置,而post必须设置
xhr.setRequestHeader("Content-Type","application/x-www-form-urlencoded");

// 4.指定xhr状态变化事件处理函数
xhr.onreadystatechange = function (){
    if(this.readyState === 4){
        // 加载完成
        console.log("DONE",xhr.readyState);
    }
}
// 3.执行发送动作
// post方式
xhr.send("name=mh&age=18");

// ajax后面的代码
console.log("after ajax");

● 了解同步模式即可,切记不要使用同步模式。

响应数据格式

提问

● 如果希望服务端返回一个复杂数据,该如何处理?
● 关心的问题:服务端发出何种格式的数据,这种格式如何在客户端用JavaScript解析。

XML

● 一种数据描述手段
● 淘汰的原因:

数据冗余太多。元数据(用来描述数据的数据)占用的数据量比较大,不利于大量数据的网络传输。
在其他语言中,比如js解析内部数据时,方法比较复杂,不方便使用。

● 代码演示

<?xml verson="1.0" encoding="utf-8" ?>
<booklist>
    <book>
       <name>三国演义</name>
       <author>罗贯中</author>
       <cate>古典名著</cate>
    </book>
    <book>
       <name>西游记</name>
       <author>吴承恩</author>
       <cate>古典名著</cate>
    </book>
    <book>
       <name>红楼梦</name>
       <author>曹雪芹</author>
       <cate>古典名著</cate>
    </book>
</booklist>

JSON

● JavaScript Object Notation 对象表示法
● 也是一种数据描述手段,类似于JavaScript字面量方式
● 服务端采用JSON格式返回值,客户端按照JSON格式解析数据

JSON格式的数据与对象字面量的区别:

1.JSON 数据并不需要存储在变量里面
2.结束时不需要写分号
3.JSON 数据中的属性名必须加 引号
演示代码

// 对象字面量
var obj = {
    name:"mw",
    age:45,
    brother:{
        name:"lh",
        age:36
    }
};
// json格式的数据
{
    "name":"zs",
    "age":18,
    "hobby":["paino","paint"]
}

ES5新增JSON对象

● JSON对象的parse方法

参数:字符串(符合JSON格式)
返回值:转换成一个对象

● JSON对象的stringify方法

参数:对象
返回值:字符串(符合JSON格式)

● 演示代码

// 对象字面量
var obj = {
    name:"mw",
    age:45,
    brother:{
        name:"lh",
        age:36
    }
};

// 创建一个符合JSON数据格式的字符串
var str = '{"name":"ff","age":99}';
// es5中新增了JSON对象
// JSON对象的parse方法和stringify方法
// 1.stringify方法
// 将对象字面量转换成 字符串形式
console.log(JSON.stringify(obj));
// 将符合JSON数据格式的字符串,转换成对象
var s = JSON.parse(str);
console.log(s);
// 可以通过打点调用属性
console.log(s.name); // ff
console.log(s.age);  // 99

注意

● 不管是JSON还是XML,只是在AJAX请求过程中用到,并不代表它们与AJAX之间有必然的联系,它们只是数据协议。
● 不管服务端采用XML还是JSON,本质上都是将数据返回给客户端。
● 服务端应该根据响应内容的格式设置一个合理的Content-Type.

JSON Server

● 平时会写一些数据,通过ajax获取。所以,需要在本地搭建一个临时服务器。
● json-server是一个Node模块,运行Express服务器,可以指定一个json文件作为api的数据源。
● 可以使用json-server快速搭建一个web服务器。
● 网址:https://github.com/typicode/json-server

原生AJAX具体用法

JSON文件书写方法

● JSON文件中的属性名,后续会成为路由名。

在命令行中

● 进入某一个具体的文件夹:输入cd,先不回车,然后在后边输入想要进入的文件夹路径,即可进入该文件夹。(将JSON文件托管到json-server服务端时,要注意路径是否正确)
● 否则会出现:文件找不到的情况,那么服务端会自动创建一个同名的json文件。
● 如下图
图片.png

GET请求

● 通常在第一次get请求中,参数传递都是通过URL地址中的’?'参数传递。
● 一般在GET请求中,无需设置请求头。
● 无需设置响应体,可以传null或者不传

案例:对自己在服务端部署的JSON文件进行get请求

● 返回:符合要求的数据

// 创建xhr对象,兼容写法
var xhr = window.XMLHttpRequest 
? new XMLHttpRequest()
: new ActiveXObject("Microsoft.XMLHTTP");

// 打开链接
// xhr.open(method,url);
// get请求
// 传递参数,筛选获取
xhr.open("get","http://localhost:3000/users?age=15");
// 执行发送
xhr.send(null);

// 指定xhr状态变化事件处理函数
xhr.onreadystatechange = function (){
    if(this.readyState === 4){
        console.log(this.responseText);
    }
}

POST请求

● POST请求过程中,都是采用请求体承载需要提交的数据。
● 需要设置请求头中的Content-Type,以便于服务端接收数据。
● 需要提交到服务端的数据可以通过send方法的参数传递。

案例:对自己在服务端部署的JSON文件进行post请求

● 返回:新增加的数据,并且查看json文件中也已经成功添加了数据,id自动增加。

// 创建xhr对象,兼容写法
var xhr = window.XMLHttpRequest 
? new XMLHttpRequest()
: new ActiveXObject("Microsoft.XMLHTTP");
        
// 打开链接
// xhr.open(method,url);
// post请求
xhr.open("post","http://localhost:3000/users");

// post请求,必须要设置请求头
xhr.setRequestHeader("Content-Type","application/x-www-form-urlencoded");
// 执行发送
xhr.send('name=bb&age=23&class=2');

// 指定xhr状态变化事件处理函数
xhr.onreadystatechange = function (){
    if(this.readyState === 4){
        console.log(this.responseText);
    }
}

● send()方法传递值时的三种写法
● 代码演示

// 第一种方法
// post请求,必须要设置请求头
xhr.setRequestHeader("Content-Type","application/x-www-form-urlencoded");
// 执行发送
xhr.send('name=bb&age=23&class=2');

// 第二种方法
xhr.setRequestHeader("Content-Type","application/json");
// json数据格式
xhr.send('{"name":"bn","age":23,"class":1}');

// 第三种方法
xhr.setRequestHeader("Content-Type","application/json");
// 对象转字符串
xhr.send(JSON.stringify({
    name:"nn",
    age:12,
    class:2
}));

处理响应数据渲染

● 客户端中拿到请求的数据后,需要把这些数据呈现到界面上。
● 数据结构简单:可以直接通过**字符串操作(拼接)**的方式处理。当数据过于复杂时,不推荐使用,字符串拼接维护成本太大。
● 数据结构复杂:推荐使用模板引擎或者ES6提供的模板字符串。
● 代码演示

* {
    margin: 0;
    padding: 0;
}
table {
    width: 300px;
    /* 上下30 左右居中 */
    margin: 30px auto;
    font: 14px/28px "微软雅黑";
    color: #333;
    /* 取消边框之间的缝隙 */
    border-collapse: collapse;
    /* border: 1px solid #666; */
}
td,th {
    width: 100px;
}
<!-- table表格中,tr表示一行,th表示表头,td表示每个单元格
         其中 th和td 必须在tr中 -->
    <table border = "1" class ="box"> 
        <tr>
            <th>学号</th>
            <th>姓名</th>
            <th>班级</th>
            <th>年龄</th>
        </tr>
    </table>
    <script src="js/jquery.min.js"></script>
    <script>
        // 获取元素
        // var $box = $(".box");
        var box = document.getElementsByClassName("box")[0];

        // 创建xhr对象,兼容写法
        var xhr = window.XMLHttpRequest 
        ? new XMLHttpRequest()
        : new ActiveXObject("Microsoft.XMLHTTP");
        
        // 打开链接
        xhr.open("get","http://localhost:3000/users");
        // 执行发送
        xhr.send(null);

        // 指定xhr状态变化事件处理函数
        xhr.onreadystatechange = function (){
            if(this.readyState === 4){
                // 返回数组 数组也是对象
                // console.log(this.responseText);
                // 将返回的结构 渲染到表格中
                var data = JSON.parse(xhr.responseText);
                console.log(data);
                var str = "";
                for(var i = 0; i < data.length; i++){
                    // 1. 拼接字符串(适用于:简单数据结构)
                    str += '<tr><td>'+ data[i].id +'</td><td>'+ data[i].name +'</td><td>'+ data[i].class +'</td><td>'+ data[i].age +'</td></tr>';
                    // 2.数据结构复杂:推荐使用**模板引擎**或者**ES6提供的模板字符串**
                    // ES6推荐的模板字符串 可以包含空格
                    str += `<tr>
                        <td>${data[i].id}</td>
                        <td>${data[i].name}</td>
                        <td>${data[i].class}</td>
                        <td>${data[i].age}</td>
                        </tr>`;
                }
                // console.log("hi");
                box.innerHTML += str;
            }
        }
    </script>

封装AJAX库

封装一个ajax函数

● 主要是为了了解封装的过程,一般情况在开发中都是使用第三方提供的 AJAX 库,因为它们可能更加严谨。
● 为了在后续的开发过程中可以更方便的使用这套 API,一般的做法都是将其封装到一个函数中以便调用。
● 代码演示(将封装好的函数单独提取到一个文件中)

<script>
        // 封装自己的ajax函数
        /* 参数1:{string} method 请求方法
           参数2:{string} url 请求地址
           参数2:{Object} params 请求参数
           参数3:{function} done 请求完成后执行的回调函数
        */
       function ajax(method,url,params,done){
            // 创建xhr对象,兼容写法
            var xhr = window.XMLHttpRequest 
            ? new XMLHttpRequest()
            : new ActiveXObject("Microsoft.XMLHTTP");

            // 将method转换成大写
            method = method.toUpperCase();
            // 参数拼接
            var pair = [];
            for(var k in params){
                pair.push(k + "=" + params[k]);
            }
            var str = pair.join("&");
            // 判断请求方法
            if(method === "GET"){
                // 字符串拼接 或者 模板字符串
                url += "?" + str;
            }
            xhr.open(method,url);

            var data = null;
            if(method === "POST"){
                // 需要请求头
                xhr.setRequestHeader("Content-Type","application/x-www-form-urlencoded");
                data = str;
            }
            xhr.send(data);

            // 指定xhr状态变化事件处理函数
            // 执行回调函数
            xhr.onreadystatechange = function (){
                if(this.readyState === 4){
                    // 返回的应该是一个对象,这样客户端更好渲染
                    done(JSON.parse(xhr.responseText));
                }
            }
       }

    //    调用自己写的ajax函数
    ajax("get","http://localhost:3000/users",{
        name:"zs",
        age:45
    },function (a){
        console.log(a);
    });
</script>

● 如图所示,以后只需要引用即可
图片.png

发表评论

0/200
0 点赞
0 评论
收藏