本文目录导读:

我来详细讲解一下 PHP 如何使用 Hotwire(Turbo + Stimulus)。
Hotwire 简介
Hotwire 是 Basecamp 开发的现代 Web 开发框架,包含:
- Turbo:处理页面导航和部分更新
- Stimulus:轻量级 JavaScript 框架
- Turbo Native:原生移动应用支持
PHP 集成方案
基础安装
# 使用 Composer 安装 composer require hotwired/turbo
配置 Laravel 项目
// config/turbo.php 配置文件示例
return [
'default' => [
'driver' => 'turbo',
],
'turbo' => [
'driver' => 'turbo',
'channel' => 'default',
],
];
在 Blade 模板中引入
<!-- layouts/app.blade.php -->
<!DOCTYPE html>
<html>
<head>@yield('title')</title>
<!-- Turbo 核心 -->
<script src="{{ asset('js/turbo.js') }}" defer></script>
<!-- Stimulus -->
<script src="{{ asset('js/stimulus.js') }}" defer></script>
@vite(['resources/js/stimulus.js', 'resources/js/app.js'])
</head>
<body>
@yield('content')
</body>
</html>
关键功能实现
Turbo Frame(页面局部更新)
<!-- 控制器方法 -->
public function index()
{
$users = User::paginate(10);
return view('users.index', compact('users'));
}
public function show(User $user)
{
return view('users.show', compact('user'));
}
<!-- users/index.blade.php -->
<div id="user-list" class="turbo-frame">
<h2>用户列表</h2>
<div class="users">
@foreach ($users as $user)
<div class="user-item">
<a href="{{ route('users.show', $user) }}" data-turbo-frame="user-detail">
{{ $user->name }}
</a>
</div>
@endforeach
</div>
{{ $users->links() }}
</div>
<!-- 详情区域 -->
<div id="user-detail" class="turbo-frame">
选择用户查看详情
</div>
Turbo Stream(实时更新)
<!-- 控制器 -->
public function store(Request $request)
{
$user = User::create($request->validated());
return response()
->view('users._user_item', ['user' => $user])
->header('Content-Type', 'text/vnd.turbo-stream.html');
}
<!-- _user_item.blade.php -->
<turbo-stream action="append" target="users-list">
<template>
<div class="user-item" id="user-{{ $user->id }}">
{{ $user->name }}
</div>
</template>
</turbo-stream>
Stimulus 集成
// resources/js/stimulus.js
import { Application, Controller } from "@hotwired/stimulus"
window.Stimulus = Application.start()
// 示例控制器
class FormController extends Controller {
static targets = ["name", "email"]
validate() {
if (this.nameTarget.value === '') {
this.element.classList.add('has-error')
event.preventDefault()
}
}
}
// 注册控制器
Stimulus.register("form", FormController)
<!-- 使用 Stimulus 控制器 -->
<form data-controller="form" action="{{ route('users.store') }}" method="POST">
<div>
<label>用户名</label>
<input type="text" name="name" data-form-target="name" data-action="submit->form#validate">
</div>
<div>
<label>邮箱</label>
<input type="email" name="email" data-form-target="email">
</div>
<button type="submit">创建用户</button>
</form>
Turbo Navigation(页面导航)
<!-- 视图中使用 Turbo 导航属性 -->
<a href="{{ route('users.index') }}"
data-turbo-action="advance"
data-turbo-frame="_top">
返回列表
</a>
<!-- 或使用 Turbo Visits -->
<script>
Turbo.visit('/users', { action: "replace" });
</script>
实时更新(WebSocket)
# 安装 Laravel Echo composer require laravel/echo pusher-http-laravel
// 控制器中使用 Turbo Stream
use Hotwired\Turbo\Broadcasters\Broadcaster;
public function broadcastUser(User $user)
{
Toast::success('用户创建成功')
->send();
TurboStream::append('users-list', 'users._user_item')
->broadcastToChannel('users-channel', $user);
}
最佳实践
错误处理
// 自定义异常处理器
class TurboExceptionHandler
{
public function render($request, Exception $exception)
{
if ($request->header('Turbo-Frame')) {
return response()
->view('errors.turbo', ['error' => $exception->getMessage()])
->setStatusCode(422);
}
return parent::render($request, $exception);
}
}
CSRF 保护
<!-- 在 Turbo Frame 中的表单需手动添加 -->
<form action="/users" method="POST">
@csrf
<input type="hidden" name="turbo_stream" value="true">
<!-- 表单字段 -->
</form>
认证系统集成
// 处理认证后的 Turbo 响应
public function authenticate(Request $request)
{
if (Auth::attempt($request->only('email', 'password'))) {
if ($request->expectsTurboFrame()) {
return redirect()->to('/dashboard')->withTurboStream();
}
return redirect()->to('/dashboard');
}
}
部署注意事项
# Vite 配置文件
// vite.config.js
export default {
plugins: [
laravel({
input: ['resources/css/app.css', 'resources/js/app.js'],
refresh: true,
}),
],
build: {
rollupOptions: {
external: ['@hotwired/turbo', '@hotwired/stimulus']
}
}
}
常见问题解决
页面刷新问题
<!-- 在特定页面禁用 Turbo -->
<body data-turbo="false">
<!-- 页面内容 -->
</body>
兼容性问题
// 检测 Turbo 是否生效
document.addEventListener('turbo:load', () => {
console.log('Turbo 已加载');
});
性能优化
// 使用部分渲染减少请求
public function showPartial(User $user, $partial = 'info')
{
if ($partial === 'info') {
return view('users.partials.info', compact('user'))->withTurboFrame('user-info');
}
}
Hotwire 在 PHP 中使用时:
- 核心是 Turbo 和 Stimulus 的组合
- 支持渐进式增强,可以选择性使用
- 与 Laravel 集成最佳,但也可以用于其他 PHP 框架
- 注意处理 CSRF、错误和认证等安全问题
- 可以利用 Turbo Stream 实现实时更新功能
如果你有更具体的需求(比如特定场景的实现),欢迎告诉我,我可以提供更详细的示例!