jQuery DOM操作あれこれ

# TL;DR
・jQueryでのDOM操作チートシート的な何か

# 何故書いた
 - webシステム開発の場からは、徐々に姿を消しつつありますが、レガシーなシステム、プロジェクトではまだまだ現役なjQuery。リファクタ等で自分自身や同僚も苦しんだ事があったので、あえて今書いてみました
    - 技術的な制約~~(&どう考えても謎すぎる政治的理由)~~等で、プロジェクトとしてjQueryを利用せざるを得ない環境に置かれて、開発やリファクタリングに苦しめられている方々の一助となれば幸いです

 
 - 最低限、DOMの操作に関して、今より更に**分かっていなかった**頃の自分が「**これは知れてよかった!**」と感じたapiや利用方法のみ、記載しています。不足、認識間違い等あるかもしれませんが、その際は生暖かく見守るかご指摘頂ければと思います

 

## DOMの取得
- まずはここから　
 - **『$』関数の第1引数**に**セレクタ文字列**を指定
 - 取得されるのは**jQueryオブジェクト**
      - **jQueryオブジェクトとは** ... かなり雑ですが、一旦**DOMそのもの**と捉えて頂いた上で、以降の内容をご覧頂けるとスムーズかもしれません
      - **セレクタ文字列とは** ... ざっくり言うとスタイルシート(css)で指定する**アレ**です。`.hoge-class`とか`body`とかを指定して、スタイル値を書いて行くと思いますが、その指定値と全く同じです。`.hoge-class`とか`body`がjQueryのDOM指定に欠かせない**アレ**、すなわち**セレクタ文字列**にあたります


```js:例
$('.hoge-class') // jQueryオブジェクトが取得される

const hogeClass = $('.hoge-class') // 変数、定数への格納ももちろん可能
```

### クラス指定
```html:html
<div class="hoge-class">
 <!-- something -->
</div>
```
```javascript:javascript
$('.hoge-class') // 画面内の「hoge-class」を全取得
```

### id指定
```html:html
<div id="hogeId">
 <!-- something -->
</div>
```
```js:javascript
$('#hogeId')
```

### タグ種別指定
```html:html
<div>
 <!-- something -->
</div>
```
```js:javascript
$('div') // 「div」タグを全取得
```

### 属性の条件判定
例 : **name属性**が**「hoge-name」**のタグを取得する

```html:html
<div name="hoge-name">
 <!-- something -->
</div>
```
```js:javascript
$('[name="hoge-name"]') // 「name」属性が「hoge-name」の要素を全て取得
```

例 : **inputタグ**かつ**type**が**checkbox**(よく見かけるパターン)

```html:html
<input type="checkbox" value="hogeCheckBox" />
```
```js:javascript
// よく見かける例だとこうだが…
$('input[type=checkbox]')

// 実はこれだけでも上記とほとんど同様の結果が得られる。最初にある「input」はinputタグを表しているので、この場合は無くても問題はなく、typeに対する条件判定だけで事足りる
$('[type=checkbox]') 
```


カスタムタグだろうが条件判定に利用可能

```html:html
<div data-custom-hoge="true">
 <!-- something -->
</div>
```
```js:javascript
$('[data-custom-hoge="true"]') // 「data-custom-hoge」属性が「true」の要素を全て取得
```
`[属性名=値]`で条件指定となる
完全一致だけでなく、(ここでは割愛するが)**後方一致**や**前方一致**での指定も可能
**DOMの属性**(**name**や**id**も始め、**『data』から始まるカスタムデータ属性**に至っても)**については`[]`で囲めば(ほぼ)どんな属性でも、条件検索が出来ると考えて貰って差支え無い**

### 『●●内の▲▲』を取得(入れ子要素の取得)
例 : 「**hoge-class**」内の『**button要素全て**』を取得

```html:html
<div class="hoge-class">
 <button>送信</button>
</div>

<!-- 直下の子要素でなくてもok -->
<div class="hoge-class">
 <div>
  <button>決定</button>
 </div>
</div>
```
```js:javascript
$('.hoge-class button') // 『半角スペース区切り』で親子関係を表現
```

### 『●●かつ▲▲』であるタグの取得(複数条件指定)
例 : 「**hoge-class**」が付与されている**buttonタグ**を取得

```html:html
<button class="hoge-class">ほげほげ</button>
```
```js:javascript
$('button.hoge-class') // 複数のセレクタを区切り無く記述
```
若干紛らわしいですが、半角スペースで区切ると親子関係の表現になってしまうので注意

```js:NG
$('button .hoge-class') // NG。これだとdivタグ内のhoge-classクラスという指定になってしまう
```

## DOMの操作
 - 値のセットから、クラスの指定等

### 値のセット(value)

**val関数**

```html:html
<input id="hogeText" type="text" />
```
```js:javascript
$('#hogeText').val('ほげほげ') // 引数を与えればsetter化

const inputValue = $('#hogeText').val() // 引数が無ければgetter化
```

### クラスの付与、削除、判定

**addClass関数**
**removeClass関数**
**toggleClass関数**
**hasClass関数**

```html:html
<div class="hoge-class">
</div>
```
```js:javascript
$('.hoge-class').addClass('fuga-class') // fuga-classを追加

$('.hoge-class').removeClass('fuga-class') // fuga-classを削除

$('.hoge-class').toggleClass('fuga-class') // fuga-classが付与されていれば削除、付与されていなければ付与

const existsFuga = $('.hoge-class').hasClass('fuga-class') // クラスの有無判定。fuga-classが付与されていればtrue、されていなければfalse
```

