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 21 资料宝石:【Lab】RDS架构 建立自己的第一台云端资料库 (上)

>>:  Day13 - PDF 加密、解密的处理

网站不想你爬

这边想说一下,关於上一篇有讲到我利用superagent()来获得网站资讯,结果抓取失败。这是因为不...

awk-2 Regex搭配浅谈

awk回顾 awk - 简介 Linux 制表好工具 复习一下awk格式 awk [options]...

第十天:安装 IntelliJ IDEA

在後续章节里,我们将使用 IntelliJ IDEA 示范如何编辑 Gradle 的 Build S...

JWT实作(四)(Day8)

今天要来实作登入功能~!! 这边要说说之前我刚开始看前後分离框架的不习惯,因为在之前没分离的开发情况...

# Day3 Virtual Memory Layout on RISC-V Linux

星期日,感觉是个适合算数的好日子,所以今天的文件,就决定是你了 Virtual Memory Lay...