Loading

Ajax加强

XMLHttpRequest 的基本使用

什么是 XMLHttpRequest

XMLHttpRequest(简称xhr)是浏览器提供的JavaScript对象,通过它,可以请求服务器上的数据资源。

jQuery中的Ajax函数,就是基于xhr对象封装出来的。

使用xhr发起GET请求

  1. 创建xhr对象
  2. 调用xhr.open()函数
  3. 调用xhr.send()函数
  4. 监听xhr.onreadystatechange事件
//1. 创建xhr对象 
var xhr = newXMLHttpRequest()
//2. 调用xhr.open()函数
xhr.open('GET','http://www.liulongbin.top:3006/api/getbooks')
//3. 调用xhr.send()函数
xhr.send()
//4. 监听xhr.onreadystatechange事件
xhr.onreadystatechange = function(){
    //4.1 监听xhr对象的请求状态 readyState;与服务器响应状态 status
    if(xhr.readyState === 4 && xhr.status === 200){
        //4.2 打印服务器响应回来的数据
        console.log(xhr.respanseText)
    }
}

了解xhr对象的readyState属性

XMLHttpRequest 对象的readyState属性,用来表示当前Ajax请求所处的状态。每个Ajax请求必然处于以下状态中的一个:

状态 描述
0 UNSENT XMLHttpRequest对象已被创建,但尚未调用open方法。
1 OPENED open()方法已经被调用。
2 HEADERS_RECEIVED send()方法已经被调用,响应头也已经被接收。
3 LOADING 数据接收中,此时response属性中已经包含部分数据。
4 DONE Ajax请求完成,这意味着数据传输已经彻底完成失败

使用xhr发起带参数的GET请求

使用xhr对象发起带参数的GET请求时,只需在调用xhr.open期间,为URL地址指定参数即可:

//...
xhr.open('GET','http://www.liulongbin.top:3006/api/getbooks?id=1')
//...

这种在URL地址后面拼接的参数,叫做查询字符串

查询字符串

什么是查询字符串

定义:查询字符串(URL参数)是指在 URL 的末尾加上用于向服务器发送信息的字符串(变量)。

格式:将英文的 ? 放在URL的末尾,再加上 参数=值,想加上多个参数的话,使用 & 符号进行分隔。以这个形式,可以将想要发送给服务器的数据添加到 URL 中。

//不带参数的URL地址
http://www.liulongbin.top:3006/api/getbooks?
//带有一个参数的URL地址
http://www.liulongbin.top:3006/api/getbooks?id=1
//带有两个参数的URL地址
http://www.liulongbin.top:3006/api/getbooks?id=1&bookname=西游记

GET请求携带参数的本质

无论使用$.ajax(),还是使用$.get(),又或者直接使用 xhr 对象发起 GET 请求,当需要携带参数的时候,本质上,都是直接将参数以查询字符串的形式,追加到 URL 地址的后面,发送到服务器的。

$.get('url',{name:'zs',age:20},function(){})
//等价于
$.get('url?name=zs&age=20',function(){})

$.ajax({method:'GET',url:'url',data:{name:'zs',age:20},function(){} })
//等价于
$.ajax({method:'GET',url:'url?name=zs&age=20',function(){} })

URL编码与解码

什么是URL编码

URL地址中,只允许出现英文相关的字母、标点符号、数字,因此,在URL地址中不允许出现中文字符。

如果URL中需要包含中文这样的字符,则必须对中文字符进行编码(转义)。

URL编码的原则:使用安全的字符(没有特殊用途或者特殊意义的可以打印字符)去表示那些不安全的字符。

URL编码原则的通俗理解:使用英文字符去表示非英文字符

http://www.liulongbin.top:3006/api/getbooks?id=1&bookname=西游记
//经过URL编码之后,URL地址变成了如下格式:
http://www.liulongbin.top:3006/api/getbooks?id=1&bookname=%E8%A5%BF%E6%B8%B8%E8%AE%B0
//西        游        记
//%E8%A5%BF %E6%B8%B8 %E8%AE%B0

如何对URL进行编码与解码

浏览器提供了 URL 编码与解码的 API,分别是:

  • encodeURL() 编码的函数
  • decodeURL() 编码的函数
