Livewire 2.x AlpineJS

モーダルの切り替えのように、ページの相互作用が完全なサーバーラウンドトリップを保証しない場合がたくさんあります。

このような場合、AlpineJSはLivewireの完璧な友人になります。

これにより、JavaScriptの動作をVueJSと非常によく似た宣言的/反応的な方法で(あなたが慣れているならば)マークアップへ直接振り替えることができます。

インストール

Livewireで使用するために、Alpineをインストールする必要があります。

プロジェクトにAlpineをインストールするには、次のスクリプトタグをレイアウトファイルの <head>セクションに追加します。

<head>
    ...
    <script src="https://cdn.jsdelivr.net/gh/alpinejs/[email protected]/dist/alpine.min.js" defer></script>
    <!-- "defer"属性は、Alpineが最初にLivewireのロードされるのを待つために重要です。 -->
</head>

インストールの詳細については、AlpineJSのドキュメントへアクセスしてください。

Livewire内でAlpineを使用する

これはLivewireコンポーネントのビュー内の「ドロップダウン」機能にAlpineJSを使用する例です。

<div>
    ...

    <div x-data="{ open: false }">
        <button @click="open = true">Show More...</button>

        <ul x-show="open" @click.away="open = false">
            <li><button wire:click="archive">Archive</button></li>
            <li><button wire:click="delete">Delete</button></li>
        </ul>
    </div>
</div>

再利用可能なBladeコンポーネントの抽出

両ツール自体にまだ慣れていない場合は、両方の構文を混在させると少し混乱するかもしれません。

このため可能であれば、Livewire内(およびアプリケーション内の任意の場所)で使用できるように、Alpineパーツを再利用可能なBladeコンポーネントに抽出する必要があります。

例を以降に示します(Laravel7のBladeコンポーネントタグ構文を使用)。

Livewireビュー

<div>
    ...

    <x-dropdown>
        <x-slot name="trigger">
            <button>Show More...</button>
        </x-slot>

        <ul>
            <li><button wire:click="archive">Archive</button></li>
            <li><button wire:click="delete">Delete</button></li>
        </ul>
    </x-dropdown>
</div>

再利用可能な"dropdown" Bladeコンポーネント

<div x-data="{ open: false }">
    <span @click="open = true">{{ $trigger }}</span>

    <div x-show="open" @click.away="open = false">
        {{ $slot }}
    </div>
</div>

これで、LivewireとAlpineの構文が完全に分離され、他のコンポーネントから使用できる再利用可能なBladeコンポーネントができました。

AlpineからのLivewireの操作: $wire

Livewireコンポーネント内の任意のAlpineコンポーネントから、魔法の$wireオブジェクトにアクセスして、Livewireコンポーネントを操作できます。

使用法を示すため、Livewireを完全に内部で使用する"counter"コンポーネントをAlpineに作成します。

class Counter extends Component
{
    public $count = 0;

    public function increment()
    {
        $this->count++;
    }
}
<div>
    <!-- Alpine counterコンポーネント -->
    <div x-data>
        <h1 x-text="$wire.count"></h1>

        <button x-on:click="$wire.increment()">Increment</button>
    </div>
</div>

これで、ユーザーが"Increment"をクリックすると、標準のLivewireラウンドトリップが起動され、AlpineはLivewireの新しい$count値を反映します。

$wireは内部でJavaScriptProxyを使用しているため、プロパティにアクセスしてメソッドを呼び出すことができ、それらの操作はLivewireに転送されます。この機能に加えて、$wireには標準の組み込みメソッドも用意しています。

$wireの完全なAPIは次のとおりです。

// Livewireプロパティへのアクセス
$wire.foo

// Livewireメソッドの呼び出し
$wire.someMethod(someParam)

// Livewireメソッドを呼び出し、その結果を使用して何かを実行する
$wire.someMethod(someParam)
    .then(result => { ... })

// Livewireメソッドを呼び出し、async/awaitを使用してその応答を保存します
let foo = await $wire.getFoo()

// 名前が"some-event"で2つのパラメータを持つLivewireイベントを発行します
$wire.emit('some-event', 'foo', 'bar')

// 名前が"some-event"で発行されたLivewireイベントをリッスンします
$wire.on('some-event', (foo, bar) => {})

// Livewireプロパティの取得
$wire.get('property')

// Livewireプロパティに特定の値を設定する
$wire.set('property', value)

// 遅らせて、Livewireプロパティに特定の値を設定する
$wire.set('property', value, true)

