Laravel 7 Blade Component


Posted by JingTeng on 2020-09-09

寫了好幾天,每天都在更正錯誤= =

blade 裡面太多類似的方法了,直接看 Laracasts 7 真的一頭霧水,去惡補完前幾代的 blade 才能理解。最好先了解一下 Laracel 5 的 component。

@extends + @section 功能上跟 @component + @slot 一樣
之後 @component + @slot<x-component> + <x-slot> 取代
至於 <x-component /> 看起來就是 @include

Laravel 7 前: @extends

透過 @extends('layout') 擴充 Layout,插入 footer 元件

@section + @yield

layout 裡面留一塊區塊給其他 blade 實作。當我們進入 page blade 時,因為 page 擴充 layout,所以看起來就像 layout,但是 @yield('content') 將呈現 @section('content') 包夾的內容。

page.blade

@extends('layout')

@section('content')
    implements something
@endsection

layout.blade

@yield('content')

也可以使用 @component 寫法

@component + slot

要引用 component 的那個 blade 實作內容

<!-- /resources/my/oops-alert.blade.php -->

@component('alert')
    <strong>Whoops!</strong> Something went wrong!
@endcomponent

component 寫好樣式用 slot 預留位置給其他 blade 插入內容

<!-- /resources/views/alert.blade.php -->

<div class="alert alert-danger">
    {{ $slot }}
</div>

Laravel 7:用 x-component 取代 @component

  • 必須將父視圖 layout.blade 放在 components 資料夾
  • 要使用 php artisan make:component [name] 來建立 x-component

更正
其實不用 make:component 也可以,這樣就會變成匿名元件(anonymous compontn = 沒有綁 view model 的 component,有 view nodel 可以做更多資料操控)
我不知道為什麼之前做匿名元件都弄不出來,我真的不知道...

blade 只要遇到 x-component 就會去掃描 components 資料夾。(要有 view model render)

其實這樣 layout 叫父視圖也怪怪的。之前是用 @extends 擴充,所以叫父視圖沒什麼問題。但 layout 變成 component 感覺就像一個普通的個元件,被注入到 view page。心理上過不去,怪怪的。

x-component + {{ $slot }}

views 的 blade 實作注入 component

<!-- /resources/views/oops-alert.blade.php -->

<x-alert>
   <strong>Whoops!</strong> Something went wrong!
</x-alert>

layout component 一樣用 slot 預留可以被注入的部分

<!-- /resources/components/alert.blade.php -->

<div class="alert alert-danger">
    {{ $slot }}
</div>

<x-component> + <x-slot>

<x-componentName> 基本上就是之前的 @component('componentName')
<x-slot name="var"> 基本上就是之前的 @slot('var')

content.blade 實作 HTML,並透過 <x-layout> 指定注入樣板 layout.blade

  • content.blade 裡,title="Laravel" 的 title 資料綁定 component 的 {{ $title }} 變數呈現。
  • content.blade 裡,<x-slot name="ad"> ad 綁定 component 的 {{ $ad }}
  • content.blade 裡,沒有綁定變數的預設綁定給 {{ $slot }} 的資料是由 content.blade 提供,

注意
這邊如果 blade 想直接傳 title 變數給 component blade,component blade 必須是匿名的
否則必須在 view model 裡面設定 public variabel

resources/views/content.blade.php

<x-layout title="Laravel">
    <x-slot name="ad">
        Buy Me a Coffee
    </x-slot>

    Laravel 7 Blade Component Note
</x-layout>

resources/views/components/layout.blade.php

<div>
    Hello {{ $title }}
</div>

<div>
    @if( isset($ad) )
        <div class="ad">
            {{ $ad }}
        </div>
    @endif

    <div class="dashboard">
        {{ $slot ?? '' }}
    </div>
<div>

組合 components

現在有一個 flash blade 是擴充 layout
檔案結構:

resources/views/
|-components //可注入的元件 blade
|---layout.blade.php 
|-welcome.blade.php //視圖 blade

layout = HTML 結構檔案

{{ $slot }}

welcome = 注入 layout ,並實作 layout slot

<x-layout>
    <section>
        <p>一些提示訊息</p>
    </section>
