誰もが知っておくべきjQueryのTips

煽りタイトルを付けようと思ったら元からそんなタイトルだった。
ということで以下は[jQuery Tips Everyone Should Know](https://github.com/AllThingsSmitty/jquery-tips-everyone-should-know)の日本語訳です。

イタリックは元記事にはない訳者(私だ)による補足です。

# jQuery Tips Everyone Should Know

これは、とても役に立つjQueryのTips集だぞ。

## Checking If jQuery Loaded

jQueryで何かするには、最初にjQueryがロードされてるか確認する必要があるぞ。

```php
	if (typeof jQuery == 'undefined') {
	  console.log('jQueryがない！');
	} else {
	  console.log('jQueryがある');
	}
```

残念ながら君はのけものだ。

## Use .on() Binding Instead of .click()

`.on()`は複数のイベントを追加できるなど、明らかに`.click()`より優位なのでonを使うべきだ。

```php
	.on('click tap hover')
```

このバインドは後から動的に追加した要素にも自動的に適用されるから、一回書けばいちいち手動でバインドを追加する必要は無いぞ。
あとnamespaceも書ける。

```php
	.on('click.menuOpening')
```

namespaceを使うと[特定のイベントだけ解除する](http://qiita.com/yuku_t/items/89044987d45ec58ea7c5)とかできて便利だぞ。

## Back to Top Button

`animate`と`scrollTop`を使うだけでTOPへ戻るボタンが簡単に作れるぞ。
プラグインも何もいらない。

```php:index.js
	// 戻るボタン
	$('.container').on('click', '.back-to-top', function (e) {
	  e.preventDefault();
	  $('html, body').animate({scrollTop: 0}, 800);
	});
```

```php:index.html
	<!-- HTMLタグ -->
	<div class="container">
	  <a href="#" class="back-to-top">TOPへ戻る</a>
	</div>
```

scrollTopの値を変更すると、スクロールバーの進む先が変わるぞ。
上のソースがやっているのは、800ミリ秒かけて最上部にスクロールするアニメーションだ。

注意：scrollTopには[バグがある](https://github.com/jquery/api.jquery.com/issues/417)から見とけよ。

## Preload Images

hoverで表示される画像など、最初からは表示されない画像をたくさん使っている場合、それらはプリロードしておくといいぞ。

```php
	$.preloadImages = function () {
	  for (var i = 0; i < arguments.length; i++) {
	    $('<img>').attr('src', arguments[i]);
	  }
	};
	$.preloadImages('img/hover-on.png', 'img/hover-off.png');
```

_せっかくjQuery使ってるんだから`$.each`とか使った方がいいのではなかろうか。_

## Checking If Images Are Loaded

画像の読み込みが完全に終わってからスクリプトを進めたい場合もあるだろう。

```php
	$('img').on('load', function () {
	  console.log('全画像読み込み終わった');
	});
```

`img`タグを他のidやclassに置き換えれば、特定の画像がロードされたことを検出できるぞ。

## Fix Broken Images Automatically

リンク先の画像が存在しなくて読み込めなかった場合、そのリンクを一個一個調べて修正するのは大変だ。
ちょっと以下のコードを書いておくと代わりに壊れ画像を表示してくれるぞ。

```php
	// 画像の読み込みに失敗したらかわりにimg/broken.pngを表示する
	$('img').on('error', function () {
	  if(!$(this).hasClass('broken-image')) {
	    $(this).prop('src', 'img/broken.png').addClass('broken-image');
	  }
	});
```

あるいは以下のように書けば読み込めなかった画像を隠してくれるぞ。

```php
	$('img').on('error', function () {
	  $(this).hide();
	});
```

_いや、ちゃんとlintなりソフトなりで調べて修正しろよと。_

## Post a Form with AJAX

jQueryはajaxメソッドでテキスト、HTML、XML、JSONなんかを簡単に送信できるぞ。
JavaScriptでフォームを送信する場合、`val()`メソッドでユーザ入力値を取得できるぞ。

```php
	// sign_up.phpに3値をPOSTする
	$.post('sign_up.php', {
	  user_name: $('input[name=user_name]').val(),
	  email:     $('input[name=email]').val(),
	  password:  $('input[name=password]').val(),
	});
```

ただ毎回個別に`val()`を呼び出すのは高コストだ。
かわりにフォームの中身をまとめて文字列にする[serialize()](https://api.jquery.com/serialize/)があるのでそちらを使った方がベターだ。

```php
	$.post('sign_up', $('#sign-up-form').serialize());
```

## Toggle Classes on Hover

クリックできる要素をわかりやすくするため、hoverしてるときだけ演出を変えたいときがあるだろう。
以下のように書けば、hover時にクラスを追加して、離れたときにクラスを削除できるぞ。

```php
	// btnクラスにhoverしているときだけhoverクラスを追加
	$('.btn').on('hover', function () {
	  $(this).addClass('hover');
	}, function () {
	  $(this).removeClass('hover');
	});
```

あとは必要なcssを追加するだけだ。
そして`toggleClass`を使えばもっと簡単に書けるぞ。

```php
	$('.btn').on('hover', function () {
	  $(this).toggleClass('hover');
	});
```

注意：上記の場合は単に`:hover`疑似クラス使えばいいだけだしそちらの方が高速だけど、このような書き方があるということ自体は知っておく価値はあるぞ。

## Disabling Input Fields

ユーザが特定の動作を行う(たとえば「利用規約に同意する」をチェックする)まで、フォームの送信ボタンや一部のテキスト入力欄などを無効にしておきたい場合があるだろう。
属性`disabled`を入れるだけで簡単に実装できるぞ。

```php
	$('input[type="submit"]').prop('disabled', true);
```

同意したら今度は`disabled`をfalseにするだけでボタンが有効になる。

```php
	$('input[type="submit"]').prop('disabled', false);
```

## Stop the Loading of Links

aタグを押してもリンク先に飛ばさないようにしたり、ページのリロードをさせたくない場合があるだろう。
あるいは他のスクリプトを呼び出したりしたいかもしれない。
そういうときにはデフォルトの動作を止めることができる。

```php
	$('a.no-link').on('click', function (e) {
	  e.preventDefault();
	});
```

_[preventDefault](https://developer.mozilla.org/ja/docs/Web/API/Event/preventDefault)はjQueryの機能ではない。_

## Cache jQuery Selectors

同じセレクタを何度も使いたいときに`$('.element')`を毎回書いていると、そのたびにDOM全体を検索しに行ってしまう。
かわりにセレクタは一回だけ実行し、結果を変数に入れておくとよい。

```php
	var blocks = $('#blocks').find('li');
```

最初に一度実行しておくだけで、以後は毎回DOMを見に行ったりせずに`blocks`を使い回すことができる。

```php
	$('#hideBlocks').on('click', function () {
	  blocks.fadeOut();
	});
	$('#showBlocks').on('click', function () {
	  blocks.fadeIn();
	});
```

セレクタをキャッシュしておくことで、簡単にパフォーマンスを上げることができるぞ。

_当然だが、セレクタの実行後にDOMを変更してもキャッシュの内容は変わらないので注意すること。_

## Toggle Fade/Slide

フェードやスライドはアニメーションで頻繁に使う演出だ。
ユーザが何かをクリックしたら要素を表示したいという場合は`fadeIn`や`slideDown`を使うと簡単だ。
しかしクリックしたら隠したり表示したりを繰り返したい場合、jQueryには専用のメソッドがある。

```php
	// フェード繰り返し
	$('.btn').on('click', function () {
	  $('.element').fadeToggle('slow');
	});
	// スライド繰り返し
	$('.btn').on('click', function () {
	  $('.element').slideToggle('slow');
	});
```

## Simple Accordion

超簡単なアコーディオンメニューの例だ。

```php
	// contentは最初は全部隠す
	$('#accordion').find('.content').hide();

	// accordion-headerボタンを押したらcontentを表示する
	$('#accordion').find('.accordion-header').on('click', function () {
	  var next = $(this).next();
	  next.slideToggle('fast');
	  $('.content').not(next).slideUp('fast');
	  return false;
	});
```

これ以外に必要なものは、メニューのHTMLだけだ。

## Make Two Divs the Same Height

複数のdivが存在し、中身がばらばらである場合に、全ての要素を同じ高さに合わせたい。

```php
	$('.div').css('min-height', $('.main-div').height());
```

この例は`min-height`を設定している。
`.div`要素は`.main-div`要素より大きくなることはあるが小さくなることはない。

もっとよりよい方法は、最も高さのある要素に全ての要素の高さを合わせることだ。

```php
	var $columns = $('.column');
	var height = 0;
	$columns.each(function () {
	  if ($(this).height() > height) {
	    height = $(this).height();
	  }
	});
	$columns.height(height);
```

全ての列の高さを揃えたい場合は以下のようにする。

```php
	var $rows = $('.same-height-columns');
	$rows.each(function () {
	  $(this).find('.column').height($(this).height());
	});
```

注意：これはCSSで調整した方が手っ取り早いが、JavaScriptで行わないといけないこともあるから知っておく価値はある。

## Open External Links in New Tab/Window

同じドメイン内のリンクにはそのまま進み、外部リンクは別ウィンドウで表示させたい場合は以下のように書けばよい。

```php
	$('a[href^="http"]').attr('target', '_blank');
	$('a[href^="//"]').attr('target', '_blank');
	$('a[href^="' + window.location.origin + '"]').attr('target', '_self');
```

注意：`window.location.origin`はIE10では動かない。対応したい場合は[このfix](http://tosbourn.com/a-fix-for-window-location-origin-in-internet-explorer/)を入れるとよい。

## Find Element By Text

[contains()セレクタ](https://api.jquery.com/contains-selector/)は、引数の文字列が含まれている要素を見つけてくれる。
以下は引数の文字列が入ってない要素を非表示にする例だ。

```php
	var search = $('#search').val();
	$('div:not(:contains("' + search + '"))').hide();
```

## Trigger on Visibility Change

別のタブを開いたとかウィンドウを最小化したとかで画面が表示されなくなったとき、また再び画面が表示されたときを[visibilitychange](https://developer.mozilla.org/ja/docs/Web/Reference/Events/visibilitychange)でトリガーできるぞ。

```php
	$(document).on('visibilitychange', function (e) {
	  if (e.target.visibilityState === 'visible') {
	    console.log('タブが画面に表示された');
	  } else if (e.target.visibilityState === 'hidden') {
	    console.log('タブが隠れた');
	  }
	});
```

## Ajax Call Error Handling

Ajax呼び出しが404や500を返してきたときはエラーハンドラが実行される。
その際エラーハンドラが定義されてなければもうjQueryのコードは動かなくなってしまう。
以下のコードでグローバルなAjaxエラーハンドラが定義できるぞ。

```php
	$(document).on('ajaxError', function (e, xhr, settings, error) {
	  console.log(error);
	});
```

_きちんとDeferredを使えと。_

## Chain Plugin Calls

メソッドチェーンを使えば、jQueryが何度も同じオブジェクトを作成してしまう無駄を省けるぞ。
以下のようなコードがあったとしよう。

```php
	$('#elem').show();
	$('#elem').html('bla');
	$('#elem').otherStuff();
```

メソッドチェーンでコストは大幅に改善する。

```php
	$('#elem')
	  .show()
	  .html('bla')
	  .otherStuff();
```

もしくは要素を変数にキャッシュしてもいい。

```php
	var $elem = $('#elem');
	$elem.hide();
	$elem.html('bla');
	$elem.otherStuff();
```

チェーンとキャッシュをうまく使いこなせば、より簡潔で高速なコードを書けるようになるだろう。

## Sort List Items Alphabetically

リストに大量のアイテムが並んでいるとしよう。
そのリストはCMSによって作成されたのだが、ID順に並んでいるのでアルファベット順にソートしなければならない。

```php
	var ul = $('#list'),
	lis = $('li', ul).get();
	lis.sort(function (a, b) {
	  return ($(a).text().toUpperCase() < $(b).text().toUpperCase()) ? -1 : 1;
	});
	ul.append(lis);
```

できたー！全部できたー！

----

# 訳者による感想

## Everyone Should Know？

正直Tipsとしてはかなり微妙。
なんかもっとこう驚きのアイデアなんかが書かれてるのかと思っていたら、特になんてことない普通の内容しかなかった。