// Livewireアクションの呼び出し
$wire.call('someMethod', param)

// ファイルをアップロードし、Livewireプロパティを設定する
$wire.upload(
    'property',
    file,
    finishCallback = (uploadedFilename) => {},
    errorCallback = () => {},
    progressCallback = (event) => {}
)

// 複数のファイルをアップロードし、Livewireプロパティを設定する
$wire.uploadMultiple(
    'property',
    files,
    finishCallback = (uploadedFilenames) => {},
    errorCallback = () => {},
    progressCallback = (event) => {}
)

// アップロードしたファイルを削除し、Livewireプロパティを更新する
$wire.removeUpload(
    'property',
    uploadedFilename,
    finishCallback = (uploadedFilename) => {},
    errorCallback = () => {}
)

// ベースとなるLivewireコンポーネントのJavaScriptインスタンスへのアクセス
$wire.__instance

LivewireとAlpineの間で状態を共有する: @entangle

Livewireには、"entangle"と言う名前の非常に強力な機能があり、LivewireとAlpineのプロパティを一緒に絡める(entangle)ことができます。エンタングルメントで一方の値が変更されると、もう一方の値も変更されます。

実例を示すために、以前のドロップダウンの例を考えてみましょう。ただし、LivewireとAlpineの間に絡み合ったshowDownプロパティがあります。エンタングルメントを使用することで、AlpineとLivewireの両方からドロップダウンの状態を制御できるようになりました。

class Dropdown extends Component
{
    public $showDropdown = false;

    public function archive()
    {
        ...
        $this->showDropdown = false;
    }

    public function delete()
    {
        ...
        $this->showDropdown = false;
    }
}
<div x-data="{ open: @entangle('showDropdown') }">
    <button @click="open = true">Show More...</button>

    <ul x-show="open" @click.away="open = false">
        <li><button wire:click="archive">Archive</button></li>
        <li><button wire:click="delete">Delete</button></li>
    </ul>
</div>

これで、ユーザーはAlpineを使用してドロップダウンをすぐにオンに切り替えることができますが、"Archive"などのLivewireアクションをクリックすると、ドロップダウンはLivewireから閉じるように指示されます。AlpineとLivewireはどちらもそれぞれのプロパティを操作でき、もう一方は自動的に更新されます。

場合により、Alpineの変更ごとにLivewireを更新する必要はなく、変更を次のLivewireリクエストに伸ばす必要が起きます。このような場合、次のように.deferプロパティをチェーンできます。

<div x-data="{ open: @entangle('showDropdown').defer }">
    ...

これでユーザーがドロップダウンのオープンとクローズを切り替えても、Livewireに対してAJAXリクエストを送信しませんが、Livewireアクションが"archive"や"delete"などのボタンから起動されると、"showDropdown"はリクエストと一緒にバンドルされます。

この違いを理解するのが難しい場合は。ブラウザの開発ツールを開き、.deferを追加した場合と追加しない場合のXHRリクエストの違いを観察してください。

BladeコンポーネントからLivewireディレクティブへアクセスする

Livewireアプリケーション内で再利用可能なBladeコンポーネントを抽出するのは、不可欠なパターンでしょう。

Livewireコンテキスト内にBladeコンポーネントを実装する際に遭遇する可能性のある問題のひとつは、コンポーネント内からwire:modelなどの属性の値にアクセスすることです。

たとえば、次のようなテキスト入力Bladeコンポーネントを作成したとしましょう。

<!-- 使用 -->
<x-inputs.text wire:model="foo"/>

<!-- 定義 -->
<div>
    <input type="text" {{ $attributes }}>
</div>

このような単純なBladeコンポーネントは完全に正常に機能します。LaravelとBladeは、コンポーネントに追加した属性(この場合はwire:modelなど)を自動的に転送し、属性バッグ($attributes)をエコーアウトするため、それらは<input>タグに配置されます

しかし、コンポーネントに渡されたLivewireの属性について、より詳細な情報を抽出する必要がある場合もあります。

Livewireはこうした手間を支援するために$attributes->wire()メソッドを提供しています。

以下がBladeコンポーネントの使用方法です。

<x-inputs.text wire:model.defer="foo" wire:loading.class="opacity-25"/>

次のように、Bladeの$attributeバッグからLivewireディレクティブ情報にアクセスできます。

$attributes->wire('model')->value(); // "foo"
$attributes->wire('model')->modifiers(); // ["defer"]
$attributes->wire('model')->hasModifier('defer'); // true

