ありがとうjQuery絶対に忘れない。Good by jQuery、Hello VanillaJS

かつては誰もが利用していた（所感）jQueryですが、今ではあまり聞かなくなりました。
学生との会話でも**JavaScriptは書いたことがありますが、jQueryは経験がありません**と答えが返ってきます。

少し時代遅れ感があるjQueryではありますが、JavaScriptがシンプルに書けることが非常に便利なのは今でも変わりません。
ただ、`querySelector()`メソッドの登場やReactやVue.jsなどのフレームワークの利用が高まる中で**jQueryを利用するメリットが少しずつ薄れていってしまった**と感じます。

加えてライブラリなので利用するためにファイルを読み込みます。
どれだけ圧縮したとしてもJavaScriptで記述するよりもファイルサイズは大きくなるのでサイトパフォーマンスにも影響を及ぼします。

:::note warn
jQueryは素晴らしいライブラリでこれまで随分お世話になりました！
ただ、世の中のトレンドやこれからのサービスの未来のために別れを決意しました…
:::

この記事ではjQueryと円満に別れするための方法を伝えたいと考えています。

## step1. jQueryの読み込みをやめる
第一歩として読み込んでいるjQueryのファイルを削除します。
読み込み方法は大きく3つにわかれると思います。

- CDNで読み込み
- サーバーにアップロードしたものを読み込み
- npmを利用してバンドルしている

CDNやサーバーから読み込んでいる場合はheadの中、もしくは該当ファイルの最下部あたりでファイルを読み込んでいるはずなのでそれを削除するだけで良いと思います。

ただ、npmでJavaScriptファイルにバンドルしている場合は**一工夫が必要かもしれません**。

### npmでjQueryを読み込んでいる場合
影響範囲が広いため少しずつJavaScriptに置き換えていきたい！という場合にはpackage.jsonの**scriptsでjQueryを含まないバンドルコマンドを用意する**必要があります。

```javascript:package.json
"scripts": {
  "build" : "SETTING=bundle webpack --config webpack/webpack.prod.js",
  "build:vanilla" : "SETTING=vanilla webpack --config webpack/webpack.prod.js",
}

// 良い名前が思いつかなかったので「vanilla」で許してください…
```

```webpack.base.js
const SETTING = process.env.SETTING;

const entry = {
  bundle: '/index.js',
  vanilla: '/vanilla.js',
}

module.exports = {
  entry: entry[SETTING],
  output: {},
  module: {},
  // 割愛
}
```

```webpack.prod.js
const merge = require('webpack-marge');
const base = require('./webpack.base.js');

module.exports = marge(base, {
  mode: 'production',
  // 割愛
});
```
こんな感じで書いてやれば現在のJSファイルとは別でコンパイルできると思います！
あとはコンパイルされたJSファイルを対象のファイルで読み込んでいくだけです。

## step2. jQueryをJavaScriptで置換する
おおよそのウェブサイトで置換しそうなjQuery処理をJavaScriptで置換するとどうなるかをご紹介します。
もし、置換を試みる場合は参考にしてください！
もっと簡単に書けるよ！ってのがあったらぜひコメントください！

### 基本的な置き換え
```diff_javascript
// 要素の取得
- $('.selector').before();
+ document.querySelector('.selector').before();

// 同じセレクターが複数ある場合
+ const selector = document.querySelectorAll('.selector');
+ selector.forEach(target => {
+   target.before();
+ });

// classの追加
- $('.selector').addClass('.add');
+ document.querySelector('.selector').classList.add('add');

// 前後の要素の取得
- $('.selector').next();
- $('.selector').prev();
+ document.querySelector('.selector').nextElementSibling
+ document.querySelector('.selector').previousElementSibling

```


### 具体的な処理の置き換え例
#### ページ内リンクのスムーススクロール
```javascript
window.addEventListener('DOMContentLoaded', () => {
  const anchors = document.querySelectorAll('a[href^="#"]');
  anchors.forEach(link => {
    link.addEventListener('click', event => {
      event.preventDefault();
      const targetId = link.hash;
      const targetElement = document.querySelector(targetId);
      const targetOffsetTop = window.pageYOffset + targetElement.getBoundingClientRect().top;
      window.scrollTo({
        top: targetOffsetTop,
        behavior: 'smooth',
      });
    });
  });
});
```

#### 横スクロールアクションに対する処理
横スクロールできることを視認させるアイコンは実際に操作する要素の親要素についている想定です。
classにてアイコンをつけている時の処理だと考えてください。

```javascript
const scrollTable = document.querySelectorAll('横スクロールするtable要素');
scrollTable.forEach(target => {
  target.addEventListener('touchmove', event => {
    event.target.closest('アイコンがついている親要素のclass').classList.remove('削除対象のclass');
  });
});
```

#### スクロールに対してページ上部または下部に追従するコンテンツ
```javascript
　window.addEventListener('load', () => {
  const sticky = document.getElementById('');
  const pageTop = 1000;
  let viewState = false;

  window.addEventListener('scroll', () => {
    if(window.pageYOffset > pageTop) {
      if (viewState) return;
      sticky.anumate(
        [
          {opacity: 0},
          {opacity: 1}
        ],
        {
          fill: 'forwards',
          duration: 500,
        }
      );
      // cssのスタイル状況によってはcssの操作を行う
      sticky.style.display = 'block';
      viewState = true;
    } else {
      if (!viewState) return;
      sticky.anumate(
        [
          {opacity: 1},
          {opacity: 0}
        ],
        {
          fill: 'forwards',
          duration: 500,
        }
      );
    }
  });
});
```

#### なにかしらのデータ通信処理
ajaxによる実装を置き換える場合を想定しています。

```javascript
const fetchData = () => {
  const value1 = document.getElementById('value1').value;
  const value2 = document.getElementById('value2').value;
  const value3 = document.getElementById('value3').value;
  const promise = fetch(`データ通信先のpath?param=${value1}&param=${value2}param=${value3}`);

  promise.then(response => {
    return response.json();
  })
  .then(data => {
    const result = data.result;
  })
  .catch(error => {
    console.log(error);
  });
};
```

## まとめ
ここまでjQueryをやめることを前提に話をしてきましたが、**絶対にダメというわけではありません**。
jQueryを使うことで簡潔に書けるのは確かですし、今だとnpmで管理できるのでファイルサイズも昔よりは抑えることができるはずです。

:::note info
それでもjQueryに「ありがとうを告げたい！」という方を応援するのが本記事です！
:::

jQueryからJavaScriptに置き換えるのは決して難易度は高くありません。
ただ、**CSSを制御するのに手間がかかったり、アニメーションがついているものは処理が長くなったりする**ことがあります。

本当はもっとシンプルに記述したいけど、HTMLの構造やCSSのスタイルの兼ね合いで妥協せざるおえない場面も出てくると思います。

目的が**JavaScriptに置き換えることであれば、いったん全て置き換えることに専念しましょう！**

皆様が1日でも早くjQueryに「ありがとう！」できる日が来ることを願っております。