選單項目:從手刻到程式產生
搞定了各頁面輸出,現在回來處理每個頁面都有使用的網站功能:網站選單。
Moderna 主題的選單範例示範了如何透過樣式指定建立具備三階層次的樹狀選單。
<nav id="navbar" class="navbar">
<ul>
<li><a class="" href="index.html">Home</a></li>
<li><a href="about.html">About</a></li>
<li><a href="services.html">Services</a></li>
<li><a href="portfolio.html">Portfolio</a></li>
<li><a href="team.html">Team</a></li>
<li><a class="active" href="blog.html">Blog</a></li>
<li class="dropdown"><a href="#"><span>Drop Down</span> <i class="bi bi-chevron-down"></i></a>
<ul>
<li><a href="#">Drop Down 1</a></li>
<li class="dropdown"><a href="#"><span>Deep Drop Down</span> <i class="bi bi-chevron-right"></i></a>
<ul>
<li><a href="#">Deep Drop Down 1</a></li>
<li><a href="#">Deep Drop Down 2</a></li>
<li><a href="#">Deep Drop Down 3</a></li>
<li><a href="#">Deep Drop Down 4</a></li>
<li><a href="#">Deep Drop Down 5</a></li>
</ul>
</li>
<li><a href="#">Drop Down 2</a></li>
<li><a href="#">Drop Down 3</a></li>
<li><a href="#">Drop Down 4</a></li>
</ul>
</li>
<li><a href="contact.html">Contact Us</a></li>
</ul>
<i class="bi bi-list mobile-nav-toggle"></i>
</nav><!-- .navbar -->
如果架構規劃得當,規模不是非常大的網站,相信三階層次(larablog 的情況一階就夠了)已經很夠用。選單獨立出來成為 Blade template 檔案然後引入到其他頁面中,只要修改單一檔案就能套用至整個網站。
那麼有沒有可能將選單的 HTML 碼改為 PHP/Laravel 程式輸出,不論選單項目怎改動都不需改程式碼呢?答案是可以的,透過 Voyager 可以建立網站選單,接著在 Blade template 中引入即可。
在 Voyager 建立網站選單
-
登入 Voyager,選擇側邊選單「工具 - 側邊欄管理」。
-
畫面中看到的「admin」項目就是現在 Voyager 所使用的選單群組,點選上方「添加」項目增加新選單。
-
輸入新選單群組名稱,因為是做為網站選單我輸入「frontend」,按「保存」完成新增。
-
回到側邊欄列表後點選「frontend」列右方的「建構器」項目。
-
點選「新側邊欄項目」新增選單項目。
-
在 modal 視窗輸入選單項目資料後按「保存」儲存,各項目說明如下:
- 側邊欄項目的標題:輸入選單項目名稱。
- 連接類型:選擇「靜態 URL」時在下方「側邊欄項目的 URL」欄位輸入靜態網址;「動態路由」則在下方「側邊欄項目的路由」輸入路由別名,如果要輸入參數就在「路由參數(如果存在)」欄位輸入。
- 側邊欄項目的字體圖標類:在編輯 Voyager 選單時才會用到的項目,本次略過。
- RGB 或 Hex 顏色:與「側邊欄項目的字體圖標類」的情況相同,略過。
- 打開:設定瀏覽器打開此連結的方式,站內連結使用「在相同標籤 / 窗口打開」;連外網站建議選擇「新標籤頁 / 窗口打開」。
建立完成的選單項目可以拖曳調整順序,如果要建立樹狀選單則是將作為子選單的項目移到親項目的下方後往右邊拖曳一些,要還原只要往左拖曳即可。
將建立好的選單集合發佈到前端
顯示網站選單的 Blade template 檔案位於 /resources/views/layout/header.blade.php
,從 <nav>
到 </nav>
為止的 HTML 碼以 {{ menu('frontend') }}
取代。
<!-- ======= Header ======= -->
<header id="header" class="fixed-top d-flex align-items-center ">
<div class="container d-flex justify-content-between align-items-center">
<div class="logo">
<h1 class="text-light"><a href="index.html"><span>Moderna</span></a></h1>
<!-- Uncomment below if you prefer to use an image logo -->
<!-- <a href="index.html"><img src="assets/img/logo.png" alt="" class="img-fluid"></a>-->
</div>
{{ menu('frontend') }}
</div>
</header><!-- End Header -->
顯示跑版了嗎?別擔心,加上 Blade template 套用
在網站畫面是看到在 Voyager 建立的選單群組及項目了,不過顯示方式不怎麼好...
這是因為 Voyager 建立的選單項目僅有 <ul> ~ <li>
結構,尚未套用 CSS 樣式,因此需再透過傳遞第二個參數:引用的 Blade template 項目,使用其視覺規劃。
在 resources/views
資料夾下新增 menu
資料夾,在其內新增 menu_layout.php
,比照 Moderna 主題的選單範例輸入標籤格式,再加上 @foreach - @endforch
陣列輸出選單項目。
以下程式碼參考哥布林老師〈【Laravel實戰】部落格從零開始實作攻略 #by Voyager〉影片內容為基礎,增加第三層選單項目顯示規劃,在實務上建議選單層次不要超過三層,會讓架構變得過於複雜也不方便操作。
<nav id="navbar" class="navbar">
<ul>
@foreach($items as $item)
@php
$sub2items = $item->children;
@endphp
@if(isset($sub2items) && count($sub2items) > 0)
<li class="dropdown"><a href="#">{{$item->title}}<i class="bi bi-chevron-down"></i></a>
<ul>
@foreach($sub2items as $sub2item)
@php
$sub3items = $sub2item->children;
@endphp
@if(isset($sub3items) && count($sub3items) > 0)
<li class="dropdown"><a href="#">{{$sub2item->title}}<i class="bi bi-chevron-down"></i></a>
<ul>
@foreach($sub3items as $sub3item)
<li><a href="{{$sub3item->link()}}">{{$sub3item->title}} </a></li>
@endforeach
</ul>
</li>
@else
<li><a href="{{$sub2item->link()}}">{{$sub2item->title}} </a></li>
@endif
@endforeach
</ul>
</li>
@else
<li><a href="{{$item->link()}}">{{$item->title}}</a></li>
@endif
@endforeach
</ul>
<i class="bi bi-list mobile-nav-toggle"></i>
</nav>
回到 header.blade.php
,將 {{ menu('frontend') }}
修改為 {{ menu('frontend', 'menu.menu_layout) }}
後存檔,完成樣式套用。
在 Voyager 建立作者簡介
在文章全文頁面中,文章內文下方有個作者簡介的區塊,顯示著作者照片、社群網站帳號及作者簡介,現在回頭將這個區塊改為程式輸出。提醒一下,在〈larablog 建構日誌:專案資料表〉時就已經建立了 user_social_profiles
資料表,也在 Voyager 中完成這個資料表的 BREAD。
現在回到 Voyager,從建立好的 BREAD 項目新增作者簡介。
編輯 PostController,加入作者簡介資料
回到 PostController
檔案,加入 UserSocialProfile
Model
use App\Models\UserSocialProfile;
負責文章全文的方法是 renderBlogPage
在這裡我加入以下程式碼到 $bindings
陣列,以 user_id
欄位搜尋 user_social_profiles
資料表中符合的資料。
'author_bio' => UserSocialProfile::where('id', $post->user_id)->first(),
顯示作者簡介的 Blade template 檔案
回到/resources/views/blog_page.blade.php
,將顯示作者簡介範例區塊改成
<!-- 作者簡介 -->
@include('widgets.author_bio')
<!-- 作者簡介 -->
負責顯示作者簡介的 Blade template 檔案位於 /resources/views/widgets/author_bio.blade.php
,如果有填寫社群網站帳號資料會顯示對應圖示,底下顯示簡介文字(支援 HTML 格式)。
<div class="blog-author d-flex align-items-center">
<img src="{{ Voyager::image($author_bio->avatar) }}" class="rounded-circle float-left" alt="作者照片">
<div>
<h4>{{ $author_bio->user->name }}</h4>
<div class="social-links">
@if($author_bio->email != '')
<a href="mailto:{{ $author_bio->email }}" target="_blank"><i class="bi bi-envelope"></i></a>
@endif
@if($author_bio->facebook != '')
<a href="{{ $author_bio->facebook }}" target="_blank"><i class="bi bi-facebook"></i></a>
@endif
@if($author_bio->instagram != '')
<a href="{{ $author_bio->instagram }}" target="_blank"><i class="biu bi-instagram"></i></a>
@endif
@if($author_bio->line != '')
<a href="{{ $author_bio->line }}" target="_blank"><i class="bi bi-line"></i></a>
@endif
@if($author_bio->twitter != '')
<a href="{{ $author_bio->twitter }}" target="_blank"><i class="bi bi-twitter"></i></a>
@endif
@if($author_bio->linkedin != '')
<a href="{{ $author_bio->linkedin }}" target="_blank"><i class="bi bi-linkedin"></i></a>
@endif
@if($author_bio->github != '')
<a href="{{ $author_bio->github }}" target="_blank"><i class="bi bi-github"></i></a>
@endif
</div>
{!! $author_bio->profile !!}
</div>
</div>
結語
透過 Voyager 我可以輕易建立顯示在網站的樹狀選單,日後選單項目的增減也不需更動 Blade template 檔案,方便我的維護作業。作者簡介的自動化讓文章全文頁面的完整性又往前邁進一步,再來就是回應功能了。