一、AJAX 核心基础:异步交互的基石
1. 同步与异步:交互模式的本质差异
AJAX 的核心是 “异步”,需先明确两种交互模式的区别:
| 类型 | 执行逻辑 | 特点 | 生活案例 | 前端场景举例 |
|---|---|---|---|---|
| 同步 | 任务按顺序执行,前一个完成后才执行下一个 | 阻塞后续任务,效率低 | 打电话时,需挂断当前通话才能接新电话 | 表单提交刷新页面、alert 弹窗 |
| 异步 | 任务并行执行,无需等待前一个任务结果 | 非阻塞,效率高,需回调 | 同时接收多条短信,无需等待一条处理完 | AJAX 请求、定时器 setTimeout
|
关键结论:
- 同步:“排队执行”,必须等待结果;异步:“并行执行”,通过回调函数获取结果。
- AJAX 的核心价值:无刷新页面局部更新,即不重新加载整个页面,仅更新需要的数据区域(如注册时实时验证手机号是否已存在)。
2. AJAX 定义与技术栈
- 全称:Asynchronous JavaScript And XML(异步 JavaScript 和 XML)。
- 本质:不是编程语言,而是一套 “创建交互式网页” 的技术组合,核心是 “用 JS 异步请求数据并更新 DOM”。
-
技术栈构成:
- 前端:JavaScript(逻辑控制)、HTML/CSS(页面展示)、DOM(局部更新)。
- 数据传输:XMLHttpRequest(核心对象,发送异步请求)。
- 数据格式:早期用 XML,现在主流用 JSON(轻量、易解析)。
3. 前后端交互的 3 种核心方式
AJAX 是现代前端的主流交互方式,需与传统方式区分:
| 交互方式 | 实现方式 | 特点 | 适用场景 |
|---|---|---|---|
| Form 表单提交 | 通过 <form> 标签的 action 和 method
|
同步,刷新整个页面 | 简单登录、注册(无实时验证需求) |
| 标签自动请求 | 通过 <a href>、<img src> 等标签 |
同步加载资源,无需 JS | 加载图片、跳转页面、引入脚本 |
| AJAX | 通过 XMLHttpRequest 对象发送请求 | 异步,无刷新局部更新 | 实时验证、列表分页、数据搜索 |
二、AJAX 工作原理与实现步骤(原生 JS)
AJAX 的执行流程可概括为 “四步走”:创建请求对象 → 配置请求 → 发送请求 → 处理响应。
1. 完整实现步骤(兼容 IE 5/6)
步骤 1:创建 XMLHttpRequest 对象(请求载体)
// 现代浏览器(Chrome/Firefox/Edge)
if (window.XMLHttpRequest) {
var xhr = new XMLHttpRequest();
}
// IE 5/6 兼容(旧浏览器)
else if (window.ActiveXObject) {
var xhr = new ActiveXObject("Microsoft.XMLHTTP");
}
步骤 2:配置请求信息(open 方法)
// 语法:xhr.open(请求方法, 请求地址, 是否异步)
// 1. GET 请求:参数拼接在 URL 后(需用 encodeURI***ponent 处理特殊字符)
var params = "username=" + encodeURI***ponent("张三") + "&age=18";
xhr.open("GET", "test.php?" + params, true); // true = 异步,false = 同步
// 2. POST 请求:参数在 send 中传递,需设置请求头
xhr.open("POST", "test.php", true);
// 必须设置 Content-Type,告诉服务器参数格式(仅 POST 需设置)
xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
步骤 3:发送请求(send 方法)
// GET 请求:send 传 null 或空
xhr.send(null);
// POST 请求:send 中传递参数(格式与 URL 参数一致)
xhr.send("username=张三&age=18");
步骤 4:监听响应(onreadystatechange 事件)
通过 readyState(请求状态)和 status(HTTP 状态码)判断请求是否成功:
xhr.onreadystatechange = function () {
// readyState === 4:请求已完成,响应已就绪
// status === 200:HTTP 请求成功(404=资源未找到,500=服务器错误)
if (xhr.readyState === 4 && xhr.status === 200) {
// 服务器返回的数据:responseText(文本)、responseXML(XML)
var responseData = xhr.responseText;
// 处理数据(如更新 DOM)
document.getElementById("result").innerText = responseData;
}
};
核心属性解析:
| 属性 | 含义 | 关键取值说明 |
|---|---|---|
readyState |
XMLHttpRequest 请求状态 | 0(未初始化)→ 4(已完成) |
status |
HTTP 响应状态码 | 200(成功)、404(未找到)、500(错误) |
responseText |
服务器返回的文本数据 | 常用(如 JSON 字符串) |
onreadystatechange |
状态变化时的回调函数 | 每次 readyState 变化都会触发 |
2. AJAX 优缺点
优点:
- 无刷新更新:局部更新页面,减少用户等待,提升体验(如实时搜索提示)。
- 减轻服务器负担:仅请求所需数据,而非整个页面(如分页仅加载当前页数据)。
- 数据与显示分离:前端负责展示,后端负责数据,便于团队协作维护。
- 跨平台兼容:基于标准 Web 技术,支持所有现代浏览器。
缺点:
- SEO 不友好:数据通过 JS 动态加载,搜索引擎难以抓取(需用 SSR 等技术优化)。
-
破坏浏览器历史:无刷新交互不生成历史记录,
Back按钮无效(需用history.pushState解决)。 - 跨域限制:浏览器 “同源策略” 禁止 AJAX 请求非同源域名(需 CORS、JSONP 等方案解决)。
- 编码限制:默认仅支持 UTF-8 编码数据,需统一前后端编码格式。
三、后端支撑:PHP 与 JSON-Server
AJAX 需要后端接口返回数据,以下介绍两种常用后端方案:PHP(真实后端) 和 JSON-Server(模拟后端)。
1. PHP 基础:搭建真实后端接口
1.1 PHP 环境搭建(XAMPP/PHPStudy)
- 工具选择:XAMPP(集成 Apache 服务器、MySQL、PHP)或 PHPStudy(中文界面,更易操作)。
-
核心步骤:
- 下载安装:XAMPP 官网(https://www.apachefriends.org/),PHPStudy 官网(https://www.xp.***/)。
- 启动服务:启动 Apache(处理 HTTP 请求)和 MySQL(可选,用于数据库)。
- 项目目录:XAMPP 为
xampp/htdocs,PHPStudy 为phpstudy_pro/WWW(PHP 文件需放在此目录)。 - 访问测试:浏览器输入
http://127.0.0.1,可查看项目目录列表。
1.2 PHP 核心语法(与 AJAX 交互相关)
(1)变量定义与输出
- 变量以
$开头,弱类型语言,无需声明类型。 - 输出函数:
echo(常用,输出字符串)、print_r(输出数组)、var_dump(输出变量类型 + 值)。
php
// 变量定义
$username = "张三";
$age = 18;
$hobby = array("篮球", "编程");
// 输出(给 AJAX 返回数据)
echo $username; // 输出:张三
print_r($hobby); // 输出:Array ( [0] => 篮球 [1] => 编程 )
var_dump($age); // 输出:int(18)
(2)接收 AJAX 参数(GET/POST)
PHP 通过超全局数组接收 AJAX 传递的参数:
-
$_GET:接收 GET 方式参数(URL 拼接)。 -
$_POST:接收 POST 方式参数(请求体)。
php
// 1. 接收 GET 参数(AJAX 用 GET 发送:test.php?username=张三&age=18)
$username = $_GET["username"];
$age = $_GET["age"];
// 2. 接收 POST 参数(AJAX 用 POST 发送,参数在 send 中)
$username = $_POST["username"];
$age = $_POST["age"];
// 3. 接收数组参数(如多选框,前端 name 需加 []:name="hobby[]")
$hobby = $_POST["hobby"]; // 数组:["篮球", "编程"]
(3)JSON 数据交互(前后端标准格式)
AJAX 与 PHP 交互常用 JSON 格式,需用 PHP 的 json_encode(数组转 JSON)和 json_decode(JSON 转数组):
php
// 1. PHP 数组转 JSON(返回给 AJAX)
$user = array(
"name" => "张三",
"age" => 18,
"hobby" => array("篮球", "编程")
);
$jsonStr = json_encode($user); // 转 JSON 字符串
echo $jsonStr; // 输出:{"name":"张三","age":18,"hobby":["篮球","编程"]}
// 2. 接收 AJAX 发送的 JSON 数据(需用 file_get_contents 读取请求体)
$jsonStr = file_get_contents("php://input");
$user = json_decode($jsonStr, true); // 转关联数组(true 表示数组,默认对象)
echo $user["name"]; // 输出:张三
(4)引入外部文件(代码复用)
通过 include/require 引入外部 PHP 文件(如公共配置、工具函数):
| 函数 | 功能 | 差异 |
|---|---|---|
include |
引入文件,报错仅警告 | 适合非必需文件(如可选模块) |
require |
引入文件,报错终止执行 | 适合必需文件(如配置文件) |
include_once |
同 include,但仅引入一次 | 防止重复引入导致代码冗余 |
require_once |
同 require,但仅引入一次 | 防止重复引入导致代码冗余 |
php
// 引入配置文件
require_once "config.php";
2. JSON-Server:快速搭建模拟后端
当后端未开发完成时,用 JSON-Server 可快速生成模拟 API,支持完整 RESTful 操作。
2.1 安装与启动
-
前置条件:安装 Node.js(
node -v验证)。 -
安装 JSON-Server:
bash
# 全局安装 npm install -g json-server # 查看版本(验证安装) json-server --version # 若最新版本有问题,安装稳定旧版本(如 0.17.3) npm uninstall -g json-server npm install -g json-server@0.17.3 -
创建数据源:在项目目录创建
db.json(模拟数据库):json
{ "student": [ { "id": 1000, "uname": "小明", "class": "web前端", "age": 19 }, { "id": 1001, "uname": "小红", "class": "java开发", "age": 20 } ], "tableList": ["首页", "公司概况", "云和教育"] } -
启动服务:在
db.json所在目录执行:bash
# 基本启动(默认端口 3000) json-server --watch db.json # 自定义端口(如 3300) json-server --watch db.json --port 3300 -
访问测试:
http://localhost:3000/student可查看所有学生数据。
2.2 RESTful API 操作(增删改查)
JSON-Server 支持标准 RESTful 接口,直接通过 URL 和请求方法操作数据:
| 操作 | 请求方法 | URL 示例 | 说明 |
|---|---|---|---|
| 获取所有资源 | GET | /student |
返回 student 数组 |
| 获取单个资源 | GET | /student/1000 |
返回 ID 为 1000 的学生 |
| 添加资源 | POST | /student |
新增学生(无需传 ID,自动生成) |
| 全量更新 | PUT | /student/1000 |
覆盖更新 ID 1000 的学生(需传所有字段) |
| 局部更新 | PATCH | /student/1000 |
仅更新指定字段(如只改 age) |
| 删除资源 | DELETE | /student/1000 |
删除 ID 1000 的学生 |
2.3 高级功能(分页、排序、查询)
-
分页:
_page(页码)+_per_page(每页条数):plaintext
http://localhost:3000/student?_page=1&_per_page=2 -
排序:
_sort(排序字段)+_order(asc 升序 /desc 降序):plaintext
http://localhost:3000/student?_sort=age&_order=desc -
条件查询:直接通过字段名过滤:
plaintext
# 查询班级为 "web前端" 的学生 http://localhost:3000/student?class=web前端 -
模糊查询(0.17.x 版本支持):
字段名_like:plaintext
# 查询姓名包含 "小" 的学生 http://localhost:3000/student?uname_like=小
AJAX 高级应用:懒加载
1. 懒加载原理
懒加载(延迟加载)是优化长列表性能的核心方案,原理是:
- 初始仅加载 “可视区域” 内的资源(如图片、列表数据)。
- 当页面滚动时,判断资源是否进入可视区域,若进入则加载。
- 核心:减少初始加载的资源量,提升首屏渲染速度。
2. 实现图片懒加载(AJAX 配合滚动监听)
html
预览
<!DOCTYPE html>
<html lang="zh-***">
<head>
<meta charset="UTF-8">
<title>图片懒加载示例</title>
<style>
.img-list { display: grid; grid-template-columns: repeat(3, 1fr); gap: 20px; width: 1000px; margin: 0 auto; padding: 20px; }
.img-item { height: 200px; background: #f5f5f5; overflow: hidden; }
.img-item img { width: 100%; height: 100%; object-fit: cover; }
</style>
</head>
<body>
<div class="img-list" id="img-list"></div>
<script>
var imgList = document.getElementById("img-list");
var page = 1; // 当前页码
var isLoading = false; // 防止重复请求的锁
// 1. 初始加载第一页图片
loadImages(page);
// 2. 监听滚动事件,实现懒加载
window.addEventListener("scroll", function () {
// 当滚动到“可视区域底部+200px”时加载下一页
var scrollTop = document.documentElement.scrollTop || document.body.scrollTop;
var windowHeight = document.documentElement.clientHeight;
var documentHeight = document.documentElement.scrollHeight;
if (scrollTop + windowHeight + 200 >= documentHeight && !isLoading) {
page++;
loadImages(page);
}
});
// 加载图片的 AJAX 函数
function loadImages(page) {
isLoading = true; // 上锁,防止重复请求
ajax({
method: "GET",
url: "https://www.fastmock.site/mock/xxx/api/images", // FastMock 模拟接口
data: { page: page, limit: 9 }, // 每页加载 9 张图
su***ess: function (responseText) {
var res = JSON.parse(responseText);
var images = res.data;
// 渲染图片到页面
renderImages(images);
isLoading = false; // 解锁
},
error: function () {
console.error("图片加载失败");
isLoading = false; // 解锁
}
});
}
// 渲染图片列表
function renderImages(images) {
var html = "";
images.forEach(img => {
// 初始用占位图,真实地址存放在 data-src 中
html += `
<div class="img-item">
<img src="placeholder.png" data-src="${img.url}" alt="图片">
</div>
`;
});
imgList.innerHTML += html;
// 检查已渲染的图片是否进入可视区域,若进入则加载真实图片
checkImagesInView();
}
// 检查图片是否进入可视区域,加载真实图片
function checkImagesInView() {
var imgs = document.querySelectorAll(".img-item img");
imgs.forEach(img => {
// 若已加载过,跳过
if (img.src === img.dataset.src) return;
// 获取图片位置信息
var rect = img.getBoundingClientRect();
var windowHeight = document.documentElement.clientHeight;
// 若图片顶部 <= 可视区域高度(进入可视区域),加载真实图片
if (rect.top <= windowHeight) {
img.src = img.dataset.src; // 替换为真实地址
// 可选:添加加载动画
img.style.opacity = 0;
img.onload = function () {
img.style.transition = "opacity 0.3s";
img.style.opacity = 1;
};
}
});
}
// 通用 AJAX 函数(同上文封装)
function ajax(options) { /* 此处省略,同上文封装代码 */ }
</script>
</body>
</html>
关键细节:
-
占位图:初始用占位图(如灰色背景),真实图片地址存放在
data-src属性中,避免初始加载大量图片。 -
滚动监听:通过
scroll事件判断页面滚动位置,当接近底部时加载下一页。 -
防重复请求:用
isLoading锁控制,避免滚动时多次触发请求。