質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

88.78%

「普通のクリック」と「別タブ/ウィンドウで開くクリック」を区別したい

解決済

回答 7

投稿 編集

  • 評価
  • クリップ 2
  • VIEW 12K+

sounisi5011

score 713

JavaScriptでリンクをクリックしページを移動しようとする操作は、通常clickイベントで検出します。

例えば、メニューのページへのリンクをクリックしたらページ移動せず、現在のページ内でメニューを表示する場合などにこのような手法が用いられます。
この場合、JavaScriptが利用できない場合や「右クリック→新しいタブ/ウィンドウで開く」を実行した場合には本来のページ移動が行われ、メニューのみのページが開かれることになります。

しかし、clickイベントを検出している影響で、別タブで開くためのクリックも普通のクリックと一緒に扱われてしまいます。
上述した例の場合、メニューへのリンクを「Ctrl+クリック」(別タブで開く)や「Shift+クリック」(別ウィンドウで開く)、「中クリック」(別タブで開く)した場合、別のタブ/ウィンドウで開くという期待する操作が実行されず、メニューはページ内で展開されてしまいます。

これを解決するには、普通のページ移転に使用するただのクリックと、「Ctrl+クリック」等、別のタブ/ウィンドウで開く為のクリックをclickイベントで区別しなくてはなりません。
clickイベントで、普通のクリックと、別のタブ/ウィンドウで開く為のクリックを区別する良い方法はありますか?
  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 7

check解決した方法

+4

MediaWikiのMedia Viewerがまさにこの質問で求める動作をしていたためデバッグを行ってみたところ、以下の処理により判定を行っていました。

/*
 * jQueryが内部的に行う`event.which`プロパティの定義
 * https://github.com/jquery/jquery/blob/3.3.1/src/event.js#L636-L662
 */
var button = event.button;
// Add which for click: 1 === left; 2 === middle; 3 === right
// Note: button is not normalized, so don't use it
if (!event.which && button !== undefined) {
    event.which = (button & 1 ? 1 : (button & 2 ? 3 : (button & 4 ? 2 : 0)));
}

/*
 * 判定箇所
 * https://github.com/wikimedia/mediawiki-extensions-MultimediaViewer/blob/6b83fca574e3dcc2fa4526117f88940dcfc06f30/resources/mmv/mmv.bootstrap.js#L431-L434
 */
if ((event.button !== 0 && event.which !== 1) || event.altKey || event.ctrlKey || event.shiftKey || event.metaKey) {
    // 別タブ/ウィンドウで開くクリック
} else {
    // 普通のクリック
}

変数eventは、対象のイベントのイベントオブジェクトです。
判定としては、event.buttonまたはevent.whichで「左クリック以外」かの判定と、CtrlやShift等の特殊キーが押下されているかをORで判定していました。

MediaWikiは、世界で5番目に人気のあるウェブサイトWikipediaで使用されているシステムです。
当然、より多くのユーザに対応するため、様々な環境で検証を行い、動作を確認しているコードのはずです。
よって、信頼性は十分であり、「普通のクリック」と「別タブ/ウィンドウで開くクリック」を区別する方法として、これが適切であると考えます。


ちなみに、IE8以下のInternet Explorerでは、mousedownmouseupmousemoveイベント以外の場合は、どのようなクリックであってもevent.buttonの値が0になってしまいます。

jQuery で 右クリックと左クリックを判別 - galife

ちなみに、clickイベント時、IE8 だと button プロパティが 0 にしかならないので使えない…

button property (Internet Explorer)

This property is used with the onmousedown, onmouseup, and onmousemove events. For other events, it defaults to 0 regardless of the state of the mouse buttons.

このため、clickイベントではクリックの種類を判定できず、利用できません。

既にセキュリティサポートすら切れた古の遺産たるIE8以下を考慮する状況は限られると思います。しかし、もしIE8以下でも動く処理が必要な場合は、クリックをmousedownイベントやmouseupイベントで検知するようにしましょう。


また、仕様ではevent.whichプロパティは削除されており、代わりにevent.buttonプロパティとevent.buttonsプロパティの使用が推奨されています。