</x-layout>

但 welcome 裡面的東西是可以再做元件,因此我們再做一個 flash 元件:

檔案結構:

resources/views/
|-components //注入子視圖的元件
|---layout.blade.php 
|---flash.blade.php 
|-welcome.blade.php //子視圖

flash

<section>
    <p>一些提示訊息</p>
</section>

welcome

<x-layout>
    <x-flash></x-flash>
</x-layout>

這樣 welcome 就會透過 x- 去注入 layout,並實作 layout 的 slot。
welcom 實作又是用一個 x- ,所以它會注入 flash。flash 沒有需要實作的內容,最終呈現的畫面就是 flash 所寫的 <p>一些提示訊息</p>

props

之前我們傳入的變數都是直接使用雙括號顯示。例如 title="Laravel" -> {{ $title }}
使用 props 可以傳入變數

flash

@props([
    'type' => 'light'
])

<section class=" {{$type === 'dark' ? 'bg-black' : 'bg-gray-300'}} ">
    <p>
        {{ $slot }}
    </p>
</section>

在 welcome 沒有傳入 type 時,props 設定 type 為 light 版面。
現在從 welcome 傳入 dark。結果就是 dark 版面。

welcome

<x-layout>
    <x-flash type="dark">
        flash~~
    </x-flash>
</x-layout>

props 可以有更多的應用

flash

@props([
    'type' => 'light',
    'colors' => [
        'light' => 'bg-gray-300',
        'dark' => 'bg-black'
    ]
])

<section class="{{ $colors[$type] }}" >
    <p>
        {{ $slot }}
    </p>
</section>

<x-component />

前面插來插去的,搞到最後都不知道是誰繼承,感覺在哪個地方實作都可以。這個寫法就比較清楚,component 裡面實作你的元件,view page 用 <x-component /> 注入。

譬如這個寫死的 footer 元件要注入到 pages/home,就跟 @include 一樣好懂。

resources/views/components/footer.blade.php

<div>
    default footer
<div>

resources/views/pages/home.blade.php

<x-footer />

一樣是可以做匿名元件
resources/views/components/footer.blade.php

<div>
    {{ $title }} //laravel
<div>

resources/views/pages/home.blade.php

<x-footer title="laravel"/>

View Model ( Component Class )

透過 make:component DemoLayout 產生 app/View/Components/DemoLayoutresources/views/components/demo-Layout.balde.php

demo-Layout

<?php

namespace App\View\Components;

use Illuminate\View\Component;

class DemoLayout extends Component
{
    /**
     * Create a new component instance.
     *
     * @return void
     */
    public function __construct()
    {
        //
    }

    /**
     * Get the view / contents that represent the component.
     *
     * @return \Illuminate\View\View|string
     */
    public function render()
    {
        return view('components.demo-layout');
    }
}

實作 View Model 驅動畫面

header.php (extends Component)

<?php

namespace App\View\Components;

use Illuminate\View\Component;

class Header extends Component
{
    public $header; //

    public function __construct($header)
    {
        $this->header = $header //
    }

    public function render()
    {
        return view('components.header');
    }
}

header.blade.php

<div>
    {{ $header }}
</div>

layout.blade.php

<x-header header="My website" />

inline blade

make:component text --inline
在 Component Class 直接 return blade view 就不用去 resources/views/components 找對應的檔案

Component Class 可以置換 attributes,也可以 merge

render()
{
    return <<<'blade'
        <div {{ $attrubutes->merge(['class' => 'bg-red-400 text-white']) }}>
            {{ $description here }}
        </div>
    blade;
}

layout.blade 可以覆蓋 Component Class 寫的 style

<x-notify description="" class="bg-green-400" />

Component Class 也可以傳進其他東西例如 type

render()
{
    return <<<'blade'
        <div class="{{ $type === 'success' ? 'bg-green-400' : 'bg-red-400'}}"">
            {{ $description here }}
        </div>
    blade;
}

參考










Related Posts

[css] css 界的人生重來槍 - revert

[css] css 界的人生重來槍 - revert

[01] props.sync

[01] props.sync

DOM - 瀏覽器事件傳遞機制

DOM - 瀏覽器事件傳遞機制


Comments