encodeURL('扣一送地狱火')
// 输出字符串 %E6%89%A3%E4%B8%80%E9%80%81%E5%9C%B0%E7%8B%B1%E7%81%AB
decodeURL('%E6%89%A3%E4%B8%80')
// 输出字符串 扣一

注意:每三组%组成一个中文字符串

URL编码的注意事项

由于浏览器会自动对URL地址进行编码操作,因此大多数情况下,程序员不需要关心URL地址的编码与解码操作。

使用xhr发起POST请求

步骤:

  1. 创建xhr对象
  2. 调用xhr.open() 函数
  3. 设置Content-Type 属性(固定写法)
  4. 调用xhr.send()属性,同时指定要发送的数据
  5. 监听xhr.onreadystatechange 事件
//1. 创建xhr对象 
var xhr = newXMLHttpRequest()
//2. 调用xhr.open()函数
xhr.open('POST','http://www.liulongbin.top:3006/api/addbook')
//3. 设置Content-Type属性(固定写法)
xhr.setRequestHeader('Content-Type','application/x-www-form-urlencoded')
//4. 调用xhr.send()函数,同时将数据以查询字符串的方式,提交给服务器
xhr.send('bookname=水浒传&author=施耐庵&publisher=天津图书出版社')
//5. 监听xhr.onreadystatechange事件
xhr.onreadystatechange = function(){
    //5.1 监听xhr对象的请求状态 readyState;与服务器响应状态 status
    if(xhr.readyState === 4 && xhr.status === 200){
        //5.2 打印服务器响应回来的数据
        console.log(xhr.respanseText)
    }
}

数据交换格式

什么是数据交换格式

数据交换格式,就是服务器端客户端之间进行数据传输与交换的格式

前端邻域,经常提及的两种数据交换格式分别是 XML 和 JSON 。其中 XML 用的非常少,故重点学习 JSON 数据交换格式。

XML

什么是 XML

XML 的英文全称是 EXtensible Markup Language,即可拓展标记语言。因此,XML 和 HTML 类似,也是一种标记语言。

HTML:

<!DOCTYPE html>
<html>
    <head>
        <title>Document</title>
    </head>
    <body>
        
    </body>
</html>

XML:

<node>
	<to>ls</to>
    <form>zs</form>
    <heading>通知</heading>
    <body>晚上开会</body>
</node>

XML 和 HTML 的区别

XML 和HTML 虽然都是标记语言,但是两者之间没有任何的关系。

  • HTML 被设计用来描述网页上的内容,是网页内容的载体
  • XML 被设计用来传输和存储数据,是数据的载体

XML 的缺点

  1. XML 格式臃肿,和数据无关的代码多,体积大,传输效率低。
  2. 在 JavaScript 中解析 XML 比较麻烦

JSON

什么是 JSON

JSON 的英文全称是JavaScript Object Notation,即“ JavaScript 对象表示法”。简单来讲,JSON 就是 JavaScript 对象和数组的字符串表示法,它使用文本表示一个 JS 对象或数组的信息,因此,JSON 的本质是字符串

作用:JSON 是一种轻量级的文本数据交换格式,在作用上类似于 XML,专门用于存储和传输数据,但是JSON 比XML 更小、更快、更易解析

现状:JSON 是在2001年开始被推广和使用的数据格式,距今为止,JSON 已经成为了主流的数据交换格式

JSON 的两种结构

JSON 就是用字符串表示 JavaScript 的对象和数组。

JSON 中包含对象数组两种结构,通过这两种结构互相嵌套,可表示各种复杂的数据结构。

对象结构:对象结构在 JSON 中表示 {} 括起来的内容。数据结构为 { key:value,key:value,...} 的键值对结构。其中,key 必须是使用英文的双引号包裹的字符串,value 的数据类型可以是数字、字符串、布尔值、null、数组、对象这6种类型。

数组结构:数组结构在 JSON 中表示为 [] 括起来的内容。数据结构为 ["java","javascript",30,true ...]。数组中数据的类型可以是数字、字符串、布尔值、null、数组、对象这6种类型。

JSON 语法注意事项

  1. 属性名必须使用双引号包裹。
  2. 字符串类型的值必须使用双引号包裹。
  3. JSON 中不允许使用单引号表示字符串。
  4. JSON 中不能写注释。
  5. JSON 的最外层必须是对象或数组格式。
  6. 不能使用 undefined 或函数作为 JSON 的值。

