Laravel 实时搜索完整指南

最后更新: 12月5 2025
  • Laravel 允许您实现从使用 AJAX 的简单搜索引擎到使用 Laravel Scout 和 Algolia、Meilisearch 或 Elasticsearch 等外部搜索引擎的高级全文搜索等各种功能。
  • 对于轻量级搜索,使用 Alpine.js 或原生 fetch 请求在前端进行过滤可以避免服务器过载,并改善小型列表的用户体验。
  • Laravel Scout 集中集成了与不同搜索引擎的集成,使模型标记为可搜索、管理索引和统一启动查询变得容易。
  • 引擎(SaaS、开源或数据库)的选择应基于数据量、搜索的复杂性以及项目的性能和维护要求。

Laravel 中的实时搜索

当你开始使用 Laravel 并且需要…… 实时搜索引擎,响应迅速面对上千种可能的解决方案,很容易迷失方向:使用 fetch 的 AJAX、jQuery、Alpine.js、使用 Algolia 或 Meil​​isearch 的 Scout、前端过滤等等。好消息是,Laravel 生态系统已经提供了几乎所有你需要的东西,可以让你轻松搭建一个流畅快速的搜索系统。

本文将介绍如何组装 Laravel 中不同类型的实时搜索从经典的 AJAX 自动补全到使用 Laravel Scout 和 Algolia、Meilisearch 等搜索引擎进行全文搜索,甚至直接使用数据库或 Elasticsearch,应有尽有。此外,当数据量较小时,您还可以使用 Alpine.js 等轻量级方案直接在浏览器中进行数据过滤。

Laravel 中的实时搜索是什么?它的基本工作原理是什么?

实时搜索背后的理念是: 当用户在文本字段中输入内容时触发查询后,无需重新加载页面即可更新结果。从技术角度来看,这涉及三个关键组件:Laravel 后端、浏览器 JavaScript 以及 JSON 格式的数据交换。

一方面, Laravel 充当服务器层。 它负责接收请求、解析搜索参数(输入的文本)、查询数据库,并返回结构化的响应,通常以 JSON 格式返回。该响应可以指示成功、错误或未找到结果。

在另一端, JavaScript 负责监听用户事件。 在搜索框中,向后端发送异步请求(AJAX),并在不刷新浏览器的情况下将返回的数据显示在页面上。这可以通过原生 Fetch、jQuery AJAX 或像 Alpine.js 这样的小型响应式库来实现。

有了这个基本机制,你可以从……开始构建 简单的自动完成功能,包含少量记录,直至高级全文搜索引擎,具备相关性、分页和过滤器功能,并由 Laravel Scout 等库和针对搜索优化的外部搜索引擎提供支持。

基本实时搜索引擎的模型、路由和控制器

在深入学习 JavaScript 之前,你需要确保 Laravel 部分组织良好: 一个用于搜索的 Eloquent 模型、清晰的路径和一个专用控制器 实时管理搜索逻辑。

第一步是创建一个 Eloquent 模型来表示你要搜索的表格。假设有一个国家/地区列表的表格,以及一个名为 `countries` 的模型。 国家 非常简单,不带时间戳,并且允许批量分配:

一个用于搜索的最小 Eloquent 模型示例:

namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;

class Pais extends Model
{
use HasFactory;
protected $guarded = [];
public $timestamps = false;
}

这里指出的是模型 Pais 位于标准的 Laravel 命名空间中。它继承自 Model 类,允许你通过空数组的方式,使用 create() 方法为任何字段赋值。通过设置 public $timestamps = false 来禁用时间戳,可以避免因表中缺少 created_at 和 updated_at 列而导致的问题。

下一步是定义 负责处理搜索引擎显示和 AJAX 请求的路由一种非常常见的方案是将用于显示视图的 GET 路由和用于接收实时查询的 POST 路由结合起来:

use Illuminate\Support\Facades\Route;
use App\Http\Controllers\BuscadorController;

Route::get('/', function () {
return view('welcome');
});

Route::get('buscador', [BuscadorController::class, 'index']);
Route::post('buscador', [BuscadorController::class, 'buscar']);

根路由返回欢迎页面,而 URL /search 保留用于搜索功能控制器的 index() 方法显示表单和搜索输入框,而 search() 方法处理从浏览器发送的异步请求。

在控制器中,您可以实现一种非常实用的模式: 准备一个默认的响应数组以应对错误。 只有当请求确实有效且查询执行无误时,才覆盖它。

控制器可能具有 相似的结构 对此:

