第5.6章:通过 Blade + Fetch 显示数据
学习时间: 50分钟
1. 混合方法:两全其美
我们可以通过两种方式构建页面:
- 完整服务器端渲染 (SSR): Laravel 生成所有 HTML,包括行星列表。对于任何更新(删除、添加),页面都会完全重新加载。
- 完整客户端渲染 (CSR): Laravel 返回一个空的 HTML“外壳”,然后 JavaScript 从 API 请求所有数据并在客户端渲染它们。(这是单页应用程序 - SPA 的方法)。
我们的选择是混合方法:
- 首次加载 (SSR): Laravel 立即返回带有预先准备好的行星列表的页面。这速度快,对 SEO 友好。用户立即看到内容。
- 后续操作 (CSR): JavaScript 捕获用户操作(按钮点击)并与 API 交互,仅更新页面所需部分,而无需完全重新加载。
💡 宇宙类比:
当你进入舰桥时,指挥中心(SSR)立即给你一张主导航图。它已经在你手中,无需等待。但随后你会在你的平板电脑上激活“实时模式”(CSR),它将开始从卫星接收实时更新,重新绘制你地图上的物体。
2. 步骤 1:准备页面
我们将使用我们的行星列表页面 resources/views/planets/index.blade.php
。它已经能够显示从控制器传递的数据。现在我们将在其上添加通过 JS 工作控件。
添加“刷新列表”按钮和通知容器:
<div class="controls">
<h2>所有已知行星列表</h2>
<button id="refresh-btn">通过 API 刷新</button>
</div>
<div id="notification-area" class="notification"></div>
<hr>
{{-- 这个 div 将作为我们动态更新的容器 --}}
<div id="planet-list-container" class="planet-list">
{{-- 包含“子”视图,它渲染初始列表 --}}
@include('planets.partials.list', ['planets' => $planets])
</div>
请注意 @include('planets.partials.list', ...)
。我们将列表显示逻辑提取到一个单独的可重用文件中。
步骤 2:创建可重用“局部”视图 (Partial)
将重复的部分提取到单独的文件中是一个好习惯。
创建文件 resources/views/planets/partials/list.blade.php
:
@forelse($planets as $planet)
<div class="planet-card" id="planet-card-{{ $planet->id }}">
<h3>{{ $planet->name }}</h3>
<p>太阳系:{{ $planet->solar_system }}</p>
<p>直径:{{ number_format($planet->size_km, 0, '.', ' ') }} 公里</p>
<a href="{{ route('planets.show', $planet) }}">了解更多 →</a>
<button class="delete-btn" data-id="{{ $planet->id }}" data-url="{{ route('api.planets.destroy', $planet) }}">
退役
</button>
</div>
@empty
<p>数据库中没有行星。</p>
@endforelse
- 重要: 请注意,删除按钮的 URL 现在是为 API 路由生成的:
route('api.planets.destroy', $planet)
。为此,请确保在routes/api.php
中您有一个命名资源:Route::apiResource('planets', ...)->name('api.planets');
步骤 3:编写用于动态更新的 JavaScript
现在是最有趣的部分。我们将创建一个 JavaScript,它将通过按钮向 API 请求最新的行星列表并重新渲染它。
创建文件 public/js/planet-manager.js
并将其引入到 layouts/app.blade.php
中。
document.addEventListener('DOMContentLoaded', () => {
const refreshBtn = document.getElementById('refresh-btn');
const planetListContainer = document.getElementById('planet-list-container');
const notificationArea = document.getElementById('notification-area');
// 用于显示通知的函数
function showNotification(message, isError = false) {
notificationArea.textContent = message;
notificationArea.className = isError ? 'notification error' : 'notification success';
setTimeout(() => {
notificationArea.textContent = '';
notificationArea.className = 'notification';
}, 3000);
}
// 用于渲染单个行星卡的函数
function createPlanetCardHtml(planet) {
// 重要:我们生成与我们的 partial 视图相同的 HTML
return `
<div class="planet-card" id="planet-card-${planet.id}">
<h3>${planet.name}</h3>
<p>太阳系:${planet.solar_system}</p>
<p>直径:${new Intl.NumberFormat().format(planet.size_km)} 公里</p>
<a href="/planets/${planet.id}">了解更多 →</a>
<button class="delete-btn" data-id="${planet.id}" data-url="/api/planets/${planet.id}">
退役 (JS)
</button>
</div>
`;
}
// 用于请求和重新渲染行星列表的函数
async function fetchAndRenderPlanets() {
showNotification('正在从轨道卫星请求最新数据...');
try {
const response = await fetch('/api/planets', {
headers: { 'Accept': 'application/json' }
});
if (!response.ok) {
throw new Error('获取数据时发生网络错误。');
}
const planets = await response.json(); // Laravel 默认会为分页资源返回 { data: [...] }
planetListContainer.innerHTML = ''; // 清除旧列表
if (planets.data.length === 0) {
planetListContainer.innerHTML = '<p>数据库中没有行星。</p>';
} else {
planets.data.forEach(planet => {
const cardHtml = createPlanetCardHtml(planet);
planetListContainer.innerHTML += cardHtml;
});
}
showNotification('数据已成功更新!', false);
} catch (error) {
console.error('更新行星列表时出错:', error);
showNotification(error.message, true);
}
}
// 为按钮添加事件监听器
if (refreshBtn) {
refreshBtn.addEventListener('click', fetchAndRenderPlanets);
}
// 可以将上一章的删除逻辑移到这里,
// 以便所有 JS 都集中在一个地方。
});
3. 最终检查
- 启动服务器(
php artisan serve
或确保 Herd 正在运行)。 - 如果需要,重新创建数据库:
php artisan migrate:fresh --seed
。 - 在浏览器中打开
/planets
页面。- 您应该立即看到服务器生成的行星列表。
- 点击“通过 API 刷新”按钮。
- 您将看到加载通知。
- 列表应该会短暂消失并重新出现,但这次它将是基于从 API 获取的数据由 JavaScript 生成的。
您已成功实现混合模型!
巩固知识小测验
🚀 恭喜您完成第5章!
您已经从 Blade 基础知识学到了创建交互式混合页面的巨大进步。您学会了:
- 创建和使用 Blade 模板和布局。
- 组织用于 CRUD 操作的 Web 路由和控制器。
- 使用 CSRF 令牌保护 Web 表单和 AJAX 请求。
- 集成 JavaScript 以在不重新加载页面的情况下与 API 进行动态交互。
您的飞行控制中心已完全功能化、安全且交互性强。 您已准备好进入下一个重要阶段 — 将此方法与其他框架进行比较,并学习生产环境的最佳实践。