THE HAM MEDIA BLOG

もっと少量のjQueryコードでHTMLテーブルの列にリンク先を指定できるようにする方法

Clip to Evernote このエントリーをはてなブックマークに追加
カテゴリ:
jQuery
タグ:
jquery
リンク

いつもブログを読んでいる『かちびと.net』に書かれていた内容で、たしかにシンプルなコードで、これは覚えておくと便利だなーなんて思ったコードだったのですがちょっとコード量が多いなんて気がしてしまったという。

で、なんとかもっとシンプルに、且つ、知っているとカッコイイ!と思うメソッドを使ってできないものかと思って試してみたところ、意外とすんなり、さらに少量化することができたのでご紹介しておきます。

まずは同じコードとそのデモ

jQuery(function($) {
  $('tbody tr[data-href]').addClass('clickable').click( function() {
    window.location = $(this).attr('data-href');
  }).find('a').hover( function() {
    $(this).parents('tr').unbind('click');
  }, function() {
    $(this).parents('tr').click( function() {
      window.location = $(this).attr('data-href');
    });
  });
});
地名 読み方 En 詳細 その他
東京 とうきょう Tokyo 日本の事実上の首都がある ダミーリンク
京都 きょうと Kyoto 794年に日本の首都に定められた ダミーリンク
静岡 しずおか Shizuoka 静岡市と浜松市の2つの政令指定都市を有する ダミーリンク
大阪 おおさか Osaka 関西地区の経済・文化の中心地 ダミーリンク

※紹介されていたデモと同じ

ちょっとしたコードの解説

せっかくなので、どういうコードなのかというのを、さらっとみましょう。

jQuery(function($) {

  //data-hrefの属性を持つtrを選択しclassにclickableを付加
  $('tbody tr[data-href]').addClass('clickable')
  
    //ata-hrefの属性を持つtrをクリックしたら動作
    .click( function() {
  
    //data-href属性の値をattr()メソッドで取得し、ページを遷移させる
    window.location = $(this).attr('data-href');
  
  //もしtr内にa要素があれば、a要素にホバーした時に以下動作させる
  }).find('a').hover( function() {

    //a要素の先祖要素trのクリックイベントを解除
    $(this).parents('tr').unbind('click');
  
    //a要素からホバーが抜けたら以下実行
  }, function() {

    //a要素の先祖要素trにクリックイベントを付加
    $(this).parents('tr').click( function() {
  
      //data-href属性の値をattr()メソッドで取得し、ページを遷移させる
      window.location = $(this).attr('data-href');
    });
  });
});

なぜa要素を見つけて、そのa要素にhoverしている時にtrのクリックイベントをunbindさせているのかというと、これをしないと、a要素のリンクと、data-hrefにセットしたリンクがどちらも動作してしまう場合があるためです。(例えばa要素のリンクを_blankで開く時など)

そんな状況の時に、a要素だけを優先して動作させるために、trのクリックイベントを解除しているというわけです。

こんなことできないかなーという疑問

と、ここで自分がもっと短くできないかなって思ってしまったのが、そのhoverイベントの部分。このコードだと、クリックしようがしまいが、a要素にマウスをのせるたびに、ちょっとした無駄な動作がでてしまうという。気にする程ではないんですけどね。

でも思ったのは、a要素クリックした時に、a要素の先祖に、そのクリックイベントがバブリング(ある要素でイベントが発生した時に、その親要素にも同じイベントが伝わっていく仕組み)しなきゃいいんじゃないか?もしくはバブリングしても、a要素じゃない時にだけ動作するようにしたらいいじゃないかーなんて思った。

で、たまたま先日のTwitterのTLでの@t32kのこーちゃんの発言がきっかけで、次に紹介するコードが思い浮かんだので、試してみた。

さらに少量のコードにする

先に注意ですが、この先紹介するコードは、jQuery1.4.3以降のバージョンで動作するものになっています。理由は後ほど。

まぁ、まずはコードとその動作でもを見てみましょ。

jQuery(function($) {
  $('tr[data-href]').addClass('clickable')
    .click(function(e) {
      if(!$(e.target).is('a')){
        window.location = $(e.target).closest('tr').data('href');
      };
  });
});

