iT邦幫忙

2021 iThome 鐵人賽

DAY 24
0
Modern Web

Laravel Livewire:不用 Vue 跟 jQuery 居然也能讓 Laravel 的畫面動起來 ?!系列 第 24

Day23 | Livewire 實作 購物網站(二): 建立商品細節頁面

有了商品列表,那應該要能點進去看商品的細節吧。所以今天就是來做點進去後的商品細節頁!

今日目標:商品細節頁

ㄧ、先刻畫面吧!

因為是範例我們一樣也是先參考別人的文案,如果是真實上線產品的話參考的尺度還請自行拿捏 XD

https://ithelp.ithome.com.tw/upload/images/20210926/20111805YqsWvv59zq.png

參考自 PCHome 的 記憶卡頁面

然後再用 TailwindCSS 去刻出來, TailwindCSS 還有 線上工具 能讓你邊玩邊調適畫面:

<div class="flex justify-center">
    <div class="grid md:grid-cols-3 sm:grid-cols-1 gap-4">
        <div class="row-span-3 w-64">
            <img src="" alt="">
        </div>
        <div class="col-span-2">
            <p class="text-xl font-bold">SanDisk Extreme microSDXC UHS-I(V30)(A2)256GB 記憶卡(公司貨)</p>
            <p class="text-red-500 font-bold mt-3">▲特價商品不參加其他贈品活動▲</p>
            <p class="text-gray-600 mt-10">
                ■讀取速度: 最高可達 160MB/s <br>
                ■寫入速度: 最高可達 90MB/s <br>
                ■UHS 新規(U3)與Video Speed Class等級 (V30) <br>
                ■專為4K UHD錄影設計 <br>
                ■增你強公司貨,首選有保障
            </p>
            <p class="mt-10 mb-5">
                <span class="text-sm text-gray-600">網路價</span>
                <span class="text-2xl text-red-600 font-bold">$1199</span>
            </p>
            <button class="bg-red-600 text-gray-50 p-2 w-36 rounded-md">加入購物車</button>
        </div>
        <div class="col-span-3 border-t mx-5"></div>
        <div class="col-span-3 mx-5 text-sm text-gray-600">介紹介紹介紹介紹介紹介紹介紹介紹介紹介紹介紹介紹介紹介紹介紹介紹</div>
    </div>
</div>

刻好大概長這樣

https://ithelp.ithome.com.tw/upload/images/20210926/20111805RVQkC5ntE1.png

關於 TailwindCSS 這次鐵人賽也有非常精彩的教學文章可以參考 -- 排版神器 Tailwind CSS~和兔兔一起快速上手漂亮的元件開發!


二、建立 Livewire 元件

一樣透過指令建立先建個元件吧!

php artisan make:livewire Shopping/ItemDetail

之後把上面的 HTML 都先塞進去剛剛建立的 item-detail.blade.php 中,並挖空靜態資料。一樣預設會傳進來的變數為 $item

<div class="flex justify-center">
    <div class="grid md:grid-cols-3 sm:grid-cols-1 gap-6">
        <div class="row-span-3 w-64">
            <img src="{{ $item->image_url }}" alt="">
        </div>
        <div class="col-span-2">
            <p class="text-xl font-bold">{{ $item->name }}</p>
            <p class="text-red-500 font-bold mt-3">{{ $item->slogan }}</p>
            <p class="text-gray-600 mt-10 w-1/3">
                {!! nl2br($item->specs) !!}
            </p>
            <p class="mt-10 mb-5">
                <span class="text-sm text-gray-600">網路價</span>
                <span class="text-2xl text-red-600 font-bold">${{ $item->price }}</span>
            </p>
            <button class="bg-red-600 text-gray-50 p-2 w-36 rounded-md">加入購物車</button>
        </div>
        <div class="col-span-3 border-t mx-5"></div>
        <div class="col-span-3 mx-5 text-sm text-gray-600">{!! $item->content !!}</div>
    </div>
</div>

註1: Laravel 中使用 {!! !!} 的話則可直接印出資料中的 HTML
註2: nl2br() 可以將資料中的 \n 轉成 <br/>


