<!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>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: 'Microsoft YaHei', sans-serif;
max-width: 800px;
margin: 0 auto;
padding: 20px;
background-color: #f5f5f5;
}
.container {
background: white;
border-radius: 10px;
padding: 30px;
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
}
h1 {
color: #333;
text-align: center;
margin-bottom: 30px;
padding-bottom: 15px;
border-bottom: 2px solid #4CAF50;
}
.section {
margin: 25px 0;
padding: 20px;
border: 1px solid #ddd;
border-radius: 8px;
background: #fafafa;
}
h2 {
color: #4CAF50;
margin-bottom: 15px;
}
.input-group {
margin-bottom: 15px;
}
label {
display: block;
margin-bottom: 5px;
color: #555;
font-weight: bold;
}
input, textarea {
width: 100%;
padding: 10px;
border: 1px solid #ddd;
border-radius: 4px;
font-size: 14px;
}
textarea {
height: 100px;
resize: vertical;
}
button {
background: #4CAF50;
color: white;
border: none;
padding: 10px 20px;
border-radius: 4px;
cursor: pointer;
font-size: 16px;
transition: background 0.3s;
}
button:hover {
background: #45a049;
}
.loading {
display: none;
color: #2196F3;
margin: 10px 0;
}
.result {
margin-top: 15px;
padding: 15px;
border-radius: 4px;
background: #e8f5e8;
border-left: 4px solid #4CAF50;
display: none;
}
.result.error {
background: #ffebee;
border-left-color: #f44336;
}
#userList {
list-style: none;
margin: 10px 0;
}
#userList li {
padding: 10px;
margin: 5px 0;
background: white;
border: 1px solid #ddd;
border-radius: 4px;
display: flex;
justify-content: space-between;
}
.delete-btn {
background: #f44336;
padding: 5px 10px;
font-size: 12px;
}
.delete-btn:hover {
background: #d32f2f;
}
</style>
</head>
<body>
<div class="container">
<h1>Ajax 无刷新交互演示</h1>
<!-- 用户注册部分 -->
<div class="section">
<h2>1. 用户注册</h2>
<div class="input-group">
<label for="username">用户名:</label>
<input type="text" id="username" placeholder="请输入用户名">
</div>
<div class="input-group">
<label for="email">邮箱:</label>
<input type="email" id="email" placeholder="请输入邮箱">
</div>
<button id="registerBtn">注册用户</button>
<div class="loading" id="registerLoading">注册中...</div>
<div class="result" id="registerResult"></div>
</div>
<!-- 获取用户列表 -->
<div class="section">
<h2>2. 用户列表</h2>
<button id="getUsersBtn">获取用户列表</button>
<div class="loading" id="usersLoading">加载中...</div>
<ul id="userList"></ul>
<div class="result" id="usersResult"></div>
</div>
<!-- 数据提交 -->
<div class="section">
<h2>3. 提交数据</h2>
<div class="input-group">
<label for="dataInput">输入内容:</label>
<textarea id="dataInput" placeholder="请输入要提交的内容"></textarea>
</div>
<button id="submitDataBtn">提交数据</button>
<div class="loading" id="submitLoading">提交中...</div>
<div class="result" id="submitResult"></div>
</div>
<!-- 模拟搜索 -->
<div class="section">
<h2>4. 实时搜索</h2>
<div class="input-group">
<label for="searchInput">搜索关键词:</label>
<input type="text" id="searchInput" placeholder="输入关键词开始搜索">
</div>
<div class="loading" id="searchLoading">搜索中...</div>
<div id="searchResults"></div>
</div>
</div>
<script>
// 基础配置
const API_BASE = 'http://localhost:3000/api';
// 显示/隐藏加载动画
function showLoading(elementId) {
document.getElementById(elementId).style.display = 'block';
}
function hideLoading(elementId) {
document.getElementById(elementId).style.display = 'none';
}
// 显示结果
function showResult(elementId, message, isError = false) {
const element = document.getElementById(elementId);
element.textContent = message;
element.className = isError ? 'result error' : 'result';
element.style.display = 'block';
// 3秒后自动隐藏
setTimeout(() => {
element.style.display = 'none';
}, 3000);
}
// 1. 注册用户
document.getElementById('registerBtn').addEventListener('click', function() {
const username = document.getElementById('username').value.trim();
const email = document.getElementById('email').value.trim();
if (!username || !email) {
showResult('registerResult', '请输入用户名和邮箱', true);
return;
}
showLoading('registerLoading');
// 使用Fetch API发送POST请求
fetch(`${API_BASE}/register`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
username: username,
email: email
})
})
.then(response => response.json())
.then(data => {
hideLoading('registerLoading');
if (data.success) {
showResult('registerResult', `注册成功!用户ID: ${data.user.id}`);
// 清空输入框
document.getElementById('username').value = '';
document.getElementById('email').value = '';
// 刷新用户列表
loadUsers();
} else {
showResult('registerResult', data.message || '注册失败', true);
}
})
.catch(error => {
hideLoading('registerLoading');
showResult('registerResult', '请求失败: ' + error.message, true);
});
});
// 2. 获取用户列表
function loadUsers() {
showLoading('usersLoading');
// 使用XMLHttpRequest(传统方式)
const xhr = new XMLHttpRequest();
xhr.open('GET', `${API_BASE}/users`, true);
xhr.onload = function() {
hideLoading('usersLoading');
if (xhr.status === 200) {
const data = JSON.parse(xhr.responseText);
displayUsers(data.users || []);
} else {
showResult('usersResult', '获取用户列表失败', true);
}
};
xhr.onerror = function() {
hideLoading('usersLoading');
showResult('usersResult', '网络错误', true);
};
xhr.send();
}
function displayUsers(users) {
const userList = document.getElementById('userList');
userList.innerHTML = '';
if (users.length === 0) {
userList.innerHTML = '<li>暂无用户</li>';
return;
}
users.forEach(user => {
const li = document.createElement('li');
li.innerHTML = `
<span>${user.username} (${user.email})</span>
<button class="delete-btn" onclick="deleteUser(${user.id})">删除</button>
`;
userList.appendChild(li);
});
}
// 删除用户
window.deleteUser = function(userId) {
if (!confirm('确定要删除这个用户吗?')) return;
fetch(`${API_BASE}/users/${userId}`, {
method: 'DELETE'
})
.then(response => response.json())
.then(data => {
if (data.success) {
loadUsers(); // 重新加载列表
}
})
.catch(error => {
console.error('删除失败:', error);
});
};
document.getElementById('getUsersBtn').addEventListener('click', loadUsers);
// 3. 提交数据
document.getElementById('submitDataBtn').addEventListener('click', function() {
const data = document.getElementById('dataInput').value.trim();
if (!data) {
showResult('submitResult', '请输入内容', true);
return;
}
showLoading('submitLoading');
// 使用Fetch API
fetch(`${API_BASE}/submit`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ data: data })
})
.then(response => {
if (!response.ok) {
throw new Error('网络响应异常');
}
return response.json();
})
.then(data => {
hideLoading('submitLoading');
showResult('submitResult', `提交成功!服务器返回: ${data.message}`);
document.getElementById('dataInput').value = '';
})
.catch(error => {
hideLoading('submitLoading');
showResult('submitResult', '提交失败: ' + error.message, true);
});
});
// 4. 实时搜索
let searchTimeout;
document.getElementById('searchInput').addEventListener('input', function() {
const keyword = this.value.trim();
clearTimeout(searchTimeout);
if (keyword.length === 0) {
document.getElementById('searchResults').innerHTML = '';
return;
}
if (keyword.length < 2) return;
showLoading('searchLoading');
// 防抖处理,300毫秒后执行搜索
searchTimeout = setTimeout(() => {
// 使用jQuery风格的ajax(如果引入jQuery)
// 这里使用原生的fetch
fetch(`${API_BASE}/search?q=${encodeURIComponent(keyword)}`)
.then(response => response.json())
.then(data => {
hideLoading('searchLoading');
displaySearchResults(data.results || []);
})
.catch(error => {
hideLoading('searchLoading');
console.error('搜索失败:', error);
});
}, 300);
});
function displaySearchResults(results) {
const container = document.getElementById('searchResults');
if (results.length === 0) {
container.innerHTML = '<p>没有找到相关结果</p>';
return;
}
let html = '<h3>搜索结果:</h3><ul>';
results.forEach(result => {
html += `<li><strong>${result.title}</strong>: ${result.content}</li>`;
});
html += '</ul>';
container.innerHTML = html;
}
// 页面加载时获取用户列表
document.addEventListener('DOMContentLoaded', loadUsers);
</script>
</body>
</html>
const express = require('express');
const cors = require('cors');
const bodyParser = require('body-parser');
const app = express();
const PORT = 3000;
// 中间件
app.use(cors()); // 允许跨域
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
// 模拟数据库
let users = [
{ id: 1, username: '张三', email: 'zhangsan@example.com' },
{ id: 2, username: '李四', email: 'lisi@example.com' },
{ id: 3, username: '王五', email: 'wangwu@example.com' }
];
let userIdCounter = 4;
// 模拟搜索数据
const searchData = [
{ id: 1, title: 'JavaScript教程', content: '学习JavaScript基础知识' },
{ id: 2, title: 'Ajax技术', content: '掌握Ajax异步通信' },
{ id: 3, title: 'Node.js开发', content: '使用Node.js构建服务器' },
{ id: 4, title: '前端框架', content: 'React、Vue等框架使用' },
{ id: 5, title: '数据库操作', content: 'MongoDB和MySQL的使用' }
];
// API路由
// 1. 用户注册
app.post('/api/register', (req, res) => {
const { username, email } = req.body;
if (!username || !email) {
return res.json({
success: false,
message: '用户名和邮箱不能为空'
});
}
// 检查邮箱是否已存在
const emailExists = users.some(user => user.email === email);
if (emailExists) {
return res.json({
success: false,
message: '邮箱已存在'
});
}
// 创建新用户
const newUser = {
id: userIdCounter++,
username,
email,
createdAt: new Date().toISOString()
};
users.push(newUser);
res.json({
success: true,
message: '注册成功',
user: newUser
});
});
// 2. 获取用户列表
app.get('/api/users', (req, res) => {
res.json({
success: true,
users: users
});
});
// 3. 删除用户
app.delete('/api/users/:id', (req, res) => {
const userId = parseInt(req.params.id);
const initialLength = users.length;
users = users.filter(user => user.id !== userId);
if (users.length < initialLength) {
res.json({
success: true,
message: '用户删除成功'
});
} else {
res.json({
success: false,
message: '用户不存在'
});
}
});
// 4. 提交数据
app.post('/api/submit', (req, res) => {
const { data } = req.body;
if (!data) {
return res.status(400).json({
success: false,
message: '数据不能为空'
});
}
// 模拟处理数据
const processedData = data.toUpperCase();
res.json({
success: true,
message: `已收到数据: ${data}`,
processed: processedData,
timestamp: new Date().toISOString()
});
});
// 5. 搜索功能
app.get('/api/search', (req, res) => {
const query = req.query.q || '';
if (!query) {
return res.json({
success: true,
results: []
});
}
const keyword = query.toLowerCase();
const results = searchData.filter(item =>
item.title.toLowerCase().includes(keyword) ||
item.content.toLowerCase().includes(keyword)
);
// 模拟延迟
setTimeout(() => {
res.json({
success: true,
query: query,
results: results,
count: results.length
});
}, 500); // 500毫秒延迟
});
// 6. 获取服务器状态
app.get('/api/status', (req, res) => {
res.json({
success: true,
status: '运行中',
timestamp: new Date().toISOString(),
usersCount: users.length
});
});
// 静态文件服务
app.use(express.static('public'));
// 错误处理中间件
app.use((err, req, res, next) => {
console.error(err.stack);
res.status(500).json({
success: false,
message: '服务器内部错误',
error: process.env.NODE_ENV === 'development' ? err.message : undefined
});
});
// 404处理
app.use((req, res) => {
res.status(404).json({
success: false,
message: 'API端点不存在'
});
});
// 启动服务器
app.listen(PORT, () => {
console.log(`服务器运行在 http://localhost:${PORT}`);
console.log(`API接口地址: http://localhost:${PORT}/api`);
console.log('可用接口:');
console.log(' POST /api/register - 用户注册');
console.log(' GET /api/users - 获取用户列表');
console.log(' DELETE /api/users/:id - 删除用户');
console.log(' POST /api/submit - 提交数据');
console.log(' GET /api/search?q= - 搜索功能');
console.log(' GET /api/status - 服务器状态');
});
{
"name": "ajax-demo",
"version": "1.0.0",
"description": "Ajax无刷新交互演示",
"main": "server.js",
"scripts": {
"start": "node server.js",
"dev": "nodemon server.js"
},
"dependencies": {
"express": "^4.18.2",
"cors": "^2.8.5",
"body-parser": "^1.20.2"
},
"devDependencies": {
"nodemon": "^3.0.1"
}
}
创建项目目录结构:
ajax-demo/
├── index.html
├── server.js
├── package.json
└── public/
└── (可放其他静态文件)
安装依赖:
npm install express cors body-parser
# 或
npm install
启动服务器:
node server.js
# 或使用nodemon(需要先安装)
nodemon server.js
访问应用:
打开浏览器,访问:http://localhost:3000
POST /api/register - 用户注册
GET /api/users - 获取用户列表
DELETE /api/users/:id - 删除用户
POST /api/submit - 提交数据
GET /api/search - 搜索功能
这个实例完整展示了Ajax无刷新交互的完整流程,您可以直接运行和扩展使用。