読者です 読者をやめる 読者になる 読者になる

つばさのーと

つばさの日常を綴るのーと

デザイナーでも覚えておきたい、jQueryセレクタのちょっと便利な使い方

f:id:tsubasa123:20170114175028j:plain

 

こんにちは、つばさ(@tsubasa123)です。

 

はてなブログのカスタマイズにもだいぶ慣れてきた今日この頃。カスタマイズを行うにあたってjQueryの使い方、特に応用したセレクタの使い方を知っておくと捗ることが多いので、勉強と備忘録を兼ねてこの記事で使い方をまとめておこうと思います。

 

ブログカスタマイズに限らず、ちょっとしたWEB制作にも応用は可能な内容だと思います。特にJavaScriptとか苦手だし、と思っているデザイナーさん、覚えておくと時間短縮になるかもしれませんのでぜひ参考にしてみてください。

 

jQueryのセレクタの基本的な使い方

 

紹介するまでもないと思いますが念のため。

 

$('#hoge');

 

id="hoge"の要素にアクセスするためには上記のようにセレクタを指定します。id指定の時は「#」をつけます。id属性の値は1つのページで重複することはない(してはいけない)ので、このセレクタでの取得結果は必ず1つになります。

 

$('.moge');

 

class="moge"の要素にアクセスするためにはこのように。class指定の時は「.」ですね。クラス指定は複数の要素に同じ値を利用することができる(というか利用するのが普通)なので、このセレクタでの取得結果は複数になることが多いです。

 

この結果にメソッドチェーンで次の処理を実行すると、取得結果の全要素に処理が適応されることになります。例えば、

 

$('.hello-btn').on('click', function() {
    alert('hello!');
}).css({color: 'red'});

 

このように記述すると、"hello-btn"というクラスが指定された要素(ボタンとか)の全ての文字が赤くなり、クリックされると'hello'という文字が書かれたダイアログが表示されるようになります。

 

ここまでが基本的な使い方になると思います。そんなに難しいことはないですね。id属性の値を使うなら「#」を、class属性の値を使うなら「.」を使いましょう、ということです。

 

クラスの指定が煩雑になる

 

先ほどの2つの指定だけでもがんばれば色々なパターンや条件でも特定の要素だけを取得することが可能です。ですが、その分だけクラスをたくさん指定しなくちゃいけなくなってしまうんですよね。

 

<ul>
<li class="navi">ナビ1</li>
<li class="navi">ナビ2</li>
<li class="navi">ナビ3</li>
<li class="navi">ナビ4</li>
<li class="navi">ナビ5</li>
</ul>

 

このようなナビゲーションがある場合、naviというクラスに対して各ナビゲーション共通の装飾を指定したりして利用しますが、全て同じクラス名が指定されているため、先ほどのような書き方では特定の要素だけを取得して処理を行うことができません。

 

単純なクラス名の指定だけで特定の要素を取得するには、

 

<ul>
<li class="navi navi1">ナビ1</li>
<li class="navi navi2">ナビ2</li>
<li class="navi navi3">ナビ3</li>
<li class="navi navi4">ナビ4</li>
<li class="navi navi5">ナビ5</li>
</ul>

 

このように各要素に任意のクラス名を指定する必要があります。まぁ、数が少なければそれでもよいかもしれませんが、規模が大きくなるにつれて管理が煩雑になっていきます。なにより、本来は装飾のために指定するクラスをJavaScriptの都合で増やすのはちょっとおかしな話です。そもそもクラスを付け足すことができないケースもあったりします。

 

セレクタをちょっと工夫しよう

 

同一のクラスを持つ複数の要素から特定の要素を取得したい、といった簡単な条件の場合はクラスを増やして対応するのではなく、セレクタを工夫して対応すると色々と捗ります。

 

jQueryのセレクタは先ほどの単純な「完全一致」だけでなく、「前方一致」や「後方一致」、「部分一致」など様々な条件を付けて指定することができるようになっています。これ、意外と知られてない機能のようなんですよね。

 

もちろんfind()メソッドのようなトラバース系(要素を探す系)のメソッドを繋げても絞り込みはできますが、セレクタの応用で一発で指定ができるとなんか気持ちいいんですよ。使えるようになって損はありませんのでぜひ参考にしてみてください。

 

ちなみに、ご存知だと思いますが、セレクタに利用できる属性はid属性とclass属性に限定されているわけではありません。name属性やhref属性、ユーザーが任意に指定することができる独自データ属性(data-hoge=""みたいなやつ)を対象にすることも可能です。

 

