Vueは要素のイベントをリッスンし、そのようなイベントが発生したときに特定の関数を実行するようにトリガーできることを私たちは知っています。 Vue.jsでは、カスタムイベントをリッスンすることもできます。これは、親コンポーネントがリッスンできるイベントを子コンポーネントが起動できるようにするための最も重要なユースケースを持つ機能です。

Vueテンプレート構文の記事で簡単なフォトギャラリーコンポーネントを作成しました。 サムネイルの行にある写真のいずれかをクリックすると、クリックした写真が下に大きなサイズで表示されます。 では、ページ全体の背景を、表示されている写真の平均的な色に設定したい場合はどうでしょうか。 これはシアターモードのように呼ぶことができます。

カスタムイベントの力は、それをかなり簡単に実行できることです。 フォトギャラリーの親コンポーネントであるApp.vueは、写真がクリックされたときに、子コンポーネントであるPhotoGallery.vueから写真の平均RGB値を受け取る必要があります。

始めましょう。 このチュートリアルでは、テンプレート構文チュートリアルが中断したところを取り上げます。

アプリのセットアップ

この前の投稿と同じセットアップを使用してみましょう。

カスタムイベントコードを書いてみましょう

fast-average-colorというnpmライブラリを使用して、特定の写真の平均カラー値を取得します。 PhotoGallery.vue<script>セクションの上部にインポートします。

import from 'fast-average-color';

現在、PhotoGallery.vueコンポーネントには、highlight()というメソッドがあり、写真の1つをクリックするとトリガーされます。

highlight() {
  event.target.id = "theater";
  this.theatrical = event.target.src;
  let eventIterator = event.target.parentNode;
  while (eventIterator.previousElementSibling != null) {
    eventIterator.previousElementSibling.getElementsByTagName('img')[0].id = "";
    eventIterator = eventIterator.previousElementSibling;
  }
  eventIterator = event.target.parentNode;
  while (eventIterator.nextElementSibling != null) {
    eventIterator.nextElementSibling.getElementsByTagName('img')[0].id = "";
    eventIterator = eventIterator.nextElementSibling;
  }
}

この方法では、クリックした写真がサムネイルの下に大きなサイズで表示されます。 メソッド全体でevent.targetを使用したことに注意してください。 event.targetはクリックされた要素です。 これは、平均色を取得したい画像です。

fast-average-colorのドキュメントをよく読むと、getColorAsync関数が見つかります。この関数は、color.rgbaが平均RGB値であるカラーオブジェクトを返します。 先に進んで、その関数呼び出しを行いましょう。

const fac = new FastAverageColor();

fac.getColorAsync(event.target)
  .then(function(color) {
  })
  .catch(function(e) {
    console.log(e);
  });

colorではまだ何もしていません。 最終的には、App.vueで背景色をcolor.rgbaに設定する必要があります。 App.vueには、color.rgbaを引数として取るメソッドがあります。 先に進んでそのメソッドを書いてみませんか?

methods: {
  setBackground(rgba) {
    document.querySelector('body').style.backgroundColor = rgba;
  }
}

それはあなたに似合うはずです!

App.vueのテンプレートセクションをご覧ください。 現在の外観は次のとおりです。

<template>
  <div id="app">
    <PhotoGallery />
  </div>
</template>

Appコンポーネントは、カスタムイベントであるPhotoGalleryコンポーネントからイベントを取得する必要があります。 イベントがtheater-modeと呼ばれたとしましょう。 コンポーネントでこのようなイベントをリッスンする場合、構文は通常のイベントの場合と同じです。 つまり、v-on:theater-modeになります。 theater-modeが発生すると、setBackgroundメソッドが呼び出されます。

次に、値color.rgbaApp.vueに送信する必要があります。 PhotoGallery.vueに戻ります。


すべてのVueコンポーネントにはメソッド$emitがあります。 このメソッドを使用すると、イベント(この場合はtheater-mode)をトリガーできます。 カラーライブラリに対して行った非同期呼び出しから、then関数内でthis.$emitを呼び出します。 あなたの記憶をジョギングしましょう。

highlight() {
  event.target.id = "theater";
  this.theatrical = event.target.src;
  let eventIterator = event.target.parentNode;
  while (eventIterator.previousElementSibling != null) {
    eventIterator.previousElementSibling.getElementsByTagName('img')[0].id = "";
    eventIterator = eventIterator.previousElementSibling;
  }
  eventIterator = event.target.parentNode;
  while (eventIterator.nextElementSibling != null) {
    eventIterator.nextElementSibling.getElementsByTagName('img')[0].id = "";
    eventIterator = eventIterator.nextElementSibling;
  }
  const fac = new FastAverageColor();
  fac.getColorAsync(event.target)
    .then(function(color) {
    })
    .catch(function(e) {
      console.log(e);
    });
}

this.$emitは、最初の引数としてイベント名を取り、データを渡すことができるオプションの追加の引数があります。 color.rgbaを渡します。 したがって、関数呼び出しはthis.$emit('theater-mode', color.rgba)のようになります。 新しい関数は次のとおりです。

highlight() {
  event.target.id = "theater";
  this.theatrical = event.target.src;
  let eventIterator = event.target.parentNode;
  while (eventIterator.previousElementSibling != null) {
    eventIterator.previousElementSibling.getElementsByTagName('img')[0].id = "";
    eventIterator = eventIterator.previousElementSibling;
  }
  eventIterator = event.target.parentNode;
  while (eventIterator.nextElementSibling != null) {
    eventIterator.nextElementSibling.getElementsByTagName('img')[0].id = "";
    eventIterator = eventIterator.nextElementSibling;
  }
  const fac = new FastAverageColor();
  fac.getColorAsync(event.target)
    .then((color) => this.$emit('theater-mode', color.rgba))
    .catch(function(e) {
      console.log(e);
    });
}

それはあなたに似合うはずです! App.vueを振り返ってみましょう。

App.vue
<template>
  <div id="app">
    <PhotoGallery/>
  </div>
</template>

<script>
import PhotoGallery from './components/PhotoGallery.vue'

export default {
  name: 'App',
  components: {
    PhotoGallery
  },
  methods: {
    setBackground(rgba) {
      document.querySelector('body').style.backgroundColor = rgba;
    }
  }
}
</script>

<style>
#app {
  font-family: Avenir, Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
  margin-top: 60px;
}
</style>

theater-modeイベントを聞くことはv-on:theater-modeのように見えることはすでに説明しました。 カスタムイベントをリッスンすると、$eventを介して渡されたすべてのデータにアクセスできます。

したがって、次のように記述します。

<template>
  <div id="app">
    <PhotoGallery v-on:theater-mode="setBackground($event)"/>
  </div>
</template>

おめでとう!

カスタムイベントを正常に発行し、親コンポーネントからそれをリッスンし、イベントから発行された値にアクセスしました。 ブラウザを確認してください。 アプリは意図したとおりに機能するはずです。 お疲れ様でした! 🚢

Vueでのコンポーネント通信に関する知識を深めたい場合は、この記事を読んでください