JSON 和 JS 对象的关系

JSON 是 JS 对象的字符串表示法,它使用文本表示一个 JS 对象的信息,本质是一个字符串。例如:

//这是一个对象
var obj = {a: 'Hello',b: 'World'}

//这是一个 JSON 字符串,本质是一个字符串
var json = '{"a":"Hello","b":"World"}'

JSON 和 JS 对象的互转

要实现从 JSON 字符串转换为 JS 对象,使用 JSON.parse() 方法:

var obj = JSON.parse('{"a":"Hello","b":"World"}')
//结果是{a:'Hello',b: 'World'}

序列化和反序列化

数据对象转换为字符串的过程,叫做序列化,例如:

​ 调用 JSON.stringify() 函数的操作,叫做 JSON 序列化。

字符串转换为数据对象的过程,叫做反序列化,例如:

​ 调用 JSON.parse() 函数的操作,叫做 JSON 反序列化。

封装自己的 Ajax 函数

要实现的效果

<!-- 1. 导入自定义的Ajax函数库 -->
<script src="./myAjax.js"></script>

<script>
	//2. 调用自定义的 myAjax 函数,发起 Ajax 数据请求
    myAjax({
        method:'请求类型',
        url:'请求地址',
        data:{/* 请求参数对象 */},
        success:function(res){ // 成功的回调函数
            console.log(res)   // 打印数据
        }
    })
</script>

定义 options 参数选项

myAjax() 函数是我们自定义的 Ajax 函数,它接收一个配置对象作为参数,配置对象中可以配置如下属性:

  • method 请求类型
  • url 请求的 URL 地址
  • data 请求携带的数据
  • success 请求成功之后的回调函数

处理 data 参数

需要把 data 对象,转化为查询字符串的格式,从而提交给服务器,因此提前定义 resolveData 函数如下:

/**
*	处理 data 参数
*	@param {data} 需要发送到服务器的数据
*	@returns {string} 返回拼接好的查询字符串 name=zs&age=10
*/
function resolveData(data){
    var arr = []
    for(let k in data){
        arr.push(k + '=' + data[k])
    }
    return arr.join('&')
}

定义 myAjax 函数

myAjax() 函数中,需要创建 xhr 对象,并监听 onreadystatechange 事件:

function myAjax(options){
    var xhr = new XMLHttpRequest()
    //拼接查询字符串
    var qs = resolveData(options.data)
    
    //监听请求状态改变的事件
    xhr.onreadystatechange = function(){
    	if(xhr.readyState === 4 && xhr.status === 200){
        	var result = JSON.parse(xhr.respnseText)
        	options.success(result)
    	}
	}
}

判断请求的类型

不同的请求类型,对应 xhr 对象的不同操作,因此需要对请求类型进行判断:

if(options.method.toUpperCase() === 'GET'){
    // 发起 GET 请求
    xhr.open(options.method,options.url + '?' + qs )
    xhr.send()
}else if(options.method.toUpperCase() === 'POST'){
    // 发起 POST 请求
    xhr.open(options.method,options.url)
    xhr.setRequestHeader('Content-Type','application/x-www-form-urlencoded')
    xhr.send(qs)
}

XMLHttpRequest Level2 的新特性

认识 XMLHttpRequest Level2

旧版 XMLHttpRequest Level2 的缺点

  1. 只支持文本数据的传输,无法用来读取和上传文件。
  2. 传送和接收数据时,没有进度信息,只能提示有没有完成。

XMLHttpRequest Level2 的新功能

  1. 可以设置 HTTP 请求的时限。
  2. 可以使用 FormData 对象管理表单数据。
  3. 可以上传文件。
  4. 可以获得数据传输的进度信息。

设置 HTTP 请求时限

有时,Ajax 操作很耗时,而且无法预知要花多少时间。如果网速很慢,用户可能要等很久。新版本的 XMLHttpRequest 对象,增加了 timeout 属性,可以设置 HTTP 请求的时限:

xhr.timeout = 3000

上面的语句,将最长等待事件设置为 3000 毫秒。过了这个时限,就自动停止 HTTP 请求。与之配套的还有一个 timeout 事件,用来指定回调函数:

xhr.ontimeout = function(event){
    alert('请求超时!')
}

FormData 对象管理表单数据

