はじめに
Elixir の Web フレームワーク Phoenix LiveView では phx-click
などのバインディングによって Web 上のイベントを Elixir に伝えます
しかし、マウスカーソルが要素に入ったときのイベント mouseenter や要素から出たときのイベント mouseleave はバインディングに存在しません
少し工夫が必要になります
Elixir forum の以下の提案を参考に実装しました
どういうときに必要か
そもそも、単に Web 上の見た目を変えるだけなから TailwindCSS の hover:
を使うだけで十分です
また、ちょっとした動作の制御であれば Alpine.js で x-on:mouseenter
と x-on:mouseleave
で事足ります
無駄にややこしくする必要はないので、基本的には TailwindCSS と Alpine.js だけで実装してしまう方がいいでしょう
Elixir 側での制御、ソケットで管理している値に介入する必要がある場合のみ、以下の実装が必要になります
実装
マウスイベントを拾いたい要素にフックを紐づけます
イベントで渡したい引数(%{"some_key" => "some_value"}
)があれば data-
で持たせておきます
Heex
<div
id="some-element"
phx-hook="MouseHook"
data-some_key="some_value"
/>
フックでは mounted
の中で mouseenter
と mouseleave
のイベントリスナーを追加します
pushEvent
の第2引数に event.target.dataset
に data-
で指定した引数が入っています
JS
const MouseHook = {
mounted () {
this.el.addEventListener('mouseenter', event => {
this.pushEvent('mouseenter', event.target.dataset)
})
this.el.addEventListener('mouseleave', event => {
this.pushEvent('mouseleave', event.target.dataset)
})
}
}
Elixir では pushEvent
で JS から来たイベントを handle_event
で受け取ります
Elixir
...
@impl true
def handle_event("mouseenter", %{"some_key" => some_value}, socket) do
...
{:noreply, socket}
end
@impl true
def handle_event("card_mouseleave", %{"some_key" => some_value}, socket) do
...
{:noreply, socket}
end
...
まとめ
基本的に Hooks を通した JS との連携でなんとでもなります
ただし、 Elixir でやるべきことと JS でやるべきことは上手く線引きしないと、どんどんややこしい実装になるので注意しましょう
基本的には JS を多用しすぎない方がいいです