ですので、無理にクラスを追加したりしなくてもその他の属性の値のルールを利用して上手にセレクタを指定することができる場合も結構あったりします。target="_blank"が指定されているリンクだけに何かしたい、みたいなケースでわざわざクラスを指定しているデザイナーさんを見かけたことがありますが、そんな必要はないわけですね。

 

できるだけ利用シーンを想定した形でご紹介していきたいと思います。それでは、ちょっと応用したセレクタ紹介スタートです!

 

前方一致で要素を探索

 

任意の属性が持つ値を前方一致で探索することが可能です。セレクタを指定する際に「^」を指定すると完全一致から前方一致に条件が変更になります。ちなみに「^」の記号は「キャレット」と呼びます。はい、ちょっと前まで知りませんでした。

 

$('a[href^="#"]').addClass('internal-links');

 

このように指定することで、aタグのhref属性の値が「#」から始まる要素のみを取得することができます。目次とか内部リンクに対して追加の装飾がしたくなったり、クリックイベント発生時になにかフックして処理を追加したいときなんかに利用することができます。

 

他にも

 

$('a[href^="https"]').on('click', function(){});

 

これでaタグのリンクが「https」から始まる要素のみを取得することができます。これもなんかに使えそうですね、すぐには思いつきませんが。

 

後方一致で要素を探索

 

先ほどとは反対に、任意の属性が持つ値を後方一致で探索します。セレクタを指定する際に「$」を指定すると完全一致から後方一致に条件が変更になります。

 

$('img[src$=".gif"]');

 

これで拡張子が「gif」の画像要素のみを取得することが可能になります。これは私的に意外と利用頻度が高い指定方法です。拡張子が「pdf」のものにアイコンをつけたいです、みたいな要望に対応するときに結構使っています。ワードとかエクセルでも言われたりしますね。

 

$('a[href$="index.html"]');

 

こちらはURLの末尾が「index.html」で終わるものを取得します。詳しい説明は省略しますが、SEOとかの関係でURLを正規化したいときに使ったりできそうです。URLの文字列から「index.html」を削除してリダイレクトさせればよさそう。これはやったことないですが、覚えておこうと思い書いてみました。

 

部分一致

 

次は部分一致。セレクタを指定する際に「*」を指定します。

 

$('a[href*="example.com"]');

 

aタグのリンクに任意のドメインが含まれているものを取得することができます。特定のサイトに遷移させる前に何か処理を挟むことができるようになります。離脱を防ぎたい時や、ちょっとしたバリデーションを行いたいときに使えたりします。

 

が、あまり部分一致は使ったことがないですね。セレクタのかわりにメソッドを経由して正規表現を使ったほうがより複雑なフィルタリングができますので、そちらを使う機会の方が多いと思います。まぁ、参考までに覚えておいてもよいのかなと。

 

一致しない

 

今までとは反対に、セレクタに一致しない要素を取得することも可能です。セレクタを指定する時に「!」を指定します。

 

$('a[target!="_blank"]');

 

これで属性がtarget="_blank"以外のリンクを取得できます。他にも、

 

$('ul.navi > li[class!="navi3"]');

 

このように指定すればナビゲーションの中の特定の要素以外に対して処理を行うことができるようになります。このセレクタの指定は今まで知らなくて損してたなーと思ったもので、この記事を書くきっかけにもなった指定方法です。結構使い勝手がよさそうなので覚えておくとよいかもです。

 

ちなみに、今まで私がやっていた方法はこんな感じです。

 

$('ul.navi > li:not(.navi3)');

 

:not()指定を単独のセレクタと認めていいのか難しいところですが、こちらの方がより細かい条件指定ができるようになります。繋げていけばそれだけ複雑な条件が書けますので。読みにくくなっちゃいますけどね。フィルタリングの条件に応じて使い分けが必要です。

 

「-」で繋げた文字列と一致

 

ちょっとわかりにくいので簡単なサンプルを。

 

<button class="btn">ボタン1</button>
<button class="btn-alert">ボタン2</button>
<button class="btn-info">ボタン3</button>
<button class="btn-success">ボタン4</button>

 

このようにクラスを指定されたボタン要素に対して、

 

$('button[class|="btn"]');

 

のように、「|」を指定することでその文字が「-」で繋げられたクラスの一部に使われている要素のみ取得することができます。先の例だとボタン1以外の3つの要素を取得できることになります。

 