Ajax 操作往往用来 提交表单数据。为了方便表单处理,HTML5 新增了一个 FormData 对象,可以模拟表单操作:

//1. 新建 FormData 对象
var fd = new FormData()
//2. 为 FormData 添加表单项
fd.append('uname','zs')
fd.append('upwd','123456')
//3. 创建 XHR 对象
var xhr = new XMLHttpRequest()
//4. 指定请求类型与 URL 地址
xhr.open('POST','http://www.liulongbin.top:3006/api/formdata')
//5. 直接提交 FormData 对象,这与提交网页表单的效果,完全一样
xhr.send(fd)

FormData 对象也可以用来获取表单的值,示例:

// 获取表单元素
var form = document.querySelector('#form1')
// 监听表单元素的 submit 事件
form.addEventListener('submit',function(e){
    e.preventDefault()
    // 根据 form 表单创建 FormData 对象,会自动将表单数据填充到 FormData 对象中
    var fd = new FormData(form)
    var xhr = new XMLHttpRequest()
    xhr.open('POST','http://www.liulongbin.top:3006/api/formdata')
    xhr.send(fd)
    xhr.onreadystatechange = function(){}
})

上传文件

新版 XMLHttpRequest 对象,不仅可以发送文本信息,还可以上传文件。

步骤:

  1. 定义 UI 结构。
  2. 验证是否选择了文件。
  3. 向 FormData 中追加文件。
  4. 使用 xhr 发起上传文件的请求。
  5. 监听 onreadystatechange 事件。

定义 UI 结构

<!-- 1. 文件选择框 -->
<input type = "flie" id = "file1">
<!-- 2. 上传按钮 -->
<button id = "btnUpload">上传文件</button>
<br/>
<!-- 3. 显示上传到服务器的上的图片 -->
<img src = "" alt = "" id = "img" width = "800" />

验证是否选择了文件

// 1. 获取上传文件的按钮
var btnUpload = document.querySelector('#btnUpload')
// 2. 为添加 click 事件监听
btnUpload.addEventListener('click',function(){
    // 3. 获取到选择的文件列表
    var files = document.querySelector('#file1').files
    if(files.length <= 0){
        return alert('请选择要上传的文件!')
    }
    // ...后续业务逻辑
})

向 FormData 中追加文件

// 1. 创建 FormData 对象
var fd = new FormData()
// 2. 向 FormData 中追加文件
fd.append('avatar',files[0])

使用 xhr 发起上传文件请求

// 1. 创建 xhr 对象
var xhr = new XMLHttpRequest()
// 2. 调用 open 函数,指定请求类型与 URL 地址。其中,请求类型必须为 POST
xhr.open('POST','http://www.liulingbin.top:3006/api/upload/avatar')
// 3. 发起请求
xhr.send(fd)

监听 onreadystatechange 事件

xhr.onreadystatechange = function(){
    if(xhr.readyState === 4 && xhr.status === 200){
        var data = JSON.parse(xhr.responseText)
        if(data.status === 200){ // 上传文件成功
            // 将服务器返回的图片地址,设置为 <img> 标签的 src 属性
            document.querySelector('#img').src = 'http:www.liulingbin.top:3006' + data.url
        }else{ // 上传文件失败
        	console.log(data.message)
        }
    }
}

显示文件上传进度

新版本的 XMLHttpRequest 对象中,可以通过监听 xhr.upload.onprogress 事件,来获取到文件的上传进度。

语法格式如下:

// 创建 XHR 对象
var xhr = new XMLHttpRequest()
// 监听 xhr.upload 的 onprogress 事件
xhr.upload.onprogress = function(e){
    // e.lengthComputable 是一个布尔值,表示当前上传的资源是否具有可计算的长度
    if(e.lengthComputable){
        // e.loaded 已传输的字节
        // e.total  需传输的总字节
        var percentComplete = Math.ceil((e.loaded / e.total) * 100)
    }
}

进度条美化

使用 Bootstrap 的库或其他的库进行美化进度条

监听上传进度的事件

xhr.upload.onprogress = function(e){
    if(e.lengthComputable){
        // 1. 计算出当前上传进度的百分比
        var percentComplete = Math.ceil((e.load / e.total) * 100)
        $('#percent')
        	// 2. 设置进度条的宽度
        	.attr('style','width:' + percentComplete + '%')
        	// 3. 显示当前的上传进度百分比
        	.html(percentComplete + '%')
    }
}