### innterTextの取得、変更

**text関数**

```html:html
<button id="hogeButton">ほげほげ</button>
```
```js:javascript
$('#hogeButton').text('ふがふが') // 引数を与えればsetter化

const buttonText = $('#hogeButton').text() // 引数を与えなければgetter化
```
　

```html:html
<h1>h1 hoge</h1>
```
```js:javascript
$('h1').text('h1 fuga') // innerTextが存在するタグならbuttonタグ以外も(もちろん)指定が可能
```

### その他属性値の変更、取得

**attr関数**

```html:html
<div id="hogeId" name="hogeName">
</div>
```
```js:javascript
const name = $('#hogeId').attr('name') // name属性の値取得

$('#hogeId').attr('name', 'fugaName') // 属性に対する値の再設定も
```

wai-aria等の特殊な属性も自由に設定可能

```html:html
<div id="hogeId" aria-hidden="true">
</div>
```
```js:javascript
const hidden = $('#hogeId').attr('aria-hidden') // 第二引数を与えなければgetter化

$('#hogeId').attr('aria-hidden', false) // 第二引数を与えればsetter化
```

**checked**、**selected**属性には、**prop関数**で存在の可否を真偽値で設定、及び取得
※attr関数との違いについては、[先達様のわかりやすい記事がありますので詳しくはそちらで・・・](https://qiita.com/ko8@github/items/c00ac707d274b5e35237)~~手抜き~~

```html:html
<select id="hogeSelectBox">
 <option>foo</option>
 <option selected>bar</option>
 <option>fooBar</option>
</select>
```
```js:javascript
$('#hogeSelectBox option') // 条件に合致するoptionタグは複数取得されるため、each関数でぐるぐる回す
  .each(function(index) {
     /** テキストがfooBarのoptionタグを選択済にする **/

     const option = $(this) // 1行分のoptionタグ(jQueryオブジェクト)を取得

     const isFooBar = 'fooBar' === option.text()

     option.prop('selected', isFooBar) // 第二引数を与えればsetter化
     // option.prop('selected')  第二引数を与えなければgetter化
  })
```

## DOMへのイベント定義、削除
 - **addEventListener**とほぼ同義
  - jQueryなりに簡潔にイベント定義が出来る

### 定義
**on関数**
例 : fuga-class子要素のbuttonタグにonClickイベントを定義する

```html:html
<div class="fuga-class">
 <button>fuga</button>
 <button>fugafuga</button>
</div>
```
```js:javascript
$('.fuga-class button')
 .on('click', function() {
  /** 押されたボタンのテキストをログ出力する **/

  const button = $(this) // $(this)で、押された自分自身(jQueryオブジェクト)を取得
  console.log(`押されたのは${button.text()}ボタン`) // ※es6以降のテンプレートリテラル表記
 })
```

### 削除
**off関数**
例 : fuga-class以下のbuttonタグに指定されたonClickイベントを削除する

```html:html
<div class="fuga-class">
 <button>fuga</button>
 <button>fugafuga</button>
</div>
```
```js:javascript
$('.fuga-class button').off('click')

$('.fuga-class button')
 .off('click') // off関数、on関数共に自分自身(jQueryオブジェクト)を返却するため、メソッドチェーンでイベントの定義しなおしも可能
 .on('click', function() {
   // do something
  })
```

### 応用
例 : **クリックされた自分と同階層**に存在するチェックボックスのチェック状態を取得する

```html:html
<div class="hoge-class">
 <button>hoge</button>
 <input type="checkbox"/>
</div>
```
```js:javascript
$('.hoge-class button')
 .on('click', function() {
  /** クリックされたボタンと同階層にあるDOM要素を取得し、値をログ出力する **/
  const button = $(this)

  const checkbox = button.parents('.hoge-class').find('input[type=checkbox]')

  console.log(checkbox.prop('checked'))
 })
```
**parents関数**で自分から見た親要素を取得
**find関数**で自分に対する子要素を取得
**どちらも「$」関数と同様に、セレクタ文字列を引き渡して利用する**

```js

$('.fuga-class button')

$('.fuga-class').find('button')

/** 上記はそれぞれ同じ結果が返却される **/
```

## その他便利操作
### DOMを隠す、再表示する
**hide関数**

```html:html
<button class="hoge-button">ほげ</button>
<button class="hoge-button">ほげほげ</button>
```
```js:javascript
// hoge-button全てを非表示にする
$('.hoge-button').hide()
```

**show関数**

```html:html
<button class="fuga-button">ふが</button>
<button class="fuga-button">ふがふが</button>
```
```js:javascript
// fuga-button全てを表示する
$('.fuga-button').show()
```


例によってメソッドチェーンも可

```js:javascript
$('.hoge-class').hide().show() // この動作はどう考えても無意味だｹﾄﾞ・・・
```


以上


# 書いてみて
 - 使ってみたらやっぱり便利だなぁと思うjQuery
  - しかし、システムの規模が大きくなればなるほど、ステートフルにDOMを扱いたくなってくるので、コンポーネント指向である昨今のjsフレームワークで書きたくなっていきます。
  - **動的に変化する『状態を全く持たない』**(←ｺｺ重要)アプリだったり、非常に規模の小さいモックアップの様なプロダクトをスピーディに作りたい場合には、jQueryという選択肢もまだまだ有りかもしれません。