先程のhover時の処理などがなくなった分すっきり!

地名 読み方 En 詳細 その他
東京 とうきょう Tokyo 日本の事実上の首都がある ダミーリンク
京都 きょうと Kyoto 794年に日本の首都に定められた ダミーリンク
静岡 しずおか Shizuoka 静岡市と浜松市の2つの政令指定都市を有する ダミーリンク
大阪 おおさか Osaka 関西地区の経済・文化の中心地 ダミーリンク

※さらに少量のコードで動作しているデモ

少量のコードでも、同じ動作しているのがわかるかと思います!

先ほど同様に、コードの解説もしちゃいます!

少量版のちょっとしたコードの解説と補足

jQuery(function($) {

  //data-hrefの属性を持つtrを選択しclassにclickableを付加
  $('tr[data-href]').addClass('clickable')
  
    //クリックイベント
    .click(function(e) {
  
      //e.targetはクリックした要素自体、それがa要素以外であれば
      if(!$(e.target).is('a')){
      
        //その要素の先祖要素で一番近いtrの
        //data-href属性の値に書かれているURLに遷移する
        window.location = $(e.target).closest('tr').data('href');
      };
  });
});

と、こんなコードになります。

仮にa要素をクリックしたとしても、分岐の時点でその判定をしているので、リンクが開くだけになる。ちなみに条件分岐をなくすと、イベントはバブリングするわけではないけど、a要素に一番近い先祖要素のtrに付いているdata属性を、td,thをクリックしたのと同じように探しにいって開いてしまうので、一度分岐が必要だという。

補足しておくと、is()はターゲット要素が指定した要素かどうかの判定をしてくれるメソッド。closest()は、説明に書いているように先祖要素で一番近い要素の選択。data()は、jQuery1.4.3以降にHTML5のカスタムデータ属性に対応し、data-hrefの属性であれば、.data('href')でその値を取得してくれる。(←jQuery1.4.3以降に対応というのはこのため。)

こういうのを知っておくのも便利!かつ、なんだかカッコイイ気がする。(あくまで個人的主観で、そしてどうでもいい。。。)

data-href属性を設定していないデモ

一応、data-href属性を入れていない場合のデモも紹介しておきます。

地名 読み方 En 詳細 その他
東京 とうきょう Tokyo 日本の事実上の首都がある wiki
京都 きょうと Kyoto 794年に日本の首都に定められた ダミーリンク
静岡 しずおか Shizuoka 静岡市と浜松市の2つの政令指定都市を有する ダミーリンク
大阪 おおさか Osaka 関西地区の経済・文化の中心地 wiki
北海道 ほっかいどう Hokkaido 日本国の最北端に位置する 北海道のホームページ

※動作の違いがわかるように東京と大阪はdata-linkをつけていません
また、北海道はtrにdata-hrefとリンクでtarget="_blank"をつけたアンカーを配置

紹介元のがダメというのでは全然なくて、もっとシンプルにするにはどうしたらいいのかなーと思って作ったものの紹介でした。

これよりもっとシンプルなコードもあるかもしれませんが、とりあえず、先に紹介されていたコードよりはシンプルになったので、よしとします。

追記

同じように思った方がいて、その方もエントリーしていました!

そこで指摘があったのですが、$(e.target).is('td,th')での判定をしていると、spanなどの要素が中に入った時に動作しなくなるという。ということで、早速修正しました。(上記内容は修正済です。)

それと、今回のマウスホバー時の、色変えはCSSでやっていますので、IEではその辺はうまくみれないと思いますが、今回のネタとは違うので省略します。

この記事へのコメント
はじめまして。
jQueryの知識が乏しく、こちらの記事を検索で見つけて非常に勉強になりました。
ちなみにこれをリンク先を新しいウィンドウで開くにはどうしたら良いのでしょうか?
Posted by メガネ at 2013年08月24日
コメントを書く
お名前: [必須入力]

メールアドレス: [必須入力]

ホームページアドレス:

コメント: [必須入力]

認証コード: [必須入力]


※画像の中の文字を半角で入力してください。

この記事へのトラックバック

トップに戻る