namespace App\Http\Controllers;

use App\Models\Pais;
use Illuminate\Http\Request;

class BuscadorController extends Controller
{
public function index()
{
return view('welcome');
}

public function buscar(Request $request)
{
$response = [
'success' => false,
'message' => 'Hubo un error',
];

if ($request->ajax()) {
$data = Pais::where('nombre', 'like', $request->texto.'%')
->take(10)
->get();

$response = [
'success' => true,
'message' => 'Consulta correcta',
'data' => $data,
];
}

return response()->json($response);
}
}

此时你已经拥有 完整的后端周期:接收 AJAX 请求、检查请求类型(是否为 AJAX)、使用 WHERE LIKE 子句进行查询并限制结果 使用 `take(10)` 将请求数量控制在合理范围内,以避免数据库过载。响应始终以 JSON 格式发送,这大大简化了前端的工作。

Blade 视图和 JavaScript fetch 用于响应式搜索

模型、路径和控制器准备就绪后,就可以开始构建可见部分了: 包含搜索字段和用于显示结果的模块的表单以及负责在后台发出请求的 JavaScript 代码。

Blade视图可以非常简单,依赖于 CSRF 令牌 Laravel 会注入该函数来验证 POST 请求,并且该函数还位于一个方便使用的搜索输入框中:

<!DOCTYPE html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<strong><meta name="csrf-token" content="{{ csrf_token() }}"></strong>
<title>Laravel</title>
</head>
<body>

<form action="" method="post">
<input type="search" name="texto" id="buscar">
</form>

<div id="resultado"></div>

<script>
window.addEventListener('load', function () {
const buscar = document.getElementById('buscar');
const resultado = document.getElementById('resultado');

buscar.addEventListener('keyup', function () {
fetch('/buscador', {
method: 'post',
body: JSON.stringify({ texto: buscar.value }),
headers: {
'Content-Type': 'application/json',
'X-Requested-With': 'XMLHttpRequest',
'X-CSRF-Token': document.head.querySelector('[name~="csrf-token"][content]').content,
},
})
.then(response => response.json())
.then(data => {
let html = '';
if (data.success) {
html += '<ul>';
for (let i in data.data) {
html += '<li>' + data.data[i].nombre + '</li>';
}
html += '<ul>';
} else {
html += 'No existen resultados';
}
resultado.innerHTML = html;
});
});
});
</script>

</body>
</html>

在这个例子中,脚本 监听搜索输入框的 keyup 事件每次按键都会触发向 /search 路径发送一个获取请求。字段的当前文本以 JSON 格式发送,并包含 X-Requested-With 等关键标头,以表明这是 AJAX 请求,同时还包含 CSRF 令牌以绕过 Laravel 的原生保护机制。

当响应到达时,它会被转换为 JSON 格式并动态生成。 一个包含结果的小型 HTML 列表或者,当查询未返回任何数据时,显示类似“未找到结果”的消息。所有这些操作都无需重新加载页面,对用户来说非常自然。

这种模式可以通过添加一些小的用户体验细节来进一步完善,例如添加一个 延迟(防抖) 在按键之间显示加载指示器或处理网络错误,以防止出现故障时界面出现冻结现象。

使用 Laravel 和 AJAX 以及 jQuery 进行实时搜索

虽然现在fetch已经获得了很大的发展, jQuery AJAX 仍然非常流行 在遗留项目或已经实现该功能的团队中,思路完全相同:捕获用户输入的内容,发出异步请求,然后刷新 DOM。

在 Laravel 中使用 jQuery 进行实时搜索的典型工作流程通常包括以下基本步骤: 定义特定路由,创建专用控制器,构建带有搜索输入的 Blade 视图 最后,添加 jQuery 代码,以便在输入时触发 AJAX。

这个过程是这样的:当用户开始输入时, jQuery 向服务器发送查询 使用搜索字符串,Laravel 会过滤数据库中的信息,返回包含匹配结果的 JSON,然后 jQuery 会更新页面上的 HTML 容器以反映匹配结果,所有这些都只需几毫秒即可完成。

使用 jQuery 的优势在于: 它基本概括了 AJAX 的语法。 如果你已经在项目中安装了该库,那么阅读起来就非常简单。但是,如果你可以使用现代 JavaScript 和原生 fetch,那么你添加的额外依赖项可能就没必要了。

使用 Alpine.js 在前端实现实时过滤和搜索