$attributes->wire('loading')->hasModifier('class'); // true
$attributes->wire('loading')->value(); // "opacity-25"

これらのLivewireディレクティブを個別に「転送(forward)」することもできます。例をご覧ください。

<!-- 元 -->
<x-inputs.text wire:model.defer="foo" wire:loading.class="opacity-25"/>

<!-- 次のようにwire:model.defer = "foo"ディレクティブを転送できます。 -->
<input type="text" {{ $attributes->wire('model') }}>

<!-- 出力 -->
<input type="text" wire:model.defer="foo">

このユーティリティを使用する方法はたくさんありますが、よくある例は、前述の @entangleディレクティブと組み合わせて使用​​することです。

<!-- 使用 -->
<x-dropdown wire:model="show">
    <x-slot name="trigger">
        <button>Show</button>
    </x-slot>

    Dropdown Contents
</x-dropdown>

<!-- 定義 -->
<div x-data="{ open: @entangle($attributes->wire('model')) }">
    <span @click="open = true">{{ $trigger }}</span>

    <div x-show="open" @click.away="open = false">
        {{ $slot }}
    </div>
</div>

{note} .defer修飾子がwire:model.deferを介して渡された場合、@entangleディレクティブはそれを自動的に認識し、@entangle('...').defer修飾子を内部で追加します。

DatePickerコンポーネントの作成

Livewire内のJavaScriptの一般的な使用例は、カスタムフォーム入力です。日付ピッカー、カラーピッカーなどのようなものは、大抵の場合アプリケーションに不可欠です。

上記のような同じパターンを使用する(そして追加ソースを追加する)ことで、Alpineを利用して、これらのタイプのJavaScriptコンポーネントとのやり取りを簡単にできます。

wire:modelを使用してLivewireで一部のデータをバインドするために使用できるdate-pickerという名前の再利用可能なBladeコンポーネントを作成しましょう。

使用方法は次のとおりです。

<form wire:submit.prevent="schedule">
    <label for="title">Event Title</label>
    <input wire:model="title" id="title" type="text">

    <label for="date">Event Date</label>
    <x-date-picker wire:model="date" id="date"/>

    <button>Schedule Event</button>
</form>

このコンポーネントは、Pikadayライブラリを使用します。

ドキュメントによると、パッケージの最も基本的な使用法(アセットをインクルードした後)は次のようになります。

<input type="text" id="datepicker">

<script>
    new Pikaday({ field: document.getElementById('datepicker') })
</script>

必要なのは <input>要素だけで、Pikadayはすべての追加の日付ピッカー動作を追加します。

次に、このライブラリで再利用可能なBladeコンポーネントを作成する方法を見てみましょう。

再利用可能なdate-picker Bladeコンポーネント:

<input
    x-data
    x-ref="input"
    x-init="new Pikaday({ field: $refs.input })"
    type="text"
    {{ $attributes }}
>

{note} {{ $attributes }}式は、コンポーネントタグで宣言された追加のHTML属性を転送するLaravel7以降のメカニズムです。

wire:model inputイベントの転送

内部的には、wire:modelはイベントリスナーを追加し、inputイベントが要素上または要素の下にディスパッチされるたびにプロパティを更新します。LivewireとAlpineの間で通信する別の方法は、Alpineを使用し、wire:modelを含む要素内または要素上に、データを含むinputイベントをディスパッチすることです。

ユーザーが最初のボタンをクリックすると、$fooプロパティがbarに設定され、ユーザーが2番目のボタンをクリックすると$foobazに設定される不思議なサンプルを作成してみましょう。

Livewireコンポーネントビューの中

<div>
    <div wire:model="foo">
        <button x-data @click="$dispatch('input', 'bar')">Set to "bar"</button>
        <button x-data @click="$dispatch('input', 'baz')">Set to "baz"</button>
    </div>
</div>

より現実的な例は、Livewireコンポーネント内で使用される可能性のある"color-picker" Bladeコンポーネントの作成です。

Color-pickerコンポーネント使用例

<div>
    <x-color-picker wire:model="color"/>
</div>

コンポーネントの定義には、Vanilla Pickerという名前のサードパーティカラーピッカーライブラリを使用します。

このサンプルは、ページにロードされていることを前提としています。

Color-picker Bladeコンポーネント定義(コメントなし)

<div
    x-data="{ color: '#ffffff' }"
    x-init="
        picker = new Picker($refs.button);
        picker.onDone = rawColor => {
            color = rawColor.hex;
            $dispatch('input', color)
        }
    "
    wire:ignore
    {{ $attributes }}