监听上传完成的事件

xhr.upload.onload = function(){
    $('#percent')
    	// 移除上传中的类样式
    	.removeClass()
    	// 添加上传完成的类样式
    	.addClass('progress-bar progress-bar-success')
}

jQuery 高级用法

jQuery 实现文件上传

定义 UI 结构

<!-- 导入 jQuery -->
<script src="./jquery.js"></script>
<!-- 文件选择框 -->
<input type = "file" id = "file1" />
<!-- 上传文件按钮 -->
<button id = "btnUpload">上传</button>

验证是否选择了文件

$('#btnUpload').on('click',function(){
    // 1. 将 jQuery 对象转化为 DOM 对象,并获取选中的文件列表
    var files = $('#file1')[0].files
    // 2. 判断是否选择了文件
    if(files.length <= 0){
        return alert('请选择图片后再上传!')
    }
})

向 FormData 中追加文件

// 向 FormData 中追加文件
var fd = new FormData()
fd.append('avatar',files[0])

使用 jQuery 发起上传文件的请求

$.ajax({
    method:'POST',
    url:'http://www.liulongbin.top:3006/api/upload/avatar',
    data:fd,
    // 不修改 Content-Type 属性,使用 FormData 默认的 Content-Type 值
    contentType:false,
    // 不对 FormData 中的数据进行 url 编码,而是将 FormData 数据原样发送到服务器
    processData:fales,
    success:function(res){
        console.log(res)
    }
})

jQuery 实现 loading 效果

ajaxStart(callback)

Ajax 请求开始时,执行ajaxStart 函数。可以在 ajaxStart 的 callback 中显示 loading 效果,示例:

//自 jQuery 版本 1.8 起,该方法只能被附加到文档
$(document).ajaxStart(function(){
    $('#loading').show()
})

注意$(document).ajaxStart() 函数会监听当前文档内所有的 Ajax 请求

ajaxStop(callback)

Ajax 请求结束时,执行 ajaxStop 函数。可以在 ajaxStop 的 callback 中隐藏 loading 效果,示例:

//自 jQuery 版本 1.8 起,该方法只能被附加到文档
$(document).ajaxStop(function(){
    $('#loading').hide()
})

axios

什么是 axios

Axios 是专注于网络数据请求的库。

相比于原生的 XMLHttpRequest 对象,axios 简单易用

相比于 jQuery,axios 更加轻量化,只专注于网络数据请求。

axios 发起 GET 请求

语法:

axios.get('url',{params:{ /*参数*/ }}).then(callback)

具体的请求示例如下:

// 请求的 URL 地址
var url = 'http://www.liulongbin.top:3006/api/get'
// 请求的参数对象
var paramsObj = { name: 'zs', age: 20}
// 调用 axios.get() 发起 GET 请求
axios.get(url,{ params: paramsObj }).then(function(res){
    // res.data 是服务器返回的数据
    var result = res.data
    console.log(result)
})

axios 发起 POST 请求

axios 发起 post 请求的语法:

axios.post('url',{ /*参数*/ }).then(callback)

具体的请求示例如下:

// 请求的 URL 地址
var url = 'http://www.liulongbin.top:3006/api/post'
// 要提交到服务器的数据
var dataObj = { name: 'zs', age: 20}
// 调用 axios.post() 发起 POST 请求
axios.get(url, dataObj).then(function(res){
    // res.data 是服务器返回的数据
    var result = res.data
    console.log(result)
})

直接使用 axios 发起请求

直接使用 axios 发起 GET 请求

axios({
    method: 'GET',
    url: 'http://www.liulongbin.top:3006/api/get',
    params: {// GET 参数要通过 params 属性提供
    	name: 'zs',
        age: 20
    }
}).then(function(res){
    console.log(res.data)
})

直接使用 axios 发起 POST 请求

axios({
    method: 'POST',
    url: 'http://www.liulongbin.top:3006/api/post',
    data: {// POST 参数要通过 data 属性提供
    	name: 'zs',
        age: 20
    }
}).then(function(res){
    console.log(res.data)
})
posted @ 2022-03-10 18:33  shumild  阅读(62)  评论(0)    收藏  举报