# 文章詳情頁
## 分析
* 列表頁和詳情頁只有兩個頁面公用了一部分的內容 可以使用 if 判斷的方式 使用同一個視圖和控制器
* 左側菜單的邏輯和頁眉的邏輯差不多 代碼可以共用 可以寫到模型里面
* 列表頁的分頁可以使用`laravel`框架自帶的`bootstrap`分頁
* 觀察發現 原網站詳情頁 單頁面(一級分類下的網站)不會顯示原標題 也不會顯示發布時間 這里我們統一處理為 單頁面還是顯示原標題 不顯示時間
## 路由
位置 `routes/web.php`
~~~php
Route::get('/categories/{article_category}.html', [ArticlesController::class, 'category'])
->name('articles.category');
Route::get('/articles/{article}.html', [ArticlesController::class, 'show'])
->name('articles.show');
~~~
## 控制器
位置 `app/Http/Controllers/ArticlesController.php`
~~~php
public function show()
{
return view('index.articles.show');
}
public function category()
{
return view('index.articles.show');
}
~~~
### 填充數據
~~~php
public function parent()
{
return $this->belongsTo(self::class, 'parent_id', 'id');
}
//獲取頂級ID
public function getTopParentId()
{
$category = self::pluck('parent_id', 'id');
$id = $this->id;
while ($category[$id]) {
$id = $category[$id];
}
return $id;
}
public function getNav()
{
$top_category_id = $this->getTopParentId();
$articles_data = self::find($top_category_id)->articles;
$categories_data = self::find($top_category_id)->children;
return $this->handle_category_data($articles_data, $categories_data);
}
public function handle_category_data($articles_data, $categories_data)
{
$articles = [];
$categories = [];
foreach ($articles_data as $k => $article) {
$articles[$k]['title'] = $article->title;
$articles[$k]['sort'] = $article->sort;
$articles[$k]['url'] = route('articles.show', ['article' => $article->id]);
}
foreach ($categories_data as $k => $category) {
$categories[$k]['title'] = $category->title;
$categories[$k]['sort'] = $category->order;
$categories[$k]['url'] = route('articles.category', ['article_category' => $category->id]);
}
$item = array_merge($articles, $categories);
array_multisort(array_column($item, 'sort'), SORT_ASC, $item);
return $item;
}
~~~
> 這里使用了`while`循環來獲取最上級 `$category`數據類似 `[1 => 0,...,5 => 1,...,13 => 5,]`
修改 `app/Http/ViewComposers/ArticleCategoryComposer.php`
~~~php
public function compose(View $view)
{
$nav = ArticleCategory::where('parent_id', 0)
->orderBy('order', 'desc')
->get();
//將文章和分類合并 并排序
if ($nav->isNotEmpty()) {
$articleCategoryModel = new ArticleCategory();
foreach ($nav as $article_category) {
$article_category->son = $articleCategoryModel->handle_category_data($article_category->articles, $article_category->children);
$articles_footer = $article_category->articles()
->where('is_footer', 1)
->get();
$article_category->son_footer = $articleCategoryModel->handle_category_data($articles_footer, $article_category->children);
}
}
$view->with('nav', $nav);
}
~~~
> 處理導航數據的方法 做成了公共方法
繼續修改 `app/Http/Controllers/ArticlesController.php`
~~~php
public function show(Article $article)
{
//左側導航
$nav = $article->category->getNav();
//面包屑
$mbx['level_1']['url'] = $nav[0]['url'];
if ($article->category->parent_id > 0) {
//二級分類下的文章
$mbx['level_1']['title'] = $article->category->parent->title;
$mbx['level_2'] = ['title' => $article->category->title, 'url' => route('articles.category', ['article_category' => $article->category->id])];
} else {
//一級分類下的文章
$mbx['level_1']['title'] = $article->category->title;
$mbx['level_2'] = ['title' => $article->title, 'url' => route('articles.show', ['article' => $article->id])];
}
return view('index.articles.show', ['nav' => $nav, 'mbx' => $mbx, 'row' => $article]);
}
public function category(ArticleCategory $articleCategory)
{
//左側導航
$nav = $articleCategory->getNav();
//面包屑
$mbx['level_1']['url'] = $nav[0]['url'];
//二級分類下的文章
$mbx['level_1']['title'] = $articleCategory->parent->title;
$mbx['level_2'] = ['title' => $articleCategory->title, 'url' => route('articles.category', ['article_category' => $articleCategory->id])];
//數據分頁
$articles = Article::where('category_id', $articleCategory->id)
->orderBy('created_at', 'desc')
->paginate(15);
return view('index.articles.show', ['list' => $articles, 'nav' => $nav, 'mbx' => $mbx, 'row' => $articleCategory]);
}
~~~
> 面包屑的數據 是根據實際情況 組裝的代碼 首頁(固定)》 一級分類(鏈接為下一級的第一項)》 二級分類、文章詳情
視圖 `resources/views/index/articles/show.blade.php`
~~~php
@extends('/index/layouts.app')
@section('title',$row->title)
@section('keywords', $row->keywords)
@section('description', $row->abstract)
@section('css')
@stop
@section('content')
<div class="page" style="padding:30px 0;">
<div class="narclass">
<ul>
@foreach($nav as $category)
<li class="cur">
<a href="{{ $category['url'] }}" title="{{ $category['title'] }}">{{ $category['title'] }}</a>
</li>
@endforeach
</ul>
</div>
<div class="right">
<div class="posit">當前位置:首頁 ?
<a href="{{ $mbx['level_1']['url'] }}"
title="{{ $mbx['level_1']['title'] }}">{{ $mbx['level_1']['title'] }}</a> ?
<a href="{{ $mbx['level_2']['url'] }}"
title="{{ $mbx['level_1']['title'] }}">{{ $mbx['level_2']['title'] }}</a>
</div>
@if(request()->route()->named('articles.show'))
<div class="newXq">
<dt class="Xqtitle">{{ $row->title }}</dt>
@if ($row->category->parent_id > 0)
<dd class="Xqdate">發布于:{{ $row->created_at->format('Y-m-d') }}</dd>
@endif
{!! $row->content !!}
</div>
@else
<div class="pnews">
<dl>
@foreach($list as $article)
<dt class="ptitleB"><a
href="{{ route('articles.show',['article'=>$article->id]) }}">{{ $article->title }}</a>
</dt>
<dd class="pdate">發布于:{{ $article->created_at->format('Y-m-d') }}</dd>
@endforeach
</dl>
</div>
<div style="float: left;margin-top: 10px">
{{ $list->links() }}
</div>
@endif
</div>
</div>
@stop
@section('js')
@stop
~~~
使用`bootstrap`分頁 修改 `app/Providers/AppServiceProvider.php`
~~~php
public function boot()
{
Paginator::useBootstrapFour();
}
~~~
下載 [bootstrap](https://github.com/twbs/bootstrap/releases/download/v5.1.3/bootstrap-5.1.3-dist.zip)
頁面引入文件
`resources/views/index/layouts/app.blade.php`
~~~php
<link href="{{ asset('static/css/bootstrap.min.css') }}" rel="stylesheet" type="text/css" />
~~~
此時分頁已經顯示出來了 但是是英文 我們現在可以下載中文包 [laravel-lang](https://github.com/overtrue/laravel-lang)
安裝
`composer require "overtrue/laravel-lang:~6.0"`
這個時候顯示的就是中文
回到首頁 發現中間樣式亂了 是因為添加的 `bootstrap` 導致的 修改
`public/static/css/style.css`
~~~css
.produ dl {
...
box-sizing: content-box;
}
~~~