Blogger:カレンダー(4)Calendar_Bloggerモジュールの作成その3

CSSツールチップ上のリンクをクリックできるようにする方法を考えます。

前の関連記事:Blogger:カレンダー(3)Calendar_Bloggerモジュールの作成その2


Calendar_Bloggerモジュールのイベントバブリングの経路


Blogger:カレンダー(3)Calendar_Bloggerモジュールの作成その2のコードを見直します。

まずツールチップ上の<a>タグからカレンダーを表示させる親ノードまでのイベントバブリングの経路を書き出してみました。

<div id="calendar_blogger"> (Bloggerテンプレートにあるdiv要素)

<div style="display:flex"> (flexコンテナ)(プロパティにイベントハンドラを設定) (currentTarget)
 ↑
<div class="tooltip">  (flexアイテム) (日)
 ↑
<span style="visibility:hidden"> (ツールチップ)
 
<a> (投稿へのリンク)

<span style="visibility:hidden">とその子ノードの<a>がツールチップに表示されるノードになります。

イベントフェーズのキャプチャフェーズは上から下へ、バブリングフェーズは下から上へ伝播していきます。(addEventListenerの第3引数の意味 | JavaScript プログラミング解説

要素のプロパティとしてイベントハンドラを登録しているのでキャプチャフェーズでは何も起こりません。(イベントハンドラ | JavaScript プログラミング解説

イベントハンドラは<div style="display:flex">に設定しているので、これがcurrentTargetになります。(イベント | JavaScript プログラミング解説)

targetになり得るのはcurrentTargetである<div style="display:flex">とその下層にある<div class="tooltip">、<span style="visibility:hidden">、<a>のいずれかの4つです。

<span style="visibility:hidden">と<a>がtargetとなるのはツールチップが表示されているときだけです。

マウスポインタがカレンダーを横切るとそれぞれの要素についてonmouseoverとonmouseoutのイベントが次から次へと発生します。

それをcurrentTargetの要素でイベントを受け取ります。

受け取ったイベントをtargetのクラス名で判別してcurrentTargetでツールチップの表示を切り替えています。

Blogger:カレンダー(3)Calendar_Bloggerモジュールの作成その2ではflexアイテムの上をマウスポインタが乗るとそのflexアイテムがtargetになりイベントが伝播されてflexコンテナでプロパティに設定されたイベントハンドラが起動します。

Blogger:カレンダー(3)Calendar_Bloggerモジュールの作成その2のCalendar_Bloggerモジュールの問題点の原因


onmouseoverで"visibility:visible"にしてツールチップ表示をし、onmouseoutで"visibility:hidden"に戻してツールチップ表示を消しています。

表示されたツールチップ上にマウスポインタを移そうとすると、ツールチップを表示させたtargetのflexアイテムから出ることになるので、ツールチップ表示が消えてしまいます。

ツールチップ上にマウスポインタが乗るとonmouseoverが起動するのでツールチップが表示されそうですが、すでに消えているものにマウスポインタが乗ることはできないのでそうはなりません。

なので、マウスをクリックすることでフラグを切り替えてonmouseoutの有効無効を切り替えようとしました。

しかしそうするとツールチップが次々表示されて消えなくなってしまいました。

それはマウスをクリックしたときに作用するツールチップが、すでに表示させているツールチップとは異なるものであることが原因と気がつきました。

ツールチップを表示させている要素の取得自体をフラグにしてまあまあ解決


ということでツールチップを表示させている要素を取得しておいてそれを操作することでうまくツールチップの表示を切り替えることができるようになりました。

ツールチップを表示させるときにflexアイテムのオブジェクトを取得します。

マウスポインタがflexアイテムから出てツールチップ上に移動させようとflexアイテムのonmouseoverが発生したときに、すでに取得しているflexアイテムのオブジェクトとイベントバブリングを受け取るオブジェクトが同一のflexアイテムのオブジェクトであるかを比較して、ツールチップの表示の消去を無効にしました。

これでツールチップ上にマウスポインタを移動させることができました。

ツールチップ上にマウスポインタが入るときに今度はツールチップの要素からonmouseoverが発生して、投稿へのリンクに入るときは、ツールチップの要素からonmouseoutと投稿へのリンクの要素からのonmouseover、といったように次々とイベントが発生しますが、これらもすべてイベントバブリングを受け取るオブジェクトとすでに取得しているflexアイテムのオブジェクトと比較することでツールチップの表示の切り替えが起こらないようにしました。

ツールチップの表示を消すのはすでに取得しているflexアイテムのオブジェクト以外のflexアイテムがイベントバブリングを受け取ったときです。

これでうまくいったと思ったのですが、まだ問題がありました。

マウスポインタがツールチップ上から他のflexアイテムを通ることなくflexコンテナから出てしまうときです。

このときはすでに取得しているflexアイテムのオブジェクト以外のflexアイテムがイベントバブリングを受け取らないのでツールチップの表示が消えません。

なので、マウスポインタがflexコンテナをでるときのonmouseoutを受け取るようにしたのですが、それはうまく動きませんでした。

ツールチップからマウスポインタが外れたときのonmouseoutイベントがイベントバブリングでflexアイテムに伝わり、そこでreturn falseやEvent.stopPropagation()をしなければ、flexコンテナでイベントを受け取れると思ったのですが、それは要素のプロパティにイベントハンドラを登録する方法ではできないから無理でした。(addEventListenerの第3引数の意味 | JavaScript プログラミング解説)

そこでflexコンテナにpaddingを設定してマウスポインタがflexコンテナを出るときのイベントを受け取ってツールチップ表示を消すようにしました。

padding:1pxではonmouseoutイベントが発生しなかったので3pxに設定しました。


Calendar_Blogger/Calendar_Blogger.js at fbf9905c60785f14aa74f6374b7e8e728870f9ca · p--q/Calendar_Blogger

これで解決と思ったのですが、flexコンテナからはみ出たツールチップからflexコンテナを経由せずにカレンダーからマウスポインタが出たときはやはりツールチップ表示が消えません。

iOS Safariではonmouseoverはタップで起動しますが、onmouseoutは効いていない感じです。

参考にしたサイト


addEventListenerの第3引数の意味 | JavaScript プログラミング解説
イベントバブリングの解説。

イベントハンドラ | JavaScript プログラミング解説
イベントハンドラの登録方法には要素のプロパティとして登録する方法とイベントリスナとして登録する二つの方法があります。

イベント | JavaScript プログラミング解説
targetがイベントを発生させたオブジェクト、currentTargetがイベントハンドラが登録されたオブジェクトになります。

次の関連記事:Blogger:カレンダー(5)Calendar_Bloggerモジュールの作成その4

PR

0 件のコメント:

コメントを投稿