AJAX 是一种用于创建快速动态网页的技术",AJAX 是基于现有前端技术的组合(非新发明的技术),核心包含 4 个部分:
- JavaScript:发起异步请求、处理服务器响应、操作 DOM 更新页面;
- XML/JSON:作为前后端数据交换的格式(早期用 XML,现在主流用 JSON,更轻量、易解析);
- XMLHttpRequest/fetch API:浏览器提供的 "通信接口",负责在后台与服务器交换数据;
- DOM(文档对象模型):通过 JavaScript 操作 DOM,实现 "局部页面更新
| | 传统网页(无 AJAX) | AJAX 网页 |
| 数据请求方式 | 同步请求:发送请求后,页面 "卡住",等待服务器响应 | 异步请求:请求在后台执行,不阻塞页面操作(如点击、滚动) |
| 页面更新方式 | 必须重新加载整个页面(即使只更新一个列表) | 仅更新需要变化的局部区域(如评论列表、商品价格) |
| 用户体验 | 等待时间长、页面频繁刷新,体验卡顿 | 无刷新、响应快,体验流畅(如微博下拉加载新内容) |
资源消耗 | 重新加载整个页面,浪费带宽(重复加载 CSS/JS) | 仅传输少量数据(如 JSON),节省带宽和服务器资源 |
---|
AJAX 的核心工作流程
-
触发事件:用户操作(如点击 "加载更多" 按钮),触发 JavaScript 函数;
-
创建请求对象 :JavaScript 创建
XMLHttpRequest
或调用fetch API
,准备与服务器通信; -
配置并发送请求 :指定请求方式(GET/POST)、请求地址(如
/api/goods
),并发送请求(带参数,如 "页码 = 2"); -
服务器处理请求 :服务器接收请求,查询数据库,返回包含商品数据的 JSON(如
{"list": [商品1, 商品2]}
); -
前端处理响应:AJAX 接收 JSON 数据,通过 JavaScript 解析数据,生成 HTML 结构(如商品卡片);
-
局部更新 DOM:将生成的 HTML 插入到 "商品列表" 容器中,完成局部更新,用户看到新商品。
javascript
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>AJAX加载更多示例</title>
<style>
.container {
max-width: 800px;
margin: 0 auto;
padding: 20px;
}
.product-list {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
gap: 20px;
margin-bottom: 30px;
}
.product-card {
border: 1px solid #ddd;
padding: 15px;
border-radius: 8px;
}
.product-card img {
width: 100%;
height: 150px;
object-fit: cover;
}
.load-more-btn {
display: block;
margin: 0 auto;
padding: 10px 20px;
background-color: #007bff;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
font-size: 16px;
}
.load-more-btn:disabled {
background-color: #6c757d;
cursor: not-allowed;
}
.loading {
text-align: center;
color: #666;
padding: 20px;
}
</style>
</head>
<body>
<div class="container">
<h1>商品列表</h1>
<!-- 商品列表容器 -->
<div class="product-list" id="productList"></div>
<!-- 加载更多按钮 -->
<button class="load-more-btn" id="loadMoreBtn">加载更多</button>
</div>
<script>
// 当前页码,从1开始
let currentPage = 1;
// 每页显示数量
const pageSize = 3;
// 是否正在加载中
let isLoading = false;
// 1. 触发事件:给按钮绑定点击事件
document.getElementById('loadMoreBtn').addEventListener('click', loadMoreProducts);
// 页面加载时先加载第一页数据
loadMoreProducts();
// 加载更多商品的函数
async function loadMoreProducts() {
// 防止重复点击
if (isLoading) return;
isLoading = true;
const loadMoreBtn = document.getElementById('loadMoreBtn');
const productList = document.getElementById('productList');
// 显示加载状态
loadMoreBtn.disabled = true;
loadMoreBtn.textContent = '加载中...';
productList.insertAdjacentHTML('beforeend', '<div class="loading">正在加载...</div>');
try {
// 2. 创建请求对象:使用fetch API
// 3. 配置并发送请求:指定GET方式,带页码参数
const response = await fetch(`https://jsonplaceholder.typicode.com/photos?_page=${currentPage}&_limit=${pageSize}`);
if (!response.ok) {
throw new Error(`请求失败: ${response.status}`);
}
// 4. 服务器处理请求后返回数据,这里解析JSON
const products = await response.json();
// 移除加载提示
const loadingEl = productList.querySelector('.loading');
if (loadingEl) productList.removeChild(loadingEl);
// 5. 前端处理响应:生成HTML结构
if (products.length > 0) {
let html = '';
products.forEach(product => {
html += `
<div class="product-card">
<img src="${product.thumbnailUrl}" alt="${product.title}">
<h3>${product.title.substring(0, 20)}...</h3>
<p>商品ID: ${product.id}</p>
</div>
`;
});
// 6. 局部更新DOM:将生成的HTML插入到列表
productList.insertAdjacentHTML('beforeend', html);
// 页码加1,准备下次加载
currentPage++;
loadMoreBtn.disabled = false;
loadMoreBtn.textContent = '加载更多';
} else {
// 没有更多数据
loadMoreBtn.textContent = '没有更多商品了';
}
} catch (error) {
// 处理错误
const loadingEl = productList.querySelector('.loading');
if (loadingEl) loadingEl.textContent = `加载失败: ${error.message}`;
// 允许重试
loadMoreBtn.disabled = false;
loadMoreBtn.textContent = '重试';
} finally {
isLoading = false;
}
}
</script>
</body>
</html>