深入理解 Ajax,利用原生 JS 实现
Ajax 基本知识点
- AJAX 全称为 Asynchronous JavaScript and XML(异步 JavaScript 和 XML),是一种创建交互式网页应用的网页开发技术
- Ajax 最核心的依赖就是浏览器提供的 XMLHttpRequest 对象
- Ajax 原理是通过 XMLHttpRequest 对象向服务器发出异步请求,从服务器获取数据,然后用 JavaScript 来操作 DOM 实现页面的局部刷新
XMLHttpRequest 常见的属性
- onreadystatechange 每次状态改变时触发的事件
- responseText 从服务器接受到的响应体(不包含头部),或者如果还没接受到数据的话,就是空字符串
- responseXML 对请求的响应,解析为 XML 并作为 Document 对象返回
- state 从服务器返回的数字代码,比如常见的 404(找不到)、 200(请求成功)500(服务器在执行请求时报错)
- readyState HTTP 请求的状态,当一个 XMLHttpRequest 初次创建时,这个属性值从 0 开始,直到接收完整的 HTTP 响应,值增加到 4
- 0(未初始化) 对象已建立,但是尚未初始化(尚未调用 open 方法)
- 1(初始化) 对象已建立,open 方法已调用,尚未调用 send 方法
- 2(发送数据) send 方法已调用,但是当前的状态及 http 请求头未知
- 3(数据传送中) 已接受部分数据,因为响应及 http 请求头不全,这时通过 responseBody 和 responseText 获取部分数据会出现错误
- 4(完成) 数据接收完毕,此时可以通过 responseXml 和 responseText 获取完整的响应数据
Ajax 实现步骤
1. 创建 XMLHttpRequest 对象,也就是创建一个异步调用对象
let xmlHttp
// 考虑兼容 IE5、6 浏览器
if (window.XMLHttpRequest) {
xmlHttp = new XMLHttpRequest()
} else {
xmlHttp = new ActiveXObject('Microsoft.XMLHTTP')
}
2. 创建一个新的 HTTP 请求,指定该请求的方法、URL、验证信息
// 语法: XMLHttpRequest.open(method, URL, flag, name, password)
// method: HTTP 请求方式,有 get post head put delete
// URL: HTTP 请求的 URL 地址
// flag: 可选参数,参数值为布尔值,true 表示异步请求,false 表示同步请求,默认为 true
// name: 该参数为可选参数,用于输入用户名。如果服务器需要验证,则必须使用该参数。
// password: 该参数为可选参数,用于输入密码。如果服务器需要验证,则必须使用该参数。
xmlHttp.open('GET', 'https://blog.csdn.net/qq_43778110/article/details/102507852', true)
// GET 请求参数需要拼接在 URL 后面
xmlHttp.open('GET', '/list?page=5', true)
xmlHttp.send()
// POST 请求数据是放在 send 里面
xmlHttp.open('POST', '/list', true)
xmlHttp.send('page=5&pageSize=10')
3. 设置响应 HTTP 请求状态变化的函数
xmlHttp.onreadystatechange = () => {
// 判断XMLHttpRequest对象的readyState属性值是否为4,如果为4表示异步调用完成
if (xmlHttp.readyState === 4) {
// 设置获取数据的语句 xmlHttp.status === 200 说明服务器成功响应返回的结果
if (xmlHttp.status === 200) {
// 返回结果以字符串的形式输出
document.write(xmlHttp.responseText)
// 返回结果以 XML 形式输出
document.write(xmlHttp.responseXML)
}
}
}
4. 发送 HTTP 请求
// 语法: XMLHttpRequest.send(data)
// 其中 data 是个可选参数,如果是 get 请求的数据写在 URL 中,那这里可以使用 null 来代替;如果是 post 请求,data 参数的格式与在 URL 中传递参数的格式类似
XMLHttpRequest.send('name=myName&value=myValue')
// 防止乱码: 服务器端设置 request.setCharacterEncoding('utf-8')
// post 请求需要额外设置请求头:
XMLHttpRequest.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded')
// 请求发送后, send()会把 readyState 设置为 2,并触发 onreadystatechange 事件。
// 当所有的 HTTP 响应头部已经接收,send() 或后台线程把 readyState 设置为 3 并触发 onreadystatechange 事件。
// 当响应完成,send() 或后台线程把 readyState 设置为 4,并最后一次触发事件。
// 只有在使用了 send() 方法后。XMLHttpRequest 对象的 readyState 属性值才会开始变化,onreadystatechange 监听到 readyState 变化后才会执行
5. 获取异步调用的数据
if (xmlHttp.status === 200) {
// 返回结果以字符串的形式输出
document.write(xmlHttp.responseText)
// 返回结果以 XML 形式输出
dcoument.write(xmlHttp.responseXML)
}
6. 利用 JavaScript 和 DOM 实现页面局部更新
原生 JS 实现 Ajax 的封装
function myAjax (obj) {
// get 方式传入时,将 data 内容进行拼接
function splicStr (data) {
let str = ''
for (let i in data) {
str = i + '=' + data[i]
}
return str
}
// 1. 创建 XMLHttpRequest 对象(注意浏览器兼容性)
let xmlHttp
if (window.XMLHttpRequest) {
xmlHttp = new XMLHttpRequest()
} else {
xmlHttp = new ActiveXObject('Microsoft.XMLHTTP') // 兼容 IE 5、6
}
// 2. 初始化 HTTP 请求参数,只初始化并不会发送
if (obj.method.toUpperCase() === 'GET') {
// get 请求
xmlHttp.open(obj.method.toUpperCase(), obj.url + '?' + splicStr(obj.data), typeof obj.async === 'boolean' ? obj.async ? true) // 路径拼接传参数
// 3. 发送此次请求
xmlHttp.send(null)
} else if (obj.method.toUpperCase() === 'POST') {
// post 请求
xmlHttp.open(obj.method.toUpperCase(), obj.url, typeof obj.async === 'boolean' ? obj.async : true)
// 表单提交,需要设置请求头
xmlHttp.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded')
// 3. 发送此次请求
xmlHttp.send(obj.data) // post 请求传参
}
// 4. 利用 onreadystatechange 监听 readyState 的变化
xmlHttp.onreadystatechange = () => {
if (xmlHttp.readyState === 4 && xmlHttp.status === 200 {
// success 回调
success(xmlHttp.responseText)
} else if (xmlHttp.readyState === 4 && xmlHttp.status !== 200) {
// fail 回调
fail()
}
}
}
// 调用 myAjax 函数
myAjax({
url: '服务器接口地址',
method: '请求方式',
async: true // 异步请求
data: {
username: 'xiaoyi',
password: '1226'
},
success (res) {
console.log(res)
},
fail () {
console.log('服务器请求失败')
}
})
原型构造函数实现 Ajax
function MyAjax (obj) {
this.xmlHttp = null
this.method = obj.method || 'get'
this.url = obj.url
this.async = typeof obj.async === 'boolean' ? obj.async : true
this.data = obj.data
this.success = obj.success
this.fail = obj.fail
// 初始话创建 XMLHttpRequest 对象
this.init()
}
myAjax.prototype = {
init () {
if (window.XMLHttpRequest) {
this.xmlHttp = new XMLHttpRequest()
} else {
this.xmlHttp = new ActiveXObject('Microsoft.XMLHTTP')
}
this.openReq()
this.watchReq()
},
openReq () {
if (this.method.toUpperCase() === 'GET') {
this.xmlHttp.open(this.method.toUpperCase(), this.url + '?' + this.splicStr(this.data), this.async)
this.xmlHttp.send(null)
} else if (this.method.toUpperCase() === 'POST') {
this.xmlHttp.open(this.method, this.url, this.async)
this.xmlHttp.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded')
this.xmlHttp.send(this.data)
}
},
watchReq () {
this.xmlHttp.onreadystatechange = () => {
if (this.xmlHttp.readyState === 4 && this.xmlHttp.status === 200) {
// success 回调
this.success(this.xmlHttp.responseText)
} else if (this.xmlHttp.readyState === 4 && this.xmlHttp.status !== 200) {
// fail 回调
this.fail()
}
}
},
splicStr (data) {
let str = ''
for (let i in data) {
str = i + '=' + data[i]
}
return str
}
}
new MyAjax({
url: 'https://blog.csdn.net/qq_43778110/article/details/102507852'
method: 'get',
data: {
userName: 'huibao',
password: '1217'
},
async: true,
success (res) {
console.log(res)
},
fail () {
console.log('服务器请求失败')
}
})