これなに
- elm-uiで条件によってmouseOverを有効にしたり無効にしたりするコードを書いた。
- たのしい
- ところが、このコードはブラウザ依存性があるらしいことがわかった。
- ついでに他のElementやElement.Eventsの同様なコードについて調査してみた。
はじめに
Elmを書くのが楽しいので、一つElm(とelm-ui)だけで何か作りたいなと思い、簡単なゲームを作成していました。この時に、「プレイヤーが操作可能なところだけ、マウスオーバーしたら色変えたりしたいな」と考え色々調べていたところ、elm-uiのElementにmouseOverがあることに気づきました。これを使って「条件ごとにmouseOver要素を入れたり入れなかったりする」コードを書いてみました。
サンプルコード
書いてみたサンプルコードはEllieで記録しています。
ModelとしてはMyself(自分)とOpposite(相手)だけを持っているカスタム型で、自分の手番の時にはMyselfのタイルにmouseOverがつき、相手の手番の時にはOppositeのタイルにつくというイメージです。
Myself <-> Oppositeは、「Change turn」ボタンで変更可能です。
具体的に条件ごとにmouseOverを出し入れしているのは下の部分。
viewTile : Player -> Model -> Element Msg
viewTile player model =
let
desc =
if player == Myself then
"Myself"
else
"Opposite"
changeMouseOver =
if player == model then
mouseOver [ Bg.color (rgba 1 0.2 0.3 0.5) ]
else
mouseOver []
in
column [ width (px 100), height (px 100), Border.width 1, changeMouseOver ] [ el [ centerX, centerY] ( text <| desc ) ]
変数としてchangeMouseOverを設定して、タイルに設定されているPlayer型と、現在Modelが持っているPlayerが同じであったときだけmouseOverによって背景色が変わります。
こういう感じにすれば、「Change turn」でModelを変更することで、mouseOverできるタイルが切り替わる……のですが、Safari 13.1で実行したときだけ、なんだか挙動がおかしい感じです。
「Change turn」を押して、OppositeにmouseOverを切り替えた時は想定どおり動作するのですが、もう一回切り替えてMyselfのタイルにmouseOverを設定しても、イベントが起こらないのです。
他のブラウザ(Chromium Edge 83, Chrome 84, FireFox 78)では、この切り替えは何度も起こすことができるので、Safari固有の問題だと考えています。でも原因はよくわからなかった(JS初心者マン)。
他のElementはどうなのか?
mouseOverの他にこのような挙動のElementがないか調べてみました。(適当)検証コードはEllieのリンクをつけています。
Element | Microsoft Edge (Chromium) 83 | Chrome 84 | FireFox 78 | Safari 13.1 |
---|---|---|---|---|
mouseOver | OK | OK | OK | 切替2回で動作しない |
mouseDown | OK | OK | OK | 切替1回で動作しない |
Events.onClick | OK | OK | OK | OK |
Events.onDoubleClick | OK | OK | OK | OK |
Events.onMouseDown | OK | OK | OK | OK |
Events.onMouseUp | OK | OK | OK | OK |
Events.onMouseEnter | OK | OK | OK | OK |
Events.onMouseLeave | OK | OK | OK | OK |
Events.onMouseMove | OK | OK | OK | OK? |
マウス動作まわりで調べてみたところ、どうやらTemporary stylingに該当するmouseOverやmouseDownで、Safariは中途半端な動作をしているようでした。Events.on-については、調べた全てのブラウザが見た感じ正常に切替動作しているようでした。onMouseMoveだけ、Safariと他のブラウザで比較した時、Safariの動きがもっさりしているのは気になるところですが、これの原因はよくわかりません(他の3ブラウザはタイル内でポインタを動かすと高速でTrue, Falseの表示が切り替わるのに対し、Safariではポインタの動き始め、動き終わりしか動作していないように見える)。
結論
正直原因がよくわからないのでモヤモヤした感じですが、Temporary stylingをifやcaseで条件分けして動作させようとすると、Safariではうまく動かないようです。なんか上手い書き方をしたらうまくいくのだろうか…。