#导航菜单动态生成 + 页面排序
## 1.导航菜单动态生成
### (1)目标
实现前台网站根据后台页面管理中的页面列表,动态生成导航菜单。
### a。修改 PageController
**文件路径**:`app/Http/Controllers/Frontend/PageController.php`
**修改 `home` 方法**:
```php
public function home()
{
$page = Page::where('is_home', true)->first();
if (!$page) {
$page = Page::first();
}
$pages = Page::where('status', true)->get();
$html = $this->renderService->render($page);
return view('frontend.layouts.app', [
'title' => $page->title,
'siteName' => $this->getSiteName(),
'siteKeywords' => $this->getSiteKeywords(),
'siteDescription' => $this->getSiteDescription(),
'pages' => $pages,
'content' => $html,
]);
}
```
**同样修改 `show` 方法**。
### b。修改 PageRenderService
**文件路径**:`app/Services/PageRenderService.php`
**修改 `wrapWithLayout` 方法**:
```php
protected function wrapWithLayout(Page $page, string $content): string
{
$site = \App\Models\Site::first();
$pages = \App\Models\Page::where('status', true)->get();
return view('frontend.layouts.app', [
'title' => $page->title,
'siteName' => $site->site_name ?? '好站站',
'siteKeywords' => $site->site_keywords ?? '',
'siteDescription' => $site->site_description ?? '',
'pages' => $pages,
'content' => $content,
])->render();
}
```
### c。修改前台布局模板
**文件路径**:`resources/views/frontend/layouts/app.blade.php`
**添加导航栏 HTML**:
```blade
<nav class="navbar">
<div class="nav-container">
<a href="/" class="logo">{{ $siteName }}</a>
<ul class="nav-menu">
@foreach($pages as $page)
<li class="nav-item">
<a href="/{{ $page->slug }}.html" class="nav-link">{{ $page->title }}</a>
</li>
@endforeach
</ul>
</div>
</nav>
```
**添加当前页面高亮(JavaScript)**:
```blade
<script>
const currentPath = window.location.pathname;
document.querySelectorAll('.nav-link').forEach(link => {
if (link.getAttribute('href') === currentPath) {
link.classList.add('active');
}
});
</script>
```
**添加导航栏样式**:
```css
.navbar {
background: #fff;
border-bottom: 1px solid #e8e8e8;
position: sticky;
top: 0;
z-index: 100;
}
.nav-container {
max-width: 1200px;
margin: 0 auto;
padding: 0 20px;
display: flex;
justify-content: space-between;
align-items: center;
height: 64px;
}
.logo {
font-size: 20px;
font-weight: bold;
color: #1890ff;
text-decoration: none;
}
.nav-menu {
display: flex;
list-style: none;
gap: 30px;
margin: 0;
padding: 0;
}
.nav-link {
color: #333;
text-decoration: none;
transition: color 0.3s;
}
.nav-link:hover {
color: #1890ff;
}
.nav-link.active {
color: #1890ff;
font-weight: bold;
}
@media (max-width: 768px) {
.nav-menu { gap: 15px; }
}
```
### d。遇到的问题
| 问题 | 原因 | 解决 |
|------|------|------|
| `Undefined variable $pages` | `PageRenderService` 没有传递 `$pages` | 在 `wrapWithLayout` 中添加查询 |
| 静态页面高亮不生效 | PHP 方法无法在静态页面执行 | 改用 JavaScript 实现 |
---
## 2.页面排序功能
### (1)目标
为页面管理添加排序功能,后台手动调整顺序,前台按顺序显示导航菜单。
### a。添加数据库字段
**执行命令**:
```bash
php artisan make:migration add_sort_order_to_pages_table
```
**迁移文件**:
```php
public function up()
{
Schema::table('pages', function (Blueprint $table) {
$table->integer('sort_order')->default(0)->after('status');
});
}
```
**执行迁移**:
```bash
php artisan migrate --force
```
### b.修改 Page 模型
**文件路径**:`app/Models/Page.php`
```php
protected $fillable = [
'site_id',
'title',
'slug',
'is_home',
'status',
'sort_order', // 新增
];
```
### c.修改后台控制器
**文件路径**:`app/Http/Controllers/Admin/PageController.php`
**修改 `update` 方法**:
```php
$validated = $request->validate([
'title' => 'string|max:255',
'slug' => 'string|max:255|unique:pages,slug,' . $id,
'is_home' => 'boolean',
'status' => 'boolean',
'sort_order' => 'integer', // 新增
]);
```
### d。修改前台排序
**文件路径**:`app/Http/Controllers/Frontend/PageController.php`
```php
$pages = Page::where('status', true)->orderBy('sort_order')->get();
```
**文件路径**:`app/Services/PageRenderService.php`
```php
$pages = \App\Models\Page::where('status', true)->orderBy('sort_order')->get();
```
### e。修改前端页面管理
**文件路径**:`resources/js/admin/views/Pages.vue`
**表格添加排序列**:
```vue
<el-table-column prop="sort_order" label="排序" width="120">
<template #default="{ row }">
<el-input-number
v-model="row.sort_order"
size="small"
:min="0"
:max="999"
controls-position="right"
@change="(val) => updateSortOrder(row, val)"
/>
</template>
</el-table-column>
```
**添加更新方法**:
```typescript
const updateSortOrder = async (row: any, val: number) => {
try {
await axios.put(`/api/admin/pages/${row.id}`, { sort_order: val });
await pageStore.fetchPages();
ElMessage.success('排序已更新');
} catch (error) {
ElMessage.error('更新失败');
await pageStore.fetchPages();
}
};
```
**编辑表单添加排序字段**:
```vue
<el-form-item label="排序" prop="sort_order">
<el-input-number v-model="form.sort_order" :min="0" :max="999" />
</el-form-item>
```
**表单数据增加 `sort_order`**:
```typescript
const form = reactive({
title: '',
slug: '',
is_home: false,
status: false,
sort_order: 0,
});
```
### f。修改 Store
**文件路径**:`resources/js/admin/stores/page.ts`
```typescript
pages.value = response.data.sort((a, b) => (a.sort_order || 0) - (b.sort_order || 0));
```
### g。遇到的问题
| 问题 | 原因 | 解决 |
|------|------|------|
| 前端发送 `sort_order`,数据库没更新 | `$fillable` 中没有 `sort_order` | 在模型中添加 |
---
## 3。验证结果
| 验证项 | 结果 |
|--------|------|
| 导航栏显示所有页面 | ✅ |
| 点击菜单跳转 | ✅ |
| 当前页面高亮 | ✅ |
| 后台表格显示排序输入框 | ✅ |
| 修改排序值 | ✅ |
| 前台菜单按新顺序显示 | ✅ |