Nuxtでマウスで画面をドラッグしてスクロールさせる

お疲れ様です。最近のモバイルではユーザーが横幅に入りきらないボタンやメニューのアイテムをスクロールすることが当たり前ですね。

これを同じようにデスクトップで行おうとしてもブラウザではデフォルトでその機能が付いていません。

ですのでこのように見た目の汚いX軸のスクロールバーを使用するしかありません。

では今日はNuxtを使ってデスクトップでスクロールバーをなしでマウスでドラッグしてスクロールする方法を紹介します。

環境

今日はVueのSSRフレームワークのNuxtを使います。Vueの場合はクライアント側でレンダーされるのでWindowオブジェクトにアクセスできますが、Nuxtはサーバーサイドでレンダーされるのでデフォルトではwindowオブジェクトが使えません。この意味が分からない人は、まずはバニラJSでどうやってマウスを使ってスクロールができるのか知っておきましょう!Nuxtのプロジェクトができていることを想定して進めていきます。

VueUseライブラリ

今日はVueでもよくつかわれるライブラリのVueUseを使います。このuseMouseの機能を使ってVueでも簡単にマウスの現在の位置を手に入れることができるので自作で作るのが面倒な場合はこれが使えそうです。このVueUseのライブラリはSSRのNuxtも対応しています。

ではVueUseをインストールします。

npm i -D @vueuse/nuxt @vueuse/core

インストールが完了したらNuxtのコンフィグファイルにこのモジュールを登録します。

// nuxt.config.ts
export default defineNuxtConfig({
  modules: [
    '@vueuse/nuxt',
  ],
})

カーソルの位置を知る

ではモジュールを登録したところでグローバルでモジュールが使えるようになります。

<script setup>
const { x, y } = useMouse()
</script>

<template>
  <div>pos: {{x}}, {{y}}</div>
</template>

これでカーソルが移動するたびにリアクティブに位置を取得できるようになりました。こんな簡単にできるとはすばらしいですね。

クリックイベントを作成

dえは下記の様にマウスイベントのクリック、マウスムーブ、マウスアップを作成してスクロールのポジションを変更していきます。

<template>
  <div
    class="scroll-container"
    ref="scrollcontainer"
    @mousedown="mousedownScrollbar"
    @mousemove="mousemoveScrollbar"
    @mouseup="mouseupScrollbar"
  >
    <Button
      class="mx-1 my-2"
      size="small"
      label="Poplar Video This week"
      severity="secondary"
      rounded
    />
       <Button
      class="mx-1 my-2"
      size="small"
      label="Info"
      severity="info"
      rounded
    />
  </div>
</template>

<script setup>
const scrollcontainer = ref(null);
const { x } = useMouse();

const isDragging = ref(false);
const startingPosition = ref(0);
const postionDiff = ref(0);
const startingScrollLeft = ref(0);

function mousedownScrollbar() {
  isDragging.value = true;
  scrollcontainer.value.style.cursor = 'grabbing';
  startingPosition.value = x.value;
}

function mousemoveScrollbar() {
  if (isDragging.value) {
    postionDiff.value = x.value - startingPosition.value;
    scrollcontainer.value.scrollLeft =
      startingScrollLeft.value - postionDiff.value;
  }
}

function mouseupScrollbar() {
  isDragging.value = false;
  scrollcontainer.value.style.cursor = 'grab';
}
</script>

<style scoped lang="scss">
.scroll-container {
  overflow-x: scroll;
  white-space: nowrap;
  padding: 0.2rem;
  cursor: grab;
  &::-webkit-scrollbar {
    display: none;
  }
}
</style>

これでエレメント内でマウスクリックするとカーソルがつかむイラストに変わることが分かりました。

さらにつかんでいる間にマウスを移動させることでスクロールが移動できるようになりました。

const scrollcontainer=ref(null);はテンプレートrefでVueのやり方でHTMLタグにアクセスする方法です。

const{x}=useMouse();は、先ほど説明した通り現在のマウスの位置を知るモジュールです。今回はx軸だけ必要になります。

const isDragging=ref(false);はマウスがスクロールをつかんだかどうかをリアクティブに保管するための変数です。逆にisDraggingがfalaseの時は何も実行されないようにします。

const startingPosition = ref(0);x軸のスタートの位置です。初期では0にしておいて、クリックイベントで値を入れるようにします。

const postionDiff = ref(0);クリックが始まってからマウスを移動している際にリアクティブでその差を保管する変数です。では上記のデータをもとにmousedownScrollbarmousemoveScrollbarmouseupScrollbarを見てください。詳しい内容は関数内に書いたままになります。

最後に::-webkit-scrollbar要素を非表示にしてスクロールバーを隠して完成です!