Nuxt, カスタムディレクティブを使ってみたいんだが!?

Nuxt
Gerd AltmannによるPixabayからの画像

目的

Nuxtで作成したwebサイト上でマウス操作したときに
操作に応じてアニメーションを起こしたいなと思うときありませんか?

例えば……

マウスをクリックした際そこから同心円状に円が広がっていくとか…ね!?

今回、「カスタムディレクティブ」を使って作っていきます。

ではやっていきましょう!!

開発環境

  • OS: Windows10 home 64bit
  • フレームワーク: Nuxt.js v2.12.2
  • プログラミング言語: Javascript

ディレクトリ構成

js_spa/
  ├ pages/
  │   └ index.vue
  ├ plugins/
  │   └ circle.js
  └ nuxt.config.js

※今回使用するファイルのみ表示しています。

サイト画面の作成 ~一つのファイルだけで完結~

まずはサイトを立ち上げたときの最初に表示されるメイン画面を作ります。

この画面上でマウスのボタンを押し続けるとその場所から円模様が広がっていきます。

まず、ローカルでカスタムディレクティブの処理を追加しましょう。

そのためのpages/index.vueを作成します。
全体のコードは以下になります。|

<!-- pages/index.vue -->
<template>
   <section class="container">
      <div>
         <div v-click="handleScale" class="circle" />
      </div>
   </section>
</template>

<script lang="js">
export default {
  directives: {
    click: {
      inserted (el, binding) {
        const f = function (evt) {
          const position = binding.value(evt, el)
          window.onmouseup = () => {
            el.setAttribute(
              'style',
              `background-color: blue; transform:scale(1,1); top: ${position.posY}px; left: ${position.posX}px;`
            )
          }
        }
        window.addEventListener('mousedown', f)
      }
    }
  },
  methods: {
    handleScale (evt, el) {
      const posX = evt.clientX
      const posY = evt.clientY
      el.setAttribute(
        'style',
        `background-color: red; transform:scale(20,20); top: ${posY}px; left: ${posX}px;`
      )
      return {
        posX, posY
      }
    }
  }
}
</script>

<style>
.container {
  min-height: 150vh;
  display: flex;
  justify-content: center;
  align-items: center;
}

.circle {
  position: absolute;
  width: 10px;
  height: 10px;
  border-radius: 50%;
  background-color:red;
  transition-property: transform;
  transition-duration: 1.5s;
}
</style>

それぞれのタグごとに分けて説明します。

templeteタグ

<section class="container">
   <div>
     <div v-click="handleScale" class="circle" />  <!-- 1 -->
   </div>
</section>
  • 1: 円模様を表示するための部分です。
    class=”circle”
    が後に記述するstyleを反映させるためにclassにcircleを加えています。
    v-click=”handleScale”
    が今回のメインとなる円模様にアニメーションを加えるためのものです。
    またv-clickはこの後、カスタムディレクティブで作成します。

scriptタグ

export default {
  directives: {
    click: {
      inserted (el, binding) {
        const f = function (evt) {
          const position = binding.value(evt, el) // ... 2
          window.onmouseup = () => { // ... 3
            el.setAttribute( // ... 4
              'style',
              `background-color: blue; transform:scale(1,1); top: ${position.posY}px; left: ${position.posX}px;`
            )
          }
        }
        window.addEventListener('mousedown', f)
      }
    }
  },
  methods: {
    handleScale (evt, el) {
      const posX = evt.clientX // ... 5
      const posY = evt.clientY // ... 5
      el.setAttribute(
        'style',
        `background-color: red; transform:scale(20,20); top: ${posY}px; left: ${posX}px;` // ... 6
      )
      return {
        posX, posY
      }
    }
  }
}
  • 2: 現在ブラウザ内にあるマウスの座標を取得しています。
  • 3: マウスの左クリックを押し、放したときに3番が実行されます。
  • 4: 実行されたときにcssの新しい属性を追加しています。
    transform: scale(1,1)で円模様の拡大、縮小をしています。
  • 5: マウスの左クリックボタンを押したときの座標を取得するためのコードです。
    座標を取得するのにブラウザの座標を基準としたclientXclientYを使っています。
    マウスの座標を取得メンバはいくつかありますが用途に合わせて使ってください。