>
    <span x-text="color" :style="`background: ${color}`"></span>
    <button x-ref="button">Change</button>
</div>

Color-picker Bladeコンポーネント定義(コメントあり)

<div
    x-data="{ color: '#ffffff' }"
    x-init="
        // 'change'ボタンをクリックすると、ピッカーが表示されるようにバインドします。
        picker = new Picker($refs.button);
        // 新しい色が選択されるたびに、このコールバックを実行します。
        picker.onDone = rawColor => {
            // Alpineの`color`プロパティを設定します。
            color = rawColor.hex;
            // Dispatch the color property for 'wire:model' to pick up.
            // ピックアップするために'wire:model'のcolorプロパティをディスパッチします。
            $dispatch('input', color)

        }
    "
    // Vanilla Pickerはこの要素内に自身のDOMをアタッチするため、`wire:ignore`を
    // 追加して、LivewireにDOM差分をスキップするように指示する必要があります。
    wire:ignore
    // `wire:model=color`のようにコンポーネントタグに追加された属性をすべて転送します
    {{ $attributes }}
>
    <!-- 背景色を選択した色に設定して、現在の色の値を表示します。 -->
    <span x-text="color" :style="`background: ${color}`"></span>
    <!-- このボタンをクリックすると、カラーピッカーダイアログが表示されます。 -->
    <button x-ref="button">Change</button>
</div>

DOMの変更を無視する(wire:ignoreを使用)

幸いにしてPikadayのようなライブラリは、ページの最後に追加のDOMを追加します。他の多くのライブラリは、初期化されるとすぐにDOMを操作し、それらを操作するときにDOMを変更し続けます。

これが発生した場合にLivewireは、コンポーネントの更新時に保持したいDOM操作と、破棄するDOM操作を追跡するのが困難になります。

コンポーネント内のHTMLのサブセットへの変更を無視するようにLivewireに指示するには、wire:ignoreディレクティブを追加します。

Select2ライブラリは、DOMの一部を乗っ取るライブラリの1つです(<select>タグを多くのカスタムマークアップに置き換えます)。

これはLivewireコンポーネント内でSelect2ライブラリを使用して、wire:ignoreの使用法を示す例です。

<div>
    <div wire:ignore> {{-- [tl! highlight] --}}
        <select class="select2" name="state">
            <option value="AL">Alabama</option>
            <option value="WY">Wyoming</option>
        </select>

        <!-- Select2はここにDOMを挿入する -->
    </div>
</div>

@push('scripts')
<script>
    $(document).ready(function() {
        $('.select2').select2();
    });
</script>
@endpush

{tip} 要素への変更を無視すると便利な場合もありますが、その子は無視したくない場合は注意してください。この場合、 wire:ignore.selfのように、self修飾子をwire:ignoreディレクティブに追加できます。

ドキュメント章別ページ

ヘッダー項目移動

注目:アイコン:ページ内リンク設置(リンクがないヘッダーへの移動では、リンクがある以前のヘッダーのハッシュをURLへ付加します。

移動

クリックで即時移動します。

言語
バージョン

設定

適用ボタンクリック後に、全項目まとめて適用されます。

カラーテーマ
和文指定 Pagination
和文指定 Scaffold
Largeスクリーン表示幅
インデント
本文フォント
コードフォント
フォント適用確認

フォントの指定フィールドから、フォーカスが外れると、当ブロックの内容に反映されます。EnglishのDisplayもPreviewしてください。

フォント設定時、表示に不具合が出た場合、当サイトのクッキーを削除してください。

バックスラッシュを含むインライン\Code\Blockの例です。

以下はコードブロックの例です。

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class User extends Model
{
    /**
     * ユーザに関連する電話レコードを取得
     */
    public function phone()
    {
        return $this->hasOne('App\Phone');
    }
}

設定を保存する前に、表示が乱れないか必ず確認してください。CSSによるフォントファミリー指定の知識がない場合は、フォントを変更しないほうが良いでしょう。

キーボード・ショートカット

オープン操作

PDC

ページ(章)移動の左オフキャンバスオープン

HA

ヘッダー移動モーダルオープン

MS

移動/設定の右オフキャンバスオープン

ヘッダー移動

T

最初のヘッダーへ移動

E

最後のヘッダーへ移動

NJ

次ヘッダー(H2〜H4)へ移動

BK

前ヘッダー(H2〜H4)へ移動

その他

?

このヘルプページ表示
閉じる