AJAX 「 ※ Learning ※ 」
编辑简介
AJAX 全称为 Asynchronous JavaScript And XML,就是异步的 JS 和 XML。
通过 AJAX 可以在浏览器中向服务器发送异步请求,最大的优势:无刷新获取数据。
AJAX 不是新的编程语言,而是一种将现有的标准组合在一起使用的新方式。
【原生】AJAX请求
准备工作
1、前往 Node.js 官方网站 并下载适合你操作系统的 Node.js 安装程序。
2、前往并下载 Express 框架。
安装Node.js
node -v //检查Node.js版本
npm -v // 检查Npm包版本
npm install -g npm // 更细Npm
安装Express
npm init --yes
npm i express //mac用户前置sudo命令
HTTP协议请求
HTTP(hypertext transport protocol)协议『超文本传输协议』,协议详细规定了浏览器和万维网服务器之间互相通信的规则。
请求报文
响应报文
状态码
Express规则
// 引入express
const express = require('express');
// 创建应用对象
const app = express();
// 创建路由规则
// request是对请求报文的封装
// response是对响应报文的封装
app.get('/server',(request,response)=>{
// 设置响应头,设置允许跨域
response.setHeader('Access-Control-Allow-Origin','*')
// 设置响应体
response.send('Hello AJAX!')
})
app.post('/server', (request, response) => {
// 设置响应头,设置允许跨域
response.setHeader('Access-Control-Allow-Origin', '*')
// 设置响应体
response.send('Hello AJAX!')
})
// 监听端口,启动服务
app.listen(8000, ()=>{
console.log('服务器已启动,8000端口监听中...')
})
AJAX基本操作
<button>点我发送请求</button>
<div id="result" class="w-48 h-48 border solid black"></div>
<script>
const btn = document.getElementsByTagName('button')[0];
const result = document.getElementById('result');
btn.onclick = function() {
// 1. 创建对象
const xhr = new XMLHttpRequest();
// 2. 初始化 设置请求方法和url
xhr.open('GET','http://127.0.0.1:8000/server');
// 3. 发送
xhr.send();
// 4. 事件绑定 处理服务端返回的结果
// on when 当....时候
// readystate 是xhr对象中的属性,表示状态 0-4
// 0:xhr对象创建完成
// 1:open方法调用完成
// 2:send方法调用完成
// 3:服务端返回部分结果
// 4:服务端返回所有结果,可以在该阶段获取返回结果
// change 改变
xhr.onreadystatechange = function() {
// 判断服务端返回所有结果
if (xhr.readyState === 4) {
// 判断响应状态码 200 404 403 401 500
// 2xx 都为成功
if (xhr.status >= 200 && xhr.status < 300) {
// 处理结果 行 头 空行 体
// 1. 响应行
// console.log(xhr.status); // 状态码
// console.log(xhr.statusText); // 状态字符串
// console.log(xhr.getAllResponseHeaders()); // 所有响应头
// console.log(xhr.response); // 响应体
// 设置result的文本
result.innerText = xhr.response;
}
}
}
}
</script>
POST请求设置
/* 当鼠标移入#result,则发送Post请求... */
<div id="result" class="w-48 h-48 border solid black"></div>
<script>
const result = document.getElementById('result');
result.addEventListener('mouseover', function () {
//1.创建对象
const xhr = new XMLHttpRequest();
//2.初始化
xhr.open('POST', 'http://127.0.0.1:8000/server');
xhr.setRequestHeader('Content-Type','application/x-www-form-urlencoded'); // 设置请求头信息(预定义)
xhr.setRequestHeader('name','parlo'); //可以设置自定义请求头
//3.发送
xhr.send('a=100&b=200'); //请求体也可以为'number';'a:100&b:100..'
//4.事件绑定
xhr.onreadystatechange = function () {
if (xhr.readyState === 4) {
if (xhr.status >= 200 && xhr.status < 300) {
result.innerText = xhr.response;
}
}
}
});
</script>
当设定为自定义的请求头时,则需要在后端添加新的请求类型(一般不需要前端去操作)
// server.js
// 可以接受任意类型的请求
app.all('/server', (request, response) => {
// 设置响应头,设置允许跨域
response.setHeader('Access-Control-Allow-Origin', '*')
response.setHeader('Access-Control-Allow-Headers', '*')
// 设置响应体
response.send('Hello AJAX!')
})
服务端响应JSON数据
// server.js
// 可以接受任意类型的请求
app.all('/json-server', (request, response) => {
// 设置响应头,设置允许跨域
response.setHeader('Access-Control-Allow-Origin', '*')
response.setHeader('Access-Control-Allow-Headers', '*')
// 响应一个数据
const data = {
name: 'parlo',
}
// 对象转换为字符串
let str = JSON.stringify(data)
// 设置响应体
response.send(str)
})
/* 当键盘在浏览器视口按下,则发送请求 */
<div id="result" class="w-48 h-48 border solid black"></div>
手动转换数据
<script>
//当键盘在浏览器视口下,按下键盘则发送POST请求
const result = document.getElementById('result')
window.onkeydown = function () {
// 发送请求
const xhr = new XMLHttpRequest();
// 初始化
xhr.open('get', 'http://127.0.0.1:8000/json-server');
// 发送
xhr.send();
// 事件绑定
xhr.onreadystatechange = function () {
if (xhr.readyState === 4) {
if (xhr.status >= 200 && xhr.status < 300) {
// 手动处理服务器返回的结果
let data = JSON.parse(xhr.response)
console.log(data)
result.innerText = data.name
}
}
}
}
</script>
自动转换数据
<script>
//当键盘在浏览器视口下,按下键盘则发送POST请求
const result = document.getElementById('result')
window.onkeydown = function () {
// 发送请求
const xhr = new XMLHttpRequest();
// 设置响应体类型
xhr.responseType = 'json'
// 初始化
xhr.open('get', 'http://127.0.0.1:8000/json-server');
// 发送
xhr.send();
// 事件绑定
xhr.onreadystatechange = function () {
if (xhr.readyState === 4) {
if (xhr.status >= 200 && xhr.status < 300) {
// 自动处理服务器返回的结果
console.log(xhr.response)
result.innerText = xhr.response.name
}
}
}
}
</script>
Nodemon工具
安装Nodemon
npm install -g nodemon
运行服务端
nodemon server.js
IE缓存问题解决
解决全世界最好用的IE浏览器的缓存解决问题!需要注意的是,现代浏览器几乎不需要调整。
<button>点我发送请求</button>
<div id="result" class="w-48 h-48 border solid black"></div>
// server.js
app.get('/ie', (request, response) => {
// 设置响应头,设置允许跨域
response.setHeader('Access-Control-Allow-Origin', '*');
// 设置响应体
response.send('HELLO IE! 2~~~');
});
<script>
const btn = document.getElementsByTagName('button')[0];
const result = document.getElementById('result');
btn.addEventListener('click', () => {
const xhr = new XMLHttpRequest();
// 初始化
xhr.open('GET', 'http://localhost:8000/ie?t=' + Date.now()); //为IE浏览器添加参数 + 时间戳
// 发送
xhr.send();
// 绑定事件
xhr.onreadystatechange = () => {
if (xhr.readyState === 4) {
if (xhr.status >= 200 && xhr.status < 300) {
result.innerText = xhr.response;
}
}
};
});
</script>
超时与网络异常
增加友好的判定来告知AJAX请求的网络情况。
<button>点我发送请求</button>
<div id="result" class="w-48 h-48 border solid black"></div>
// server.js
app.get('/delay', (request, response) => {
// 设置响应头,设置允许跨域
response.setHeader('Access-Control-Allow-Origin', '*');
// 设置响应体
setTimeout(() => {
response.send('延时响应');
}, 3000);
});
<script>
const btn = document.getElementsByTagName('button')[0];
const result = document.getElementById('result');
btn.addEventListener('click', () => {
// 创建对象
const xhr = new XMLHttpRequest();
// 设置超时时间
xhr.timeout = 2000;
// 设置超时回调
xhr.ontimeout = function () {
alert('网络超时,请稍后重试!');
};
// 设置网络异常回调
xhr.onerror = function () {
alert('网络异常,请稍后重试!');
};
// 初始化
xhr.open('GET', 'http://localhost:8000/delay');
// 发送
xhr.send();
// 事件绑定
xhr.onreadystatechange = () => {
if (xhr.readyState === 4) {
if (xhr.status >= 200 && xhr.status < 300) {
result.innerText = xhr.response;
}
}
};
});
</script>
取消请求
取消正在发送的AJAX请求。
<button>点击发送请求</button>
<button>点击取消请求</button>
<script>
const btn = document.querySelectorAll('button');
let xhr = null; // 作用域需放在外层
btn[0].onclick = function () {
xhr = new XMLHttpRequest();
xhr.open('GET', 'http://localhost:8000/delay');
xhr.send();
};
btn[1].onclick = function () {
xhr.abort(); //取消请求
};
</script>
重复请求问题
当多次发送AJAX请求时,取消之前的请求。这样可以减少服务器的性能冲突。
<script>
const btn = document.querySelectorAll('button');
let xhr = null;
//标识变量
let isSending = false; // 是否正在发送AJAX请求
btn[0].onclick = function () {
if (isSending) xhr.abort();//判断!如果正在发送,则取消本次发送
xhr = new XMLHttpRequest();
//修改 标识变量的值
isSending = true;
xhr.open('GET', 'http://localhost:8000/delay');
xhr.send();
xhr.onreadystatechange = function () {
if (xhr.readyState === 4) {
//修改表示变量
isSending = false;
}
};
};
btn[1].onclick = function () {
xhr.abort(); // 取消请求
};
</script>
jQuery方法
<button>GET请求</button>
<button>POST请求</button>
<button>通用AJAX请求</button>
// jquery
app.all('/jquery-server', (request, response) => {
// 设置响应头,设置允许跨域
response.setHeader('Access-Control-Allow-Origin', '*');
// 设置响应体
//response.send('HELLO jquery AJAX');
const data = {name:'parlo'};
response.send(JSON.stringify(data));
});
GET请求
<script>
$('button').eq(0).click(function () {
$.get('http://127.0.0.1:8000/jquery-server', {name: 'parlor', age: 18}, function (data) {
console.log(data);
}, 'json');
});
</script>
POST请求
<script>
$('button').eq(1).click(function () {
$.post('http://127.0.0.1:8000/jquery-server', {name: 'parlor', age: 18}, function (data) {
console.log(data);
}, 'json');
});
</script>
通用方法
$('button').eq(2).click(function () {
$.ajax({
// url
url: 'http://127.0.0.1:8000/jquery-server',
// 参数
data: {name: 'parlo', age: 18},
// 请求类型
type: 'GET',
// 响应体结果
dataType: 'json',
// 成功的回调
success: function (data) {
console.log(data);
},
// 超时时间
timeout: 2000,
// 失败的回调
error: function () {
console.log('出错了');
},
headers: {
a: 300,
b: 400
}
});
});
Axiso方法
基本语法
axuis({ url:`目标资源地址` }).then(result=>{ //对服务器是返回的数据做后续处理 })
参数查询
axuis({ url:`目标资源地址` params:{ 参数名:值 } }).then((result)=>{ //对服务器是返回的数据做后续处理 })
<p></p>
<script>
axios({
url: 'https://hmajax.itheima.net/api/city',
params: {
pname: '山东省'
}
}).then(result => {
console.log(result.data.list);
document.querySelector('p').innerHTML = result.data.list.join('<br>');
});
</script>
<form>
<label>省份名字
<input name="province" placeholder="请输入省份名字" type="text" value="北京">
</label>
<label>城市名字
<input name="city" placeholder="请输入城市名字" type="text" value="北京市">
</label>
</form>
<button type="button">查询</button>
<p>地区列表</p>
<ul>
<li></li>
</ul>
<script>
<!--创建绑定事件-->
document.querySelector('button').addEventListener('click', function () {
// 获取用户输入的省份值
let pname = document.querySelectorAll('input')[0].value;
let cname = document.querySelectorAll('input')[1].value;
console.log(pname, cname);
// 使用axios发送请求
axios({
url: 'https://hmajax.itheima.net/api/area',
params: {
pname,
cname
}
}).then(result => {
// 打印并检查数据
console.log(result.data.list);
let list = result.data.list;
// ele.map()方法是根据当前数组生成一个新数组
let theLi = list.map(ele => `<li>${ele}</li>`).join('');
console.log(theLi);
// 将生成的li标签添加到ul中
document.querySelector('ul').innerHTML = theLi;
});
});
</script>
请求配置
axuis({ url:`目标资源地址`, method:'请求方法', data:{ 参数名:值 } params:{ 参数名:值 } }).then(result=>{ //对服务器是返回的数据做后续处理 })
错误处理
axuis({ //请求选项 }).then(result=>{ //处理数据 }).catch(error=>{ //处理错误 })
<button id="btn">点击注册用户</button>
<script>
document.getElementById('btn').addEventListener('click', () => {
axios({
url: 'https://hmajax.itheima.net/api/register',
method: 'post',
data: {
username: 'parlo0532',
password: '12345678'
}
}).then(result => {
console.log(result);
}).catch(error => {
console.log(error);
alert(error.response.data.message);
});
});
</script>
Form-serialize(插件)
引入插件 Form-serialize
<script src="path/to/form-serialize.js"></script>
使用serialize函数快速手机表单元素的值
<script>
document.querySelector('.btn').addEventListener('click',(){
const form = document.querySelector('.example-form')
/*
hash:设置获取对象的结构
- true:JS对象(推介)一般请求体里提交给服务器
- false:查询字符串
empty:设置是否获取空值
- true:获取空值(推介)一般请求体里提交给服务器
- false:不获取空值
*/
const data = serialize(form,{hash:true,empty:true})
console.log(data)
})
</script>
案例一:登录表单
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta content="IE=edge" http-equiv="X-UA-Compatible">
<meta content="width=device-width, initial-scale=1.0" name="viewport">
<title>案例_登录</title>
<!-- 引入bootstrap.css -->
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.2/dist/css/bootstrap.min.css" rel="stylesheet">
<!-- 公共 -->
<style>
html,
body {
background-color: #EDF0F5;
width: 100%;
height: 100%;
display: flex;
justify-content: center;
align-items: center;
}
.container {
width: 520px;
height: 540px;
background-color: #fff;
padding: 60px;
box-sizing: border-box;
}
.container h3 {
font-weight: 900;
}
</style>
<!-- 表单容器和内容 -->
<style>
.form_wrap {
color: #8B929D !important;
}
.form-text {
color: #8B929D !important;
}
</style>
<!-- 提示框样式 -->
<style>
.alert {
transition: .5s;
opacity: 0;
}
.alert.show {
opacity: 1;
}
</style>
<script src="../node_modules/axios/dist/axios.js"></script>
<script src="form-serialize.js"></script>
</head>
<body>
<div class="container">
<h3>欢迎-登录</h3>
<!-- 登录结果-提示框 -->
<div class="alert alert-success" role="alert">
提示消息
</div>
<!-- 表单 -->
<div class="form_wrap">
<form class="login-form">
<div class="mb-3">
<label class="form-label" for="username">账号名</label>
<input autocomplete="current-username" class="form-control username" name="username"
type="text">
</div>
<div class="mb-3">
<label class="form-label" for="password">密码</label>
<input autocomplete="current-password" class="form-control password" name="password"
type="password">
</div>
<button class="btn btn-primary btn-login" type="button"> 登 录</button>
</form>
</div>
</div>
<script>
//目标2:将错误或登录信息放在前端显示
const message = document.querySelector('.alert')
function alertFn(msg, isSuccess) {
//显示提示框
message.classList.add('show')
//放入提示消息
message.innerText = msg
//设置样式
const className = isSuccess ? 'alert-success' : 'alert-danger'
message.classList.add(className)
//过两秒隐藏
setTimeout(() => {
message.classList.remove('show')
message.classList.remove(className)
}, 2000)
}
// 目标1:点击登录时,用户名和密码长度判断,并提交数据和服务器通信
document.querySelector('.btn-login').addEventListener('click', () => {
// 使用serialize函数收集表单里用户名和密码
const form = document.querySelector('.login-form')
const data = serialize(form, {hash: true, empty: true})
console.log(data);
const {username, password} = data;
console.log(username, password)
// const username = document.querySelector('.username').value
// const password = document.querySelector('.password').value
if (username.length < 6) {
console.log('用户名长度不能小于6位');
alertFn('用户名长度不能小于6位', false)
return
}
if (password.length < 8) {
console.log('密码长度不能小于8位')
alertFn('密码长度不能小于8位', false)
return
}
axios({
url: 'https://hmajax.itheima.net/api/login',
method: 'post',
data: {
username,
password,
},
}).then(result => {
console.log(result);
console.log(result.data.message);
alertFn(result.data.message, true)
}).catch(error => {
console.log(error);
console.log(error.response.data.message);
alertFn(error.response.data.message, false)
});
});
</script>
</body>
</html>
案例二:图书管理
>01使用属性控制弹窗
<!-- 使用属性控制弹窗显示
1、引入bootstrap.css和bootstrap.js
2、准备弹窗标签,确认结构
3、通过自定义属性,控制弹窗的显示和隐藏
data-bs-toggle="modal" 用于触发模态框(Modal)的显示。
data-bs-target="#myModal" 查找具有相应NAME模态框,并显示或操作该模态框。
data-bs-dismiss="modal" 关闭对应的模态框
-->
<button class="btn btn-primary" data-bs-target=".my-modal" data-bs-toggle="modal" type="button">显示弹窗
</button>
<div class="modal my-modal" tabindex="-1">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Modal title</h5>
<button aria-label="Close" class="btn-close" data-bs-dismiss="modal" type="button"></button>
</div>
<div class="modal-body">
<p>Modal body text goes here.</p>
</div>
<div class="modal-footer">
<button class="btn btn-secondary" data-bs-dismiss="modal" type="button">Close</button>
<button class="btn btn-primary" type="button">Save changes</button>
</div>
</div>
</div>
</div>
>02使用JS控制弹窗
<!--
目标:使用JS控制弹窗,显示和隐藏
1. 创建弹窗对象
const modaDom = document.querySelector('.modal')
const modal = new bootstrap.Modal(modaDom)
2. 调用弹窗对象内置方法
.show() 显示弹窗
.hide() 隐藏弹窗
-->
<button class="btn btn-primary edit-btn" type="button">
编辑姓名
</button>
<div class="modal name-box" tabindex="-1">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">请输入姓名</h5>
<button aria-label="Close" class="btn-close" data-bs-dismiss="modal" type="button"></button>
</div>
<div class="modal-body">
<form action="">
<span>姓名:</span>
<input class="username" type="text">
</form>
</div>
<div class="modal-footer">
<button class="btn btn-secondary" data-bs-dismiss="modal" type="button">取消</button>
<button class="btn btn-primary save-btn" type="button">保存</button>
</div>
</div>
</div>
</div>
<!-- 引入bootstrap.js -->
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.2.2/dist/js/bootstrap.min.js"></script>
<script>
// 1. 创建弹窗对象
const modaDom = document.querySelector('.name-box')
const modal = new bootstrap.Modal(modaDom)
// 编辑姓名->点击->弹窗显示
document.querySelector('.edit-btn').addEventListener('click', () => {
document.querySelector('.username').value = '张三'
modal.show()
})
// 保存按钮->点击->获取姓名打印->弹窗隐藏
document.querySelector('.save-btn').addEventListener('click', () => {
const username = document.querySelector('.username').value
console.log('模拟把姓名保存到服务器上', username)
modal.hide()
})
</script>
GET请求
<button>GET</button>
<button>POST</button>
<button>AJAX</button>
<script>
const btns = document.querySelectorAll('button');
// 配置baseURL
axios.defaults.baseURL = 'http://127.0.0.1:8000';
btns[0].onclick = function () {
//GET请求
axios.get('/axios-server', {
// url参数
params: {
id: 123,
name: 'Tom'
},
// 请求头信息
headers: {
name: 'parlo',
age: 31
}
}).then(value => {
console.log(value);
});
};
</script>
POST请求
<script>
const btns = document.querySelectorAll('button');
// 配置baseURL
axios.defaults.baseURL = 'http://127.0.0.1:8000';
btns[1].onclick = function () {
//POST请求
axios.post('/axios-server', {
username: 'admin',
password: '123456'
}, {
// url
params: {
id: 123,
name: 'Tom'
},
// 请求头参数
headers: {
name: 'parlo',
age: 31
}
});
};
</script>
函数请求
<script>
const btns = document.querySelectorAll('button');
// 配置baseURL
axios.defaults.baseURL = 'http://127.0.0.1:8000';
btns[2].onclick = function () {
axios({
// 请求方法
method: 'POST',
// url
url: '/axios-server',
// url参数
params: {
id: 123,
name: 'Tom'
},
// 头信息
headers: {
name: 'parlo',
age: 31
},
// 请求体参数
data: {
username: 'admin',
password: '123456'
}
}).then(response => {
console.log(response);
//响应状态码
console.log(response.status);
// 响应状态字符串
console.log(response.statusText);
// 响应头信息
console.log(response.headers);
// 响应体
console.log(response.data);
});
};
</script>
Fetch函数
<button>AJAX</button>
<script>
const btn = document.querySelector('button');
btn.onclick = function () {
fetch('http://127.0.0.1:8000/fetch-server?parlo=31', {
//请求方法
method: 'POST',
//请求头
headers: {
name: 'parlo'
},
//请求体
body: 'username=admin&password=123456'
}).then(response => {
return response.json();
}).then(response => {
console.log(response);
});
};
</script>
跨域
同源策略
同源策略(Same-Origin Policy)最早由 Netscape 公司提出,是浏览器的一种安全策略。
同源: 协议、域名、端口号 必须完全相同。
而违背同源策略就是跨域。
JSONP
JSONP(JSON with Padding),是一个非官方的跨域解决方案,纯粹凭借程序员的聪明
才智开发出来,只支持 get 请求。
用户名:<input id="username" type="text"/>
<p></p>
// 用户名检测是否存在
app.all('/check-username', (request, response) => {
const data = {
exist: 1,
msg: '用户名已经存在'
};
let str = JSON.stringify(data);
response.send(`handle(${str})`);
});
<script>
//获取input元素
const input = document.querySelector('input');
const p = document.querySelector('p');
// 声明handle函数
function handle(data) {
input.style.border = '1px solid red';
//修改p标签的提示文本
p.innerHTML = data.msg;
}
//绑定事件
input.onblur = function () {
//获取用户输入的值
let username = this.value;
//向服务器发送请求 检测用户名是否存在
//1、创建script标签
const script = document.createElement('script');
//2、设置script标签的src属性
script.src = 'http://127.0.0.1:8000/check-username';
//3、将script标签添加到页面中
document.body.appendChild(script);
};
</script>
jQuery发送JSONP
app.all('/jquery-jsonp-server', (request, response) => {
// response.send('HELLO IE! 2~~~');
const data = {
name: '中国',
city: ['北京', '上海', '青岛']
};
let str = JSON.stringify(data);
// 接受callback参数
let cb = request.query.callback;
// 拼接数据
response.send(`${cb}(${str})`);
});
<button>点击发送jsonp请求</button>
<div id="result"></div>
<script>
$('button').eq(0).click(function () {
$.getJSON('http://127.0.0.1:8000/jquery-jsonp-server?callback=?', function (data) {
// console.log(data);
$('#result').html(
`
名称:${data.name}<br>
城市: ${data.city}
`
);
});
});
</script>
CORS
CORS(Cross-Origin Resource Sharing),跨域资源共享。
CORS 是官方的跨域解决方案,它的特点是不需要在客户端做任何特殊的操作,完全在服务器中进行处理,支持 get 和 post 请求。跨域资源共享标准新增了一组 HTTP 首部字段,允许服务器声明哪些 源站通过浏览器有权限访问哪些资源。
<button>点击发送jsonp请求</button>
<div id="result"></div>
javas//cors
app.all('/cors-server', (request, response) => {
//设置响应头
response.setHeader('Access-Control-Allow-Origin', '*');
response.setHeader('Access-Control-Allow-Headers', '*');
response.setHeader('Access-Control-Allow-Method', '*');
response.send('hello cors');
});
<script>
const btn = document.querySelector('button');
btn.onclick = function () {
//1. 创建对象
const xhr = new XMLHttpRequest();
//2. 设置请求方法和url
xhr.open('GET', 'http://127.0.0.1:8000/cors-server');
//3. 发送
xhr.send();
//4. 监听事件
xhr.onreadystatechange = function () {
if (xhr.readyState === 4) {
if (xhr.status >= 200 && xhr.status < 300) {
console.log(xhr.response);
}
}
};
};
</script>
- 3
- 0
-
分享