三、讓列表的項目點擊後能夠傳遞所點的項目

照原本 Vue 的邏輯直接在外層的 index.balde.php 中加上 Click事件 後直接傳值就好,像是這樣 <livewire:shopping.list-item wire:click="傳值"/>

但這個在 Livewire 中可行不通,因為 <livewire:shopping.list-item /> 在渲染後並不會產生實體,就像是 Vue 的 <template> 一樣。

https://ithelp.ithome.com.tw/upload/images/20210926/20111805EKAB5aTtHE.png

上圖:透過瀏覽器的開發工具可以清楚看到渲染後是直接印出元件的內容

因此我們要將 wire:click 寫在商品項目的元件中,也就是昨天的 list-item.blade.php

使用 $emit 來傳遞資料,由於會過手 JavaScript 因此沒辦法直接傳 PHP 的 Object 所以只能傳 $item->id 到時候再重拉一次。 Emit不熟悉的話可以參考此篇 或是 官方文件

<div class="..." wire:click="$emit('selectItem', {{ $item->id }})">
	...
</div>

四、接收傳遞過來的值

在主頁面(Index)中為了能攔截 $emit 的值,我們必須宣告一個監聽,並額外宣告一個變數 $selectedItem 及處理所選項目的函式 selectItem()。之後只要有點擊項目這邊就會自動去替換 $selectedItem 的內容。

class Index extends Component
{
    protected $listeners = ['selectItem'];
    public $selectedItem;

    public function render()
    {
        return view('livewire.shopping.index', [
            'list' => Good::all(),
        ]);
    }

    public function selectItem($itemId)
    {
        if (!$itemId) return false;
        $this->selectedItem = Good::find($itemId);
    }

}

五、修改主頁面顯示

接下來就只要修改一下前端的畫面就好啦 index.blade.php。因為要做成類似 SPA 的樣子,因此就不做換頁來顯示商品的細節,這邊就用 @if 來判斷是不是有東西可以顯示,如果沒有就顯示原本的列表。

<div class="mx-2 mt-2">
    @if($selectedItem)
        <livewire:shopping.item-detail :wire:key="'detail' . $selectedItem->id" :item="$selectedItem"/>
    @else
        <div class="grid lg:grid-cols-6 sm:grid-cols-4 gap-3"">
            @foreach($list as $item)
                <livewire:shopping.list-item :wire:key="'list-itme' . $item->id" :item="$item"/>
            @endforeach
        </div>
    @endif
</div>

六、做一個返回鍵

如果點進細節頁要回列表的話,因為都在同一頁運作所以不能用「上一頁」的功能來回列表。因此要做一個返回按鈕,其實就是把 $selectedItem 的值清掉就好:

如果是跟我一樣要做在最外層的話,同樣都是修改 index.blade.php

這邊在最上面加一條導航列,並在$selectedItem有值的時候(頁面會顯示細節頁),才會顯示「返回」按鈕。按下去後會觸發後端的 cleanItem() 去把值清掉。

<div class="mx-2 mt-2">
    <div class="h-10 bg-gray-300 p-2 -mx-2 -mt-2 mb-10">
        @if($selectedItem)
            <button class="text-black font-extrabold" wire:click="cleanItem">返回列表</button>
        @endif
    </div>
    @if($selectedItem)
     ...
</div>

後端

public function cleanItem()
{
    $this->selectedItem = null;
}

串好之後的商品細節頁長這樣~ XD

https://ithelp.ithome.com.tw/upload/images/20210926/20111805p95pgrNTCx.png

那今天的內容到這邊就完成啦!!

要看本次實作的範例的話請移駕至 => DEMO


上一篇
Day 22.5 | Livewire 實作 購物網站: 建立資料表
下一篇
Day 24 | Livewire 實作 購物網站(三): 加入購物車
系列文
Laravel Livewire:不用 Vue 跟 jQuery 居然也能讓 Laravel 的畫面動起來 ?!34

尚未有邦友留言

立即登入留言