Livewire で Livewire.directive でカスタムディレクティブを作るには?custom

ショコラ
ショコラ

Livewire で Livewire.directive でカスタムディレクティブを作るには?custom

「Livewire.directive(directiveName, (el, directive, component) => {})」「Register a new Livewire directive (wire:custom-directive)」の話です。
これは、どう使えばいいのか?何ができるのか?謎ですが、これでいいのかな?的な使い方を考えました。
Fomantic-UI の場合、コンポーネントを表示するときに1行のJavaScriptが必要になります。
例えば、ドロップダウンなら「$(‘.ui.dropdown’) .dropdown()」。カレンダーなら「$(‘.ui.calendar’) .calendar()」。プログレスなら「$(‘.ui.progress’).progress()」という感じです。
カスタムディレクティブを使うことによって、上記の JavaScript を書かなくても画面に表示できるかなと思いました。

もっさん先輩
もっさん先輩

手順

Laravel と Livewire をインストールして、ドロップダウンのカスタムディレクティブを作成する手順。

  1. プロジェクト名(custom)を決めて以下のコマンドを実行します。
curl -s https://laravel.build/custom | bash

インストール時にプロジェクト名のディレクトリが作成されます。

  1. インストールの最後に sudo でパスワードの入力を求められます。

↓下のメッセージが表示されてインストールは終わります。

Use 'docker scan' to run Snyk tests against images to find vulnerabilities and learn how to fix them

Get started with: cd custom && ./vendor/bin/sail up
  1. sail のエイリアスを定義します。
echo "alias sail='[ -f sail ] && sh sail || sh vendor/bin/sail'" >> ~/.bashrc
source ~/.bashrc

Laravel のインストールはここまで。

  1. 「sail up」でコンテナを起動します。
cd custom && sail up -d
  1. ララベルのトップディレクトリで、Livewireパッケージ をインストールします。
sail composer require livewire/livewire
  1. 次のコマンドを実行して、multipleコンポーネント を生成します。
sail artisan make:livewire multiple
$ sail artisan make:livewire multiple
 COMPONENT CREATED  ?

CLASS: app/Http/Livewire/Multiple.php
VIEW:  resources/views/livewire/multiple.blade.php

次の 2つ のファイルが生成されます。

<?php

namespace App\Http\Livewire;

use Livewire\Component;

class Multiple extends Component
{
    public function render()
    {
        return view('livewire.multiple');
    }
}
<div>
    {{-- Be like water. --}}
</div>

※因みに、renderメソッド を定義しなくても livewire.multiple は呼び出されます。

<?php

namespace App\Http\Livewire;

use Livewire\Component;

class Multiple extends Component
{
}
  1. 生成された multipleコンポーネント のクラスとビューを次のように置き換えます。

app/Http/Livewire/Multiple.php

<?php
namespace App\Http\Livewire;
class Multiple extends \Livewire\Component
{
  public $skills = [];
  public function dehydrate() {
    \Log::debug($this->skills);
  }
}

resources/views/livewire/multiple.blade.php

<div>
  <select wire:model="skills" multiple="" class="ui fluid dropdown" wire:module="dropdown" wire:module.settings="window.settings()">
    <option value="">Skills</option>
    <option value="angular">Angular</option>
    <option value="css">CSS</option>
    <option value="design">Graphic Design</option>
    <option value="ember">Ember</option>
    <option value="html">HTML</option>
    <option value="ia">Information Architecture</option>
    <option value="javascript">Javascript</option>
    <option value="mech">Mechanical Engineering</option>
    <option value="meteor">Meteor</option>
    <option value="node">NodeJS</option>
    <option value="plumbing">Plumbing</option>
    <option value="python">Python</option>
    <option value="rails">Rails</option>
    <option value="react">React</option>
    <option value="repair">Kitchen Repair</option>
    <option value="ruby">Ruby</option>
    <option value="ui">UI Design</option>
    <option value="ux">User Experience</option>
  </select>
</div>

@push ('scripts')
<script>
function settings() {
  return {
    clearable: true,
    onChange: value => console.log(value),
  }
}
</script>
@endpush

↑注目です。2行目に「wire:module=”dropdown”」と「wire:module.settings=”window.settings()”」を追加しました。JavaScript で dropdownメソッド の呼び出しは行っていません。

  1. resources/views/index.blade.php ファイル を作成します。
<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8">
    <script src="https://cdn.jsdelivr.net/npm/jquery@3.6.1/dist/jquery.min.js"></script>
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/fomantic-ui@2.9.0/dist/semantic.min.css">
    <script src="https://cdn.jsdelivr.net/npm/fomantic-ui@2.9.0/dist/semantic.min.js"></script>
    <livewire:styles />
  </head>
  <body>
    <div class="ui basic segment">
      <livewire:multiple />
    </div>
    <livewire:scripts />
    @stack ('scripts')
<script>
Livewire.directive('module',(el,directive,component) => {
  const module = el.getAttribute('wire:module')
  const settings = el.getAttribute('wire:module.settings')
  eval(`$(el).${module}('destroy')`) // onHideが呼ばれない。
  eval(`$(el).${module}(${settings})`)
})
</script>
  </body>
</html>

↑Livewire.directive で「wire:module」を定義しています。これでエレメントに対して dropdownメソッド を実行するようにします。
一見「できたかな」と思ったのですが、「Transition: Element is no longer attached to DOM. Unable to animate. Use silent setting to suppress this warning in production. slide down out」のエラーがでてしまいましたので、エレメントを destroy で削除しています。そうすると onHide が呼び出されないので、何か考えなければならないかもしれません。

  1. routes/web.php に Livewireコンポーネント のルートを追加します
Route::get('/', fn() => view('index'));
  1. ブラウザで確認します。

カスタムディレクティブを使うことで、ブレードファイルに JavaScript を書くことなく、コンポーネントを表示することができました。

以上

Scroll to Top