当要显示的数据量相对较小时(例如, 少于 50 件),但并非总是值得搭建一个具有复杂搜索功能的后端。在这种情况下,一个非常便捷的选择是 使用 Alpine.js 直接在浏览器中进行过滤无需在用户输入时向服务器发出请求。

其思路是预先计算每个元素的搜索字符串(例如,名称、描述和类别,全部小写),将其存储在 data-search-text 属性中,然后让 Alpine.js 处理其余部分。 根据文本内容显示或隐藏元素 在搜索栏中。

Alpine.js 组件可以具有类似这样的结构: 筛选项

{
search: '',
hasResults: true,
selectedValue: '',
init() {
this.$watch('search', () => this.filterItems());
this.$nextTick(() => this.$refs.searchInput?.focus());
},
filterItems() {
const searchLower = this.search.toLowerCase().trim();
const cards = this.$el.querySelectorAll('.item-card');
let visibleCount = 0;

cards.forEach(card => {
const text = card.dataset.searchText || '';
const isVisible = searchLower === '' || text.includes(searchLower);
card.style.display = isVisible ? '' : 'none';
if (isVisible) visibleCount++;
});

this.hasResults = visibleCount > 0;
},
}

在视图中,每张卡片或每行数据都会携带一个属性。 data-search-text 文本已预先准备好,格式为小写因此,过滤过程简化为 JavaScript 中的 includes() 函数,对于短列表来说速度非常快:

<input type="search" x-model="search" x-ref="searchInput" placeholder="Buscar..." />
<div>
<div class="item-card" data-search-text="formulario contacto simple">
<h3>Formulario de contacto</h3>
<p>Formulario de contacto simple</p>
</div>
</div>

此外,您可以仅在以下情况下显示空状态块: 当前搜索词没有结果。邀请用户修改文本或通过按钮清除字段,该按钮会将搜索重置为空字符串。

这种方法具有明显的优势: 搜索过程中没有服务器调用。交互几乎是瞬时的,逻辑高度本地化,易于调试。它非常适合用于快速选择器、项目选择模态框或嵌入 Laravel 页面中的小型目录。

Laravel Scout:使用专用引擎进行全文搜索

当事情变得严重,你需要 快速、相关且可扩展的全文搜索在 Laravel 中,Laravel Scout 是自然而然的选择。Scout 是一个集成层,它允许你通过外部控制器轻松地将 Eloquent 模型与 Algolia、Meilisearch 等搜索引擎、你自己的数据库、内存集合,甚至是 Elasticsearch 连接起来。

要开始使用 Scout,通常的做法是: 创建一个新的 Laravel 项目或重用一个现有的 Laravel 项目要启动它,请使用 Docker(例如,配合 Laravel Sail),然后使用 Composer 安装库。安装完成后,发布 scout.php 配置文件,并根据您要使用的驱动程序调整环境变量。

典型的工作流程是使用 Composer 安装 Scout,发布其配置, 使用 SCOUT_QUEUE=true 激活索引队列 在 .env 文件中,确保资源密集型操作在后台处理,从而提升应用程序的响应速度。此外,必须确保 DB_HOST 指向您正在使用的数据库,如果您使用的是 Docker 容器,这一点尤为重要。

模特若想参加 Scout 的选拔活动,必须满足以下条件: 要将其明确标记为可搜索,请添加 Searchable 特性。例如,如果您有一个 Train 模型,它表示一个包含 title 字段的火车表,您可以这样定义它:

namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use Laravel\Scout\Searchable;

class Train extends Model
{
use Searchable;

protected $fillable = ['title'];

public function searchableAs()
{
return 'trains_index';
}
}

searchableAs 方法允许 自定义搜索引擎中的索引名称Scout 不会使用从模型派生的默认名称,而是会接管后续操作。接下来,Scout 会根据所选驱动程序,处理与远程或本地索引的创建、更新和删除操作的同步。

Laravel Scout 与 Algolia:闪电般快速的 SaaS 搜索

Algolia 是一家专注于 SaaS 服务的公司。 提供对海量数据进行快速且相关的搜索它有一个用于管理索引、相关性规则、同义词等的 Web 面板,并且通过 Scout 和官方 PHP 客户端与 Laravel 集成得非常好。

要将 Algolia 与 Scout 结合使用,您需要使用 Composer 安装其 PHP 客户端,并在 .env 文件中注册您的凭据(应用程序 ID 和管理员 API 密钥)。 设置 SCOUT_DRIVER=algolia 指示 Scout 使用此引擎。您可以从 Algolia 控制面板获取应用程序 ID 和管理密钥。

