Skip to content

AJAX 实时搜索

PHP 示例:使用 Fetch API 和 JSON 实现 AJAX 实时搜索

Section titled “PHP 示例:使用 Fetch API 和 JSON 实现 AJAX 实时搜索”

AJAX (Asynchronous JavaScript and XML - 异步 JavaScript 和 XML,尽管现在 JSON 更常用) 允许网页从服务器请求数据并更新页面部分内容,而无需完全重新加载。这带来了更快、更具交互性的用户体验,例如实时搜索建议。

此示例演示了实时搜索功能。当您在输入框中键入时,JavaScript 会向一个 PHP 脚本发送请求,该脚本搜索匹配的数据并以 JSON 格式返回建议。然后 JavaScript 会更新页面以显示这些建议。

实时搜索的优点:

  • 即时反馈:结果会随着用户的键入而出现。
  • 结果细化:输入更多字符,结果范围会缩小。
  • 效率高:避免不必要的整页加载。

想象一个输入框,其下方有一个 div 元素,用于显示结果:

<form onsubmit="return false;"> <!-- 阻止表单提交 -->
<label for="search">Search for a term:</label>
<input type="text" id="search" size="30" autocomplete="off">
</form>
<div id="livesearch-results" style="border: 1px solid #ccc; min-height: 20px; margin-top: 5px; padding: 5px;"></div>

在此概念示例中,建议将来自 PHP 后端。

示例讲解 - 客户端(使用 Fetch 的 JavaScript)

Section titled “示例讲解 - 客户端(使用 Fetch 的 JavaScript)”

我们使用现代 JavaScript(fetch API、async/await、addEventListener)来处理用户输入并与服务器通信。

<!-- 将此脚本块包含在您的 HTML 页面中 -->
<script>
document.addEventListener('DOMContentLoaded', () => {
const searchInput = document.getElementById('search');
const resultsContainer = document.getElementById('livesearch-results');
searchInput.addEventListener('keyup', async (event) => {
const query = event.target.value.trim();
if (query.length === 0) {
resultsContainer.innerHTML = '';
resultsContainer.style.display = 'none'; // 如果为空则隐藏
return;
}
try {
// 发送请求到 PHP 后端
const response = await fetch(`livesearch.php?q=${encodeURIComponent(query)}`);
if (!response.ok) {
throw new Error(`HTTP error! Status: ${response.status}`);
}
// 期望 JSON 响应
const suggestions = await response.json();
// 更新结果容器
resultsContainer.style.display = 'block'; // 显示结果容器
if (suggestions.length > 0) {
resultsContainer.innerHTML = ''; // 清除之前的结果
suggestions.forEach(suggestion => {
const div = document.createElement('div');
// 注意:在实际应用中,生成链接需要谨慎处理
// 如果直接使用,请确保 suggestion.url 经过适当的清理/验证
div.innerHTML = `<a href="#" onclick="alert('Selected: ${suggestion.title.replace(/'/g, "\\'")}')">${suggestion.title}</a>`;
resultsContainer.appendChild(div);
});
} else {
resultsContainer.innerHTML = '未找到建议。';
}
} catch (error) {
console.error('获取搜索结果出错:', error);
resultsContainer.innerHTML = '加载建议出错。';
resultsContainer.style.display = 'block';
}
});
});
</script>

代码解释:

  • 输入框的 keyup 事件上附加了一个事件监听器。
  • 如果输入为空,则清除并隐藏结果区域。
  • fetch API 向 livesearch.php 发起一个异步 GET 请求,将用户的查询 (q) 作为 URL 参数传递(使用 encodeURIComponent 进行适当编码)。
  • 使用 async/await 以更清晰地处理异步操作。
  • 基本的错误处理检查 HTTP 响应状态并捕获网络或 JSON 解析错误。
  • 使用 response.json() 将响应解析为 JSON。
  • resultsContainer 会根据从服务器接收到的建议动态更新,或者显示“未找到建议”的消息。
  • 为建议创建链接(在实际应用中,这些链接会用于导航或执行某个操作)。

示例讲解 - 服务器端(PHP 脚本)

Section titled “示例讲解 - 服务器端(PHP 脚本)”

livesearch.php 脚本接收搜索查询,查找匹配的数据(此处来自一个简单的数组),并将结果作为 JSON 格式的字符串返回。

<?php
// 示例数据源(在实际应用中,这可能来自数据库)
$dataStore = [
['id' => 1, 'title' => 'HTML Tutorial', 'url' => '/html/'],
['id' => 2, 'title' => 'CSS Tutorial', 'url' => '/css/'],
['id' => 3, 'title' => 'JavaScript Tutorial', 'url' => '/js/'],
['id' => 4, 'title' => 'PHP Tutorial', 'url' => '/php/'],
['id' => 5, 'title' => 'SQL Introduction', 'url' => '/sql/'],
['id' => 6, 'title' => 'Python Basics', 'url' => '/python/']
];
// 获取搜索查询参数(带有基本过滤)
$query = filter_input(INPUT_GET, 'q', FILTER_SANITIZE_STRING);
$suggestions = [];
if ($query && strlen($query) > 0) {
$queryLower = strtolower($query);
foreach ($dataStore as $item) {
// 在标题中进行不区分大小写的搜索
if (str_contains(strtolower($item['title']), $queryLower)) {
// 仅选择响应所需的字段
$suggestions[] = [
'title' => $item['title'],
'url' => $item['url'] // 如果直接在 JS 中使用,请确保这是安全的!
];
}
// 如有需要,限制建议的数量
if (count($suggestions) >= 10) {
break;
}
}
}
// 设置内容类型头部为 JSON
header('Content-Type: application/json');
// 将建议数组编码为 JSON 并输出
echo json_encode($suggestions);
?>

代码解释:

  • 一个简单的数组 $dataStore 用作我们的数据库。
  • 使用 filter_input 从 GET 请求中检索搜索查询 q,进行基本的清理(sanitization)。
  • 如果查询存在,代码会遍历数据存储。
  • str_contains (PHP 8+) 执行不区分大小写的搜索(在将两个字符串转换为小写之后)。对于旧版 PHP,请使用 stripos。
  • 匹配项(仅包含 ‘title’ 和 ‘url’)被添加到 $suggestions 数组中。
  • Content-Type 头部被设置为 application/json,以告知客户端。
  • json_encode() 将 PHP 数组转换为 JSON 字符串,然后作为响应发送回去。