メンバ
screenX, screenYイベントが発生した位置のX or Y座標をディスプレイを基準として取得する
clientX, clientYイベントが発生した位置のX or Y座標をブラウザを基準として取得する
offsetX, offsetYイベントが発生した位置のX or Y座標を要素を基準として取得する
pageX, pageYイベントが発生した位置のX or Y座標をページを基準として取得する
  • 6: transform:scale(20,20)が円模様の大きさを変更するコードです。
    ここに追加することでマウスの左クリックボタンを押している間だけ円模様が徐々に拡大していきます。

styleタグ

.container {
  min-height: 150vh;
  display: flex;
  justify-content: center;
  align-items: center;
}

.circle {
  position: absolute;
  width: 10px;
  height: 10px;
  border-radius: 50%;    /* 7 */
  background-color:red;
  transition-property: transform;    /* 8 */
  transition-duration: 1.5s;    /* 9 */
}
  • 7: ボックスの角を丸くするのに使いますが、50%くらいに指定すると円模様を作れる。
    widthheightをいじることで、 楕円や正円に変えることができます。
  • 8: transition(時間的変化)における効果を適用する範囲を指定できます。
    scriptタグtransform:scaleのみに適用したいので、transformを選びます。
  • 9: 変化における時間間隔を指定しています。
    これはわたし的に1.5秒くらいがちょうど良かったので、1.5sを指定しています。

これでnpm run devを実行してhttp://localhost:3000/にアクセスするとマウスを長押ししたところから円の色が変わりかつ、だんだんと広がっていくのが分かります。

サイト画面の作成 ~ディレクティブを使いまわせるようにする~

<!-- pages/index.vue -->
<template>
  <section class="container">
    <div>
      <div v-click="handleScale" class="circle" />
    </div>
  </section>
</template>

<script>
export default {
  methods: {
    handleScale (evt, el) {
      const posX = evt.clientX
      const posY = evt.clientY
      el.setAttribute(
        'style',
        `background-color: red; transform:scale(20,20); top: ${posY}px; left: ${posX}px;`
      )
      return {
        posX, posY
      }
    }
  }
}
</script>

<style>
.container {
  min-height: 150vh;
  display: flex;
  justify-content: center;
  align-items: center;
}

.circle {
  position: absolute;
  width: 10px;
  height: 10px;
  border-radius: 50%;
  background-color:red;
  transition-property: transform;
  transition-duration: 1.5s;
}
</style>

サイト画面の作成 ~一つのファイルだけで完結~」のscriptタグ内にdirectivesで作成した処理を外部のjavascriptファイルに分けたので、directivesを削除します。

削除したdirectivesの処理をpluginsフォルダにcircle.jsとして以下のように作成します。

// plugins/circle.js
import Vue from 'vue'

Vue.directive('click', {
  inserted (el, binding) {
    const f = function (evt) {
      const position = binding.value(evt, el)
      window.onmouseup = () => {
        el.setAttribute(
          'style',
          `background-color: blue; transform:scale(1,1); top: ${position.posY}px; left: ${position.posX}px;`
        )
      }
    }
    window.addEventListener('mousedown', f)
  }
})

このままではindex.vueファイル側にcircle.jsが認識されていないので
ディレクティブ処理をnuxt.config.jsに追加します。

// nuxt.config.js
export default {
~~~~~~~~~~~~~~省略~~~~~~~~~~~~~~~~
  plugins: [
    './plugins/circle.js'
  ],
~~~~~~~~~~~~~~省略~~~~~~~~~~~~~~~
}

nuxt.config.jsのpluginsフォルダ内に外部のディレクティブファイルのパスを追加する

実行

カスタムディレクティブの実装

最後に

これでカスタムディレクティブを使った画面効果を簡単に作ることができました。

対して高度なことはしていないですが、何か参考になれば嬉しいです。

ここまで読んでくれてありがとう!!

タイトルとURLをコピーしました