环境配置完成后,您可以使用以下方法: Train::search('text')->paginate(6) 直接在控制器中对索引字段执行搜索,以分页 Eloquent 格式接收结果,准备将其传递给 Blade 视图。

例如你可以拥有一个控制器 指数 列出所有列车,或者如果收到 titlesearch 参数则执行搜索,以及一个用于将新列车插入索引的 create 方法:

public function index(Request $request)
{
if ($request->has('titlesearch')) {
$trains = Train::search($request->titlesearch)->paginate(6);
} else {
$trains = Train::paginate(6);
}

return view('Train-search', compact('trains'));
}

public function create(Request $request)
{
$this->validate($request, ['title' => 'required']);
Train::create($request->all());
return back();
}

在相应的视图中,您可以组合 新列车登记表 还有一个包含标题搜索字段的 GET 表单,提交后即可触发搜索。然后,您只需遍历列车集合,并利用 Laravel 生成的分页链接,将它们的字段显示在表格中即可。

利用 Meil​​isearch、数据库和馆藏进行侦察

如果您不想使用外部服务, Meilisearch 是一个开源搜索引擎。 您可以将其部署在本地或您的基础架构上。Scout 与 Meil​​isearch 的集成方式与 Algolia 非常相似,只需更改驱动程序并将 MEILISEARCH_HOST 和 MEILISEARCH_KEY 变量添加到 .env 文件即可。

要使用它,您需要安装 Meil​​isearch PHP 客户端并进行调整 SCOUT_DRIVER=meilisearch 并将 MEILISEARCH_HOST 指向实例 URL(例如,http://127.0.0.1:7700)。如果您之前已有记录,可以使用命令 `php artisan scout:import "App\Models\Train"` 对其进行索引,以便引擎可以访问这些记录。

在规模较小或中等的应用场景中,您也可以选择 侦察兵驾驶员数据库这会利用 MySQL 或 PostgreSQL 数据库上的全文索引和 LIKE 命令。在这种情况下,您不需要外部服务;只需将 SCOUT_DRIVER 设置为 database,Scout 即可使用数据库本身作为其搜索引擎。

另一个有趣的选择是 驱动程序集合,它处理内存中的 Eloquent 集合。该引擎使用 WHERE 子句和集合过滤来筛选结果,并且兼容 Laravel 支持的任何数据库。您可以使用 `SCOUT_DRIVER=collection` 来激活它,或者通过调整 Scout 配置文件来进行更具体的设置。

使用 Explorer 与 Elasticsearch 集成

如果您的搜索需求涉及 处理海量数据和实时分析Elasticsearch 是一个经典的数据库管理工具。在 Laravel 生态系统中,将其与 Scout 集成的一种现代方法是使用 Explorer 控制器,它充当模型和 Elasticsearch 集群之间的桥梁。

为此,通常会使用 Docker,以及一个内容丰富的 docker-compose 文件,该文件除了包含典型的服务(Laravel、MySQL、Redis、Meilisearch 等)之外, Elasticsearch 和 Kibana 容器然后通过 Composer 安装 jeroen-g/explorer 包,并发布其配置文件以指示应该索引哪些模型。

在 config/explorer.php 文件中,您可以通过添加以下代码在 indexes 键下注册您的模型: App\Models\Train::class此外,您需要在 .env 文件中将 Scout 驱动程序更改为 elastic,将 SCOUT_DRIVER=elastic 设置为 Elastic,以便所有内容都指向 Elasticsearch。

在 Train 模型中,必须实现 Explored 接口并重写该方法。 可映射它定义了要发送到索引的字段映射。一个简单的示例是:

use JeroenG\Explorer\Application\Explored;
use Laravel\Scout\Searchable;

class Train extends Model implements Explored
{
use Searchable;

protected $fillable = ['title'];

public function mappableAs(): array
{
return [
'id' => $this->id,
'title' => $this->title,
];
}
}

从现在开始, 您可以使用相同的 Scout 界面在 Elasticsearch 上发起搜索。受益于极低的响应时间和该引擎的全部查询能力,但又无需离开 Laravel 生态系统。

所有这些方法——从使用 fetch 或 jQuery 的基本自动完成功能,到使用 Alpine.js 的前端过滤,再到使用 Laravel Scout 和各种驱动程序的全文搜索—— Laravel 为您提供了丰富的选项来实现实时搜索。 根据您的项目规模、所需性能以及您愿意维护的基础设施量身定制。

  视频游戏编程:如何入门 - 分步指南