Ajax
1.同步与异步
以前端请求,后端响应为例
- 同步:前端请求发送,必须等到后端响应完成,才允许发送另一个请求
- 异步:前端发请求后不等待后端响应结果继续执行,后端响应完成通过事件通知前端处理
异步最常用的处理形式就是回调函数
2. XMLHttpRequest 对象
XMLHttpRequest
是浏览器提供的,处理异步请求的宿主对象,而非 Js 内置对象- 基本流程:
- 1.创建请求对象:
new XMLHttpRequest()
- 2.监听请求回调:
onreadystatechange
- 3.初始化请求参数:
open(请求类型,请求地址,是否异步)
- 4.发送请求:
send()
- 1.创建请求对象:
// 1. 创建ajax对象
var xhr = new XMLHttpRequest();
// 2.监听请求
xhr.onreadystatechange = function () {
if (xhr.readyState === 4 && xhr.status === 200) {
// 控制台输出返回的数据
console.log(xhr.responseText); //输出 {"name":"peter","age":23}
}
};
// 3.初始化请求参数
xhr.open("GET", "test1.php?action=demo1", true);
// 4.发送请求
xhr.send(null);
php 部分
case 'demo1':
// 创建数组
$user['name'] = 'peter';
$user['age'] = 23;
// JSON 编码返回
echo json_encode($user);
break;
- 如果是 post 请求,步骤略有不同
- 1.创建请求对象
new XMLHttpRequest()
- 2.监听请求回调
onreadystatechange
- 3.初始化请求参数
open(请求类型,请求地址,是否异步)
- 4.设置请求头
setRequestHeader()
- 5.准备请求参数(可选)
var data = ...
- 6.发送请求
send(data)
- 1.创建请求对象
// 创建对象
var xhr = new XMLHttpRequest();
// 监听请求
xhr.onreadystatechange = function () {
if (xhr.readyState === 4 && xhr.status === 200) {
console.log(xhr.responseText);
// 返回值 Array
// (
// [name] => peter
// [age] => 56
// )
}
};
// 初始化请求参数
xhr.open("POST", "test1.php?action=demo2", true);
// 设置请求头
xhr.setRequestHeader("content-type", "application/x-www-form-urlencoded");
// 创建对象
var user = {
name: "peter",
age: "56",
};
// 转JSON
var data = JSON.stringify(user);
// 发送请求
xhr.send(data);
php 部分
- 方法 1
case 'demo2':
print_r($_POST);
// 这里输出的是 Array
// (
// [{"name":"peter","age":"56"}] =>
// )
// 所以要获取一下键
$data = key($_POST);
$user = json_decode($data,true);
print_r($user);
break;
- 方法 2
case 'demo3':
$data = file_get_contents('php://input');
$user = json_decode($data,true);
print_r($user);
break;
3. GET 请求
- 服务器:返回
JSON
- 前端:
JSON.parse()
解析 JSON 字符串
4. POST 请求
- 前端:发送
JSON
- 后端:
- JSON 数据以表单数据类型发送,可
$_POST
接收 - JSON 数组就是以 JSON 发送,
php://input
流文件方式接收
- JSON 数据以表单数据类型发送,可
5. FormData
- 可直接序列化表单数据
- 可直接被 Ajax 识别,所以可以不设置请求头
- 除了表单数据外,也可用于普通数据
// 创建 ajax对象
var xhr = new XMLHttpRequest();
// 监听数据返回
xhr.onreadystatechange = function () {
if (xhr.readyState === 4 && xhr.status === 200) {
console.log(xhr.responseText);
// 返回 Array
// (
// [username] => admin
// [password] => admin888
// )
}
};
// 初始化请求参数
xhr.open("POST", "test1.php?action=demo4");
// FormData 传值
var data = new FormData();
data.append("username", "admin");
data.append("password", "admin888");
// 发送请求
xhr.send(data);
php 部分
case 'demo4':
// 可以直接获取到值
print_r($_POST);
break;
6. 实战
实战内容 :
- 异步请求完成点击刷新验证码
- 异步请求完成登录并在验证通过后自动跳转到首页
演示地址: http://php.rc238.cn/0522
- 账号 123@qq.com 密码 123456
index.php
<?php
session_start();
//先判断有没有sesssion 没有跳去登录
if (!isset($_SESSION['user'])){
die("<script>location.href='login.html';</script>");
}
//向下执行
$session = unserialize($_SESSION['user']);
//直接输出数据
var_dump($session);
echo "<a href='handle.php?action=logout'>点这里退出登录</a>";
login.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="stylesheet" href="css/style.css" />
<title>登录</title>
</head>
<body>
<form action="" onsubmit="return false">
<h2>用户登录</h2>
<input
type="email"
name="email"
placeholder="email@php.cn"
required
autofocus
/>
<input
type="password"
name="password"
placeholder="password for php.cn"
required
/>
<div>
<input type="text" name="captch" required placeholder="验证码" />
<button type="button">点击获取验证码</button>
<img src="" alt="" />
</div>
<button>登录</button>
</form>
</body>
<script>
////////////////////////////////////////
// 获取验证码按钮 和 img
var captch_btn = document.querySelector("form > div > button");
var img = document.querySelector("form > div > img");
// 验证码按钮被单击
captch_btn.onclick = function () {
// 隐藏按钮
captch_btn.style.display = "none";
// 显示img
img.style.display = "inline";
// 创建异步请求 请求验证码
var xhr = new XMLHttpRequest();
// 监听请求
xhr.onreadystatechange = function () {
if (xhr.readyState === 4 && xhr.status === 200) {
img.src = xhr.responseText;
}
};
// 初始化请求参数
xhr.open("get", "handle.php?action=captch", true);
// 发送请求
xhr.send(null);
};
// 图片被单击
img.onclick = function () {
// 创建异步请求 请求验证码
var xhr = new XMLHttpRequest();
// 监听请求
xhr.onreadystatechange = function () {
if (xhr.readyState === 4 && xhr.status === 200) {
// 修改src属性
img.src = xhr.responseText;
}
};
// 初始化请求参数
xhr.open("get", "handle.php?action=captch", true);
// 发送请求
xhr.send(null);
};
///////////////////////////////////////
// 登录按钮被单击
// 获取表单 和按钮
var form = document.querySelector("form");
var btn = document.querySelector("form > button");
// 点击事件
btn.onclick = function () {
// 创建ajax对象
var xhr = new XMLHttpRequest();
// 监听返回数据
xhr.onreadystatechange = function () {
if (xhr.readyState === 4 && xhr.status === 200) {
// 反序列化JSON
var msg = JSON.parse(xhr.responseText);
if (msg.message === 1) {
// 跳转去首页
location.href = msg.href;
} else {
// 创建span标签
var span = document.createElement("span");
// 给个值
span.innerHTML = msg.error;
// 换个颜色
span.style.color = "red";
// 标签插入到form表单中
form.appendChild(span);
}
}
};
// 初始化请求参数
xhr.open("POST", "handle.php?action=login", true);
// 获取到表单数据
var data = new FormData(form);
// 发送请求
xhr.send(data);
};
// 清除一下提示信息
var inputs = document.querySelectorAll("input");
for (var i = 0; i < inputs.length; i++) {
// 当有一个input被选中时
inputs[i].oninput = function () {
// 如果button的后面存在元素
if (btn.nextElementSibling !== null) {
// 先获取到span;
var spans = document.querySelectorAll("span");
for (var i = 0; i < spans.length; i++) {
// 循环删除
form.removeChild(btn.nextElementSibling);
}
}
};
}
</script>
</html>
handle.php
<?php
//先判断请求是否合法
if (!isset($_GET['action'])){
die('非法请求');
}
require 'vendor/autoload.php';
use Gregwar\Captcha\CaptchaBuilder;
//开启session
session_start();
//获取action指令
$action = $_GET['action'];
//执行
switch ($action){
// 验证码
case "captch":
$builder = new CaptchaBuilder(4);
$builder->build();
$_SESSION['phrase'] = $builder->getPhrase();
echo $builder->inline();
break;
// 登录
case 'login':
// 先判断验证码是否正确
if (!stristr($_SESSION['phrase'],$_POST['captch'],false)){
die(json_encode(['message'=>0 , 'error'=> '验证码错误']));
}
// 查找数据库
$pdo = new PDo('mysql:host=localhost;dbname=php11.edu','php11.edu','php11.edu');
$stmt = $pdo->prepare('SELECT * FROM `admin` WHERE `email`=? AND `password` = ?');
$stmt->execute([$_POST['email'],sha1($_POST['password'])]);
$user = $stmt->fetch(PDO::FETCH_ASSOC);
// 判断有没有返回数据
if ($user !== false){
// 有数据创建session
$_SESSION['user'] = serialize($user);
// 序列化返回
echo json_encode(['message'=>1 , 'href'=>'index.php']);
}else{
// 没有数据说明密码或邮箱错误
echo json_encode(['message'=>2 , 'error'=> '邮箱或密码错误']);
}
break;
// 退出
case 'logout':
if (session_destroy()) {
echo '<script>alert("退出成功");location.href="index.php";</script>';
}
break;
}
style.css
* {
margin: 0px;
padding: 0px;
box-sizing: border-box;
}
body {
min-height: 100vh;
min-width: 100vw;
background-color: lightskyblue;
display: flex;
justify-content: center;
align-items: center;
}
form {
width: 400px;
gap: 20px;
display: grid;
padding: 20px;
background-color: #fff;
border: none;
border-radius: 10px;
box-shadow: 1px 1px 5px black;
}
form input {
height: 30px;
border: none;
border: 1px solid #ccc;
border-radius: 3px;
text-indent: 20px;
}
form div {
height: 30px;
display: flex;
justify-content: space-between;
}
form > div > input {
width: 200px;
}
form > div > button {
margin-right: 20px;
width: 120px;
border: none;
padding: 5px;
border-radius: 3px;
background-color: #cfcfcf;
color: red;
}
form > div > button:hover {
background-color: grey;
color: #fff;
}
form > div > img {
margin-right: 20px;
width: 120px;
border-radius: 3px;
display: none;
}
form > button {
height: 30px;
border: none;
background-color: lightseagreen;
color: #fff;
font-size: 1.2rem;
letter-spacing: 20px;
border-radius: 10px;
}
form > button:hover {
background-color: limegreen;
}
关于验证码
composer require gregwar/captcha
7. 总结
本来打算把注册也写上的,写得太慢了,写着写着就六点了,只能用已有的账号密码演示了,删除 span 提示标签时,按教案写法结果为 input 删除一个字,span 删除一条 在里面又加了一个循环完美解决 实现删除一个字,span 全部删除