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

jQueryによるコンポーネント化考察

javascript program Advent Calendar

はじめに

JavaScript Advent Calendar 2016 - Qiita

4日目

注) SPAの話ではありません。

なぜjQueryを使うのか

今の時代、JavaScriptはAngular2やReactに代表されるコンポーネント指向の時代を迎えている。 そんな中でなぜjQueryを使うのか。 下記の条件が組み合わさっている場合にはjQueryの方が使いやすい。

JavaScriptが必要な箇所が少ない

SPAでJavaScriptをメインで使う場合はjQuery等今更使うことは無いと思うが、 ほとんどサーバーでレンダリングされるhtmlで完結しているシステムに、 時々動きを加えたい、なんて時はいちいちNodeの環境を準備、周知し、 ビルドしつつ開発する方が面倒。

開発陣が入れ替わる

ずっと同じリーダーが開発の深い部分まで指揮していない場合もある。 そういった場合はメインのエンジニアも入れ替わるし、 その場その場で違う人がコードを書く。 サーバー側のフレームワークは定まっていることが多いが、 JavaScript側は特に指定されていなければjQueryが使われることは多いと思う。

サーバー側のフレームワークが優秀

なんだかんだで世の中のサーバー側のフレームワークは優秀で、うまく使っていると開発は非常に楽。 それをわざわざAngular2やReactに置き換える場合、連携のためのコードを書いたり、 サーバー側フレームワークと同等の機能をJavaScriptで書きなおしたりなどの作業が必要となり、 逆に面倒になる。

なんとかやったとしても、今度はJavaScript側のサーバーサイドレンダリングが必要なんじゃないか、 という考えに至り、じゃあNode側のサーバーの処理も作らないと、でもそこまでやるのはなあ… となっていき結局jQueryに落ち着く。

でもコンポーネント化したい

でもはやり最新の考え方を導入していきたい。ではそういった状況下において、jQueryコンポーネント化し、Fluxの思想を取り入れるためにはどうすればいいのか、考察してみる。

プラグイン

なるべく処理はプラグイン化し、至るところで再利用できるようにする。

データの流れを1方向にする

JavaScriptの開発でDOMやデータが現状どうなっているか分からなくなり不具合の温床となる、 ということがFluxの思想が生まれたベースとなった話だったと記憶している。

jQueryを使用しているとそういうことが起こりやすいのだろうが、それは適当に開発しているからだ。 きっちり考えてやればそうはなりにくくすることはできると思う。 (もちろんjQueryだからきっちりしない選択もできるので、それをするエンジニアがプロジェクト内に出てきてしまう、 というのが本質的な問題かもしれないが)

とりあえず、諸々の処理ですぐにDOMを操作せず、 「処理→最後にrender」というのを一貫すればいい。

例えば下記はjQueryプラグインのfullcalendarのソースの一部。

fullcalendar/main.js at master · fullcalendar/fullcalendar · GitHub

見ての通り中でCalendarクラスのインスタンスを作成し、最後にrenderしている。 初期化だけでなく基本的には全ての処理がこれになっている。

つまり描画されるDOMは必ずインスタンスのプロパティ通りになる。 これにより1方向の流れの基礎が出来上がる。

クラスを分ける

プラグインが大きくなるなら描画部分ごとのパーツでクラスを分ける。 パーツはなるべく親の値を参照するのみにし、 重要な値の変更が必要な場合はパーツ内ではなく大元のクラスの値変更+再描画を徹底すれば完全にFluxだ。

htmlは変数に結合しまくりなのでやりにくいのは否定しないが、 ちゃんと処理やパーツを分ければさほど見にくくなることもない。

自動起動

jQueryプラグインはscriptタグで読み込んで、ページ内で初期化メソッドを呼び出す、という流れが多いと思うが、 BootstrapのJSのように勝手に動作してくれる方が楽だと思うし最近のコンポーネントぽいので、 そのようにしてみる。

下記の一番下にプラグインの雛形がある。

jquery プラグイン/作成 - Qiita

このmethodsの上に初期化スクリプトを入れてしまう。

$(function() {
  var targets = $('[data-tooltip]');
  if (targets.length > 0) {
    targets.tooltip();
  }
});

これでいちいち初期化を書かなくても全部自動起動される。 クラス名はデザイナーがいつの間にか変えている場合もあるのでdata属性がいいと思う。

初期化設定

これじゃあパーツ毎に設定ができないじゃないか、と思うかもしれないが設定もdata属性にしてしまえばいいだけ。 プラグイン側で初期化時に値をそこから読めばいい。 さっきのfullcalendarの例で言うとnew Calendarの中でやればいい。

<div data-tooltip="foo" data-position="right">項目名</div>

まとめ

長々と書いたが、これくらいなら普通に開発するのとほとんど労力は変わらないと思う。

jQueryを使うデメリットは他にもある、という人もいると思うしやり方に好き嫌いはあると思うので、 ひとまずより良い方法、というよりは考察とさせていただく。

逆に言うと、まるまるAngular2やReactなどに置き換えるのではなく、 こういった手法を簡単に安全に確実に実現できる良いjQueryのラッパーライブラリなどが登場するといいのではと思う。