jQueryを使わずにマウスドラッグスクロールを実装する

パソコンの画面
石田正泰
この記事を書いた人 石田正泰

中学生の時に趣味でZ80マシン語やFortran等を始めてから、現在まで数多くのプログラミング言語を経験。ShopifyによるECサイト構築では主にカスタマイズを担当。

はじめに

初めに断っておきますが、私はjQuery否定派では決してありません。
DOMから取得したオブジェクトがHTMLCollectionなのかNodeListなのかElementなのかとかをいちいち気にする必要がなくなる上に、jQueryオブジェクトのメソッドは強力で、アニメーションが簡単に実装でき、CSSも簡単に操作でき、そして記述が劇的に短くなりコードがとても見やすくなったりします。

しかしカスタマイズの仕事をしていると、jQueryライブラリが読み込まれていないページをカスタマイズしなければならない場面が多々発生します。

ECサイトは「表示速度が0.1秒遅くなると売上が1%減少する」とか「表示速度が1秒から3秒に落ちると、直帰率は32%上昇する」とか言われている世界です。
また、表示速度が遅いとユーザビリティが悪いとみなされて、検索順位が下がる可能性も高くなります。

その様な理由から、ちょっとしたカスタマイズだけのためだけにjQueryライブラリを読み込むのには躊躇してしまいます。
この記事ではちょっとしたカスタマイズをバニラなJavaScriptでカスタマイズする例をご紹介します。

 

マウスドラッグスクロールをテストする

商品詳細ページの商品画像サムネイル表示とかでよくあるのですが、親要素のCSSでoverflowにautoが指定されていて、なおかつその中身の要素が大きい時は、スクロールバーが表示されます。
スマートフォンやタブレットの時はドラッグでスクロールできるのですが、PCの場合はマウスをドラッグしても動きません。これをPCでもマウスでドラッグスクロールできるようにします。

まずは、サンプルのHTMLとCSSの準備です。

<div class="wrap">
  <div class="inner inner1">aaa</div>
</div>
<div class="wrap">
  <div class="inner inner2">bbb</div>
</div>
<div class="wrap">
  <div class="inner inner3">ccc</div>
</div>

<style>
  .wrap {
    display: inline-block;
    margin-right: 30px;
    width: 200px;
    height: 100px;
    overflow: scroll;
    margin-bottom: 30px;
    cursor: pointer;
  }
  .inner {
    width: 500px;
    height: 500px;
  }
  .inner1 {
    background-image: repeating-radial-gradient(circle at 30% 72%, rgba(178, 254, 255, 1), rgba(137, 219, 248, 1) 12%, rgba(178, 254, 255, 1) 24%);
  }
  .inner2 {
    background-image: linear-gradient(40deg, rgba(45, 71, 150, 1) 4%, rgba(95, 91, 165, 1) 23%, rgba(143, 106, 174, 1) 40%, rgba(185, 86, 230, 1) 52%, rgba(219, 111, 150, 1) 67%, rgba(245, 150, 59, 1) 77%, rgba(247, 165, 103, 1) 84%, rgba(216, 175, 104, 1) 94%);
  }
  .inner3 {
    background-image: repeating-linear-gradient(135deg, rgba(224, 110, 170, 1) 5% 10%, rgba(255, 255, 255, 1) 10% 15%, rgba(85, 85, 85, 1) 15% 20%, rgba(255, 255, 255, 1) 20% 25%);
  }
</style>

 

Googleで「javascript マウスドラッグスクロール」で検索すると、サンプルが沢山ヒットします。とても良く出来ているのですが・・・どれもjQueryで書かれたものばかりです。でも、本当にとても考えられて良く出来ているので、これをバニラなJavaScriptで書き直します。

function mousedragscrollable(element){
  let target;
  const elms = document.querySelectorAll(element);
  for(let i=0; i<elms.length; i++){
    elms[i].addEventListener('mousedown', function(evt){
      evt.preventDefault();
      target = elms[i];
      target.dataset.down = 'true';
      target.dataset.move = 'false';
      target.dataset.x = evt.clientX;
      target.dataset.y = evt.clientY;
      target.dataset.scrollleft = target.scrollLeft;
      target.dataset.scrolltop = target.scrollTop;
      evt.stopPropagation();
    });
    elms[i].addEventListener('click', function(evt){
      if(elms[i].detaset != null && elms[i].detaset.move == 'true') evt.stopPropagation();
    });
  }
  document.addEventListener('mousemove', function(evt){
    if(target != null && target.dataset.down == 'true'){
      evt.preventDefault();
      let move_x = parseInt(target.dataset.x) - evt.clientX;
      let move_y = parseInt(target.dataset.y) - evt.clientY;
      if (move_x !== 0 || move_y !== 0) {
        target.dataset.move = 'true';
      } else {
        return;
      }
      target.scrollLeft = parseInt(target.dataset.scrollleft) + move_x;
      target.scrollTop = parseInt(target.dataset.scrolltop) + move_y;
      evt.stopPropagation();
    }
  });
  document.addEventListener('mouseup', function(evt){
    if(target != null && target.dataset.down == 'true'){
      target.dataset.down = 'false';
      evt.stopPropagation();
    }
  });
}
    
window.addEventListener('DOMContentLoaded', function(){
  mousedragscrollable('.wrap');
});

 

※PCで試してみてください。

 

aaa
bbb
ccc

全てのブラウザで試したわけでは無いのですが、マウスドラッグでスクロールできるようになったと思います。

 

最後に

2021年、ECサイトプラットホームであるShopifyは、Reactベースのフレームワーク「Hydrogen」を発表しました。

Hydrogenを使用するにはNode.jsが動作するWEBサーバーが必要になりますが、同じくReactベースのフレームワークであるNext.jsのSSRとCSRの弱点を改善した「ストリーミングSSR」等の機能があり、Shopifyをバックオフィス、つまりヘッドレスコマースとして使用しフロントエンドと切り離す様な使い方をすると、フロントエンドの表示高速化が期待できます。詳しくはShopify公式ブログ「Hydrogenを使用したストアフロントはなぜパフォーマンスが高いのか」を御覧ください。

私見ですが、jQueryに限らずJavaScriptは要素を手続き的に取得していかなければならない上にDOM操作後にどのようなHTML構造になるのかコードからは分かりにくいという欠点を持っており、規模が大きくなるほど複雑になっていきます。そのためWEBアプリ系の世界でのJavaScriptライブラリの主流はjQueryからReactに、あるいはフレームワークであるVue.jsやAngularとかに移行しつつある雰囲気で、私自身もWEBアプリ制作でのUI部分はすっかりReactやVue.js等に頼ってます。

しかしWEBページコンテンツ制作の方の世界では、HTMLとCSSでページを作ってそこにJavaScriptで動きをつけていく手順が主流であり、テンプレートをJSX内に記述する必要があるReactが向いているとは思えません。代わりに、小規模開発に向いていてHTMLをそのままテンプレート化できて更に双方向バインディングまでできるVue.jsをCDNで読み込んで使用するのがとても手軽で、そこで更にDOMをトラバースしたい時とかにjQuery等を併用するのが制作効率が高そうだと感じています。