$('button[class^="btn-"]')

 

と、前方一致でも同じような結果を得ることができますが、クラス名が長くて複数の文字が「-」で繋げられている場合は「|」を使ったほうがスマートかもしれません。

 

正直、いまいち使いどころがわからない指定方法ですが、Bootstrapなどのように複数のクラスを組み合わせて使うようなフレームワークなんかと相性がいいのかもしれません。CSSに詳しい方がいましたら教えていただけると嬉しいです。

 

どれかひとつでも一致

 

これもちょっとサンプルを。

 

<button class="btn red">ボタン赤</button>
<button class="btn green">ボタン緑</button>
<button class="btn blue">ボタン青</button>

 

このように複数のクラスを指定されたボタン要素に対して、

 

$('button[class~="red"]');

 

のように、「~」を指定することで、複数のクラスの中の1つでも一致した要素を取得することができるようになります。先の例だと1爪のボタンが取得可能。これは便利。完全一致だと全部指定する必要がありますからね。複数のクラスからデザインを構成するようなフレームワークを使う場合は抑えておきたい指定方法です。

 

$('button[class*="red"]');

 

部分一致でも同じようなことができますが、他のクラスで一致する文字列が偶然使われているとそちらも取得されてしまいます。ちょっと強引ですが、

 

<button class="btn red">ボタン1</button>
<button class="btn reduce">ボタン2</button>

 

こんな感じでクラスが指定されていると、部分一致で探索すると両方のボタンが取得されてしまいます。適宜、使い分けるようにしましょう。

 

今までの条件を復号指定

 

セレクタは1つだけでなく、複数組み合わせて使うことも可能です。

 

$('li[class^="navi1"][class~="active"]');

 

このようにする指定すれば、「navi1から始まるクラス名を持つ」かつ「activeというクラスも指定されている」という条件を満たす要素のみを取得できます。

 

これも上手く組み合わせればキレイにかけると思いますが、部分一致の時同様、メソッドを利用してフィルタリングした方がわかりやすく保守しやすいコードになることがおおいかなというのが私の感想です。条件の複雑さに応じて使い分けると良いかと。

 

奇数・偶数・最初・最後で指定

 

これは簡単ですね。

 

$('li[class="navi"]:even'); // 奇数
$('li[class="navi"]:odd'); // 偶数
$('li[class="navi"]:first'); // 最初
$('li[class="navi"]:last'); // 最後

 

指定位置とそれ以降とそれ以前

 

指定位置はよく使いますが、それ以降とそれ以前は使ったことがないかもですね。指定位置は0から始まるのでデザイナーさんは注意してお使いください。

 

$('li[class="navi"]:eq(2)'); // 3番目の要素
$('li[class="navi"]:gt(2)'); // 4番目以降の要素
$('li[class="navi"]:lt(2)'); // 2番目以前の要素

 

後者2つのメソッドは指定された順番の要素自身は取得対象となりませんのでそちらもお気を付けください。あと、直感的ではないので私はあまり使いませんが、

 

$('li[class="navi"]:eq(-2)');

 

負の数を指定すると後ろから数えて要素を指定できるようになります。

 

指定した子要素をもつ要素

 

最後は使いそうで使わないやつを。

 

$('li[class^="navi"]:has(a[href^="#"])');

 

「navi」から始まるクラス名のリスト要素のうち、URLが「#」で始まるリンク要素のみを取得します。これくらいならまだわかりやすいですが、やはり複雑な指定をするときはセレクタだけでなくフィルタリングメソッドの導入を考えたほうが良いかなと。

 

さいごに

 

途中から調べるのが面白くなってついつい長くなってしまいましたが、ちょっと応用したセレクタの指定方法のご紹介でした。

 

クラス指定がやはり一番基本的な使い方にはなりますが、ここでご紹介したようにその他の属性に対して一致条件を指定して使うだけでもそこそこ細かく要素の取得結果を変更することができます。

 

記事中でも何回か言いましたが、むやみにセレクタを複雑にすると逆に保守が大変になる可能性があります。その際は素直にフィルタリングメソッドを使ったほうがよいでしょう。ケースバイケースでうまく使い分けられるようになると今後の作業が捗ると思います。

 

今度はフィルタリングメソッドの便利な使い方についてもまとめてみたいと思います。あっちは高度なことができるから今回よりもさらに長くなりそうな…

 

ではでは、最後までお付き合いいただきありがとうございました。