MouseEvent.which - Web APIs | MDN

Non-standard
This feature is non-standard and is not on a standards track. Do not use it on production sites facing the Web: it will not work for every user. There may also be large incompatibilities between implementations and the behavior may change in the future.

The standard alternatives to this property are MouseEvent.button and MouseEvent.buttons.

event.whichは今後ブラウザからも消えていくプロパティです。
しかし、jQueryでは逆にevent.buttonよりevent.whichの使用を推奨する記述があり、このままでは今後のWeb標準に対応できません。

event.which | jQuery API Documentation

Use event.which instead of event.button.

この事を視野に入れた、更なる修正が必要かもしれません。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

+3

単に Ctrl や Shift などが押されているかどうかだけならイベントオブジェクトで検出できると思いますが、

    document.getElementById('link').addEventListener('click', function(ev){
        if (ev.altKey || ev.shiftKey || ev.ctrlKey) {
            return;
        }
        ev.preventDefault();
        console.log(ev);
    }, false);

普通のクリックと、別のタブ/ウィンドウで開くためのクリックは、ブラウザの設定によると思うので、検出は難しいと思います(アドオンとかで変えられそうなので)。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2015/07/21 10:30 編集

    > 普通のクリックと、別のタブ/ウィンドウで開くためのクリックは、ブラウザの設定によると思うので、検出は難しいと思います(アドオンとかで変えられそうなので)。

    まさにそこが、この動作を容易に実現できない理由であり、ここで質問した理由でもあります。
    左クリックの判定や、Ctrlキーなどはイベントオブジェクトで判別できるのですが…質問本文にない他の操作等は考慮しきれるかどうか…
    アドオンに関しては利用者の自己責任とも考えられるので対応は見送りますが、ブラウザのデフォルトの機能として備わる「特殊なクリック」は正しく判別したいです。

    キャンセル

+1

リファラ(document.referrer)から、ページ遷移を判定すれば実現できます。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2015/07/21 10:25

    移転する"前"のクリックイベントの段階で判定する事が目的です。
    ただ、実際に移転した後に判定する方法が一番確実であるのも確かです。

    キャンセル

+1

こういうことでしょうか?

ttp://www.programming-magic.com/20090127231544/

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2015/07/21 10:34

    このあたりの情報についてはあらかた調べてあります。
    そしてこれらの情報を合わせれば、「Ctrl+クリック」、「Shift+クリック」、「中クリック」を判別する事そのものは可能です。

    ですが、この問題の本質はそこではありません。
    質問に書いた操作はあくまで例に過ぎず、これ以外の「別のタブ/ウィンドウで開く為のクリック」が存在する可能性があります。
    これを正しく識別することが本質問の求める要件です。

    キャンセル

+1

大抵のブラウザの設定では、左クリックは開く、中クリックは新しいウィンドウで開くになっていることと思います。
そこで、そうでない設定をしている人達は置いておいて、中クリックを新しいタブで開くためのものとして扱うのはどうでしょう。
event.button - MDN
event.button==0なら左クリック、event.button==1なら中クリックです。

ブラウザが設定をJavaScriptに知らせる機能というのは見つかりませんでした。どうしても設定を知りたいなら、ユーザーがどのイベントを起こしたら同時に新しいウィンドウが開いているかを監視すればできると思います。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

-1

同じウインドウ内で遷移
location.href=URL

別タブで表示
window.open(URL, '_blank')

…ということでしょうか。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2015/07/21 07:07 編集

    違います。
    addEventListener等で設定するclickイベントで、普通の「ページ移転クリック」と質問に書いた「別のタブ/ウィンドウで開く為のクリック」を区別したいということです。

    キャンセル

  • 2016/11/17 10:16

    質問を正しく理解できていない

    キャンセル

-1

遷移後にhistory.lengthを見るというのはどうでしょうか

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2015/07/21 10:30

    移転する"前"のクリックイベントの段階で判定する事が目的です。

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 88.78%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

同じタグがついた質問を見る