スキルアップ

Vue.js入門:ココだけ分かれば改修はできる!

Vue.jsは、使いやすさと柔軟性を兼ね備えたJavaScriptフレームワークです。

本記事では、Vue.jsの基本概念と実践的な使い方を、具体的なコード例を交えながら解説します。

Vue.jsを初めて学ぶ方にも理解しやすい内容となっていますので、ぜひ最後までご覧ください。

コンポーネントとは

分かりやすく言うと、コンポーネントは「ウェブページの特定の部分」を担当する小さな部品のようなものです。

特定の部分とは1つのページのことであったり、セレクトボックスだったり、ラジオボタンだったりのことを表しています。

このコンポーネントへの理解が重要なポイントになるので、他よりも厚めに説明しておきます。

コンポーネントの例

以下に、シンプルなVue.jsコンポーネントの例を示します。

親コンポーネント

親コンポーネントは、子コンポーネントを使用してデータを渡す役割を持ちます。

<!-- ParentComponent.vue -->
<template>
  <div>
    <h1>親コンポーネント</h1>
    <ChildComponent :message="parentMessage"/>
  </div>
</template>

<script>
import ChildComponent from './ChildComponent.vue';

export default {
  components: {
    ChildComponent
  },
  data() {
    return {
      parentMessage: 'Hello from Parent Component!'
    };
  }
};
</script>

<style scoped>
h1 {
  color: blue;
}
</style>

子コンポーネント

子コンポーネントは、親コンポーネントから渡されたデータを受け取りそれを表示します。

<!-- ChildComponent.vue -->
<template>
  <div>
    <h2>子コンポーネント</h2>
    <p>{{ message }}</p>
  </div>
</template>

<script>
export default {
  props: {
    message: {
      type: String,
      required: true
    }
  }
};
</script>

<style scoped>
h2 {
  color: green;
}
</style>

コンポーネントの説明

  • template: コンポーネントのHTML構造を定義します。ここでは、親コンポーネント内に子コンポーネントが含まれています。
  • script: コンポーネントのロジックを定義します。データ、プロパティ、メソッド、ライフサイクルフックなどが含まれます。
  • style: コンポーネントの見た目を定義します。scopedキーワードを使用することで、スタイルがそのコンポーネントに限定されます。

例の説明

親コンポーネント(ParentComponent.vue)

templateセクションでは、<ChildComponent>タグを使用して子コンポーネントを組み込み、messageプロパティにparentMessageの値を渡しています。

data(※)オプションでparentMessageというデータプロパティを定義しています。componentsオプションで、ChildComponentをインポートし、登録しています。

子コンポーネント(ChildComponent.vue)

templateセクションでは、親コンポーネントから受け取ったmessageプロパティを表示しています。

props(※)オプションで、親コンポーネントから受け取るmessageプロパティを定義しています。typeStringであり、必須であることを指定しています。

datapropsについては後で説明が出てきます。

このようにコンポーネントを使うことでアプリケーションのUIを小さな再利用可能な部分に分割し、各部分を独立して管理および開発することができます。

コンポーネントは、複雑なアプリケーションをシンプルで直感的なものにし開発プロセスを効率化します。

propsとは

propsは、親コンポーネントから子コンポーネントにデータを渡すための機能です。

親コンポーネントから渡されたデータは、子コンポーネント内で読み取り専用(readonly)となります。

コード例

<!-- 親コンポーネント -->
<template>
  <ChildComponent message="Hello from Parent!"/>
</template>

<script>
import ChildComponent from './ChildComponent.vue';

export default {
  components: {
    ChildComponent
  }
};
</script>
<!-- 子コンポーネント -->
<template>
  <div>{{ message }}</div>
</template>

<script>
export default {
  props: {
    message: {
      type: String,
      required: true
    }
  }
};
</script>

dataとは

dataオプションは、コンポーネントのインスタンスに対して持つ状態(ステート)を定義します。

dataオプションは関数として定義され、その関数がオブジェクトを返します。

コード例

<template>
  <div>{{ count }}</div>
  <button @click="incrementCount">Increment</button>
</template>

<script>
export default {
  data() {
    return {
      count: 0
    };
  },
  methods: {
    incrementCount() {
      this.count++;
    }
  }
};
</script>

asyncDataとは

asyncDataはNuxt.js特有のメソッドで、コンポーネントがレンダリングされる前にデータを取得し、それをコンポーネントのデータとして設定します。

コード例

export default {
  async asyncData({ params }) {
    const data = await fetch(`https://api.example.com/data/${params.id}`)
      .then(res => res.json());
    return { data };
  }
};

computedとは

computedプロパティは依存関係に基づいて動的に計算されたプロパティを定義します。

これによりデータの変化に応じて自動的に再計算されます。

コード例

<template>
  <div>{{ reversedMessage }}</div>
</template>

<script>
export default {
  data() {
    return {
      message: 'Hello, World!'
    };
  },
  computed: {
    reversedMessage() {
      return this.message.split('').reverse().join('');
    }
  }
};
</script>

stateとは

Vue.js自体にはstateという特定の概念はありませんが、Vuexを使用して状態管理を行う際にstateという名前のオプションがよく使われます。

stateはアプリケーションの中央で管理される状態を保持します。

コード例

// store.js
import Vue from 'vue';
import Vuex from 'vuex';

Vue.use(Vuex);

export default new Vuex.Store({
  state: {
    count: 0
  },
  mutations: {
    increment(state) {
      state.count++;
    }
  }
});
<!-- コンポーネント内での使用 -->
<template>
  <div>{{ count }}</div>
  <button @click="incrementCount">Increment</button>
</template>

<script>
import { mapState, mapMutations } from 'vuex';

export default {
  computed: {
    ...mapState(['count'])
  },
  methods: {
    ...mapMutations(['increment'])
  }
};
</script>

data-cyとは

data-cyはテスト対象要素を指定するために使われるカスタム属性です。

Cypressのようなエンドツーエンドテストツールで、特定の要素を簡単に識別するために使用されます。

コード例

<template>
  <button data-cy="increment-button">Increment</button>
</template>
// Cypressテスト例
describe('Increment Button', () => {
  it('increments the count', () => {
    cy.visit('/');
    cy.get('[data-cy=increment-button]').click();
    cy.contains('1');
  });
});

watchとは

watchは特定のデータプロパティの変更を監視し、変更があった場合に指定した処理を実行するために使用されます。

変更前と変更後の値を引数として受け取ることができます。

コード例

<template>
  <div>{{ count }}</div>
  <button @click="incrementCount">Increment</button>
</template>

<script>
export default {
  data() {
    return {
      count: 0
    };
  },
  methods: {
    incrementCount() {
      this.count++;
    }
  },
  watch: {
    count(newVal, oldVal) {
      console.log(`カウントが ${oldVal} から ${newVal} に変更されました。`);
    }
  }
};
</script>

mountedとは

mountedフックはコンポーネントがDOMにマウントされた後に実行されます。

これによりDOM要素へのアクセスや初期化処理を行うことができます。

コード例

<template>
  <div ref="myElement">This is a mounted element</div>
</template>

<script>
export default {
  mounted() {
    console.log(this.$refs.myElement);
  }
};
</script>

mixinsとは

mixinsは複数のコンポーネント間で再利用可能なコードを定義するための仕組みです。

mixins内のデータ、メソッド、ライフサイクルフックは、コンポーネントに「ミックスイン」されます。

コード例

// mixin.js
export const myMixin = {
  data() {
    return {
      mixinData: 'This is mixin data'
    };
  },
  methods: {
    mixinMethod() {
      console.log('This is a mixin method');
    }
  }
};
<!-- コンポーネント内での使用 -->
<template>
  <div>{{ mixinData }}</div>
</template>

<script>
import { myMixin } from './mixin';

export default {
  mixins: [myMixin]
};
</script>

fetchとは

fetchはAPIからデータを取得するためのメソッドです。

Nuxt.jsでよく使われ、サーバーサイドレンダリング(SSR)や静的サイト生成時にデータを取得できます。

コード例

export default {
  async fetch({ store }) {
    const data = await fetch('https://api.example.com/data')
      .then(res => res.json());
    store.commit('setData', data);
  }
};

middlewareとは

middlewareはルートに対してアクセスする前に実行される関数です。

認証やリダイレクトなどの処理を行うために使用されます。Nuxt.jsでよく使われます。

コード例

// middleware/auth.js
export default function ({ store, redirect }) {
  if (!store.state.authenticated) {
    return redirect('/login');
  }
}
// nuxt.config.js
export default {
  router: {
    middleware: 'auth'
  }
};

画面遷移時のデータ取得のフロー

コード例

// pages/index.vue
<template>
  <div>{{ data }}</div>
</template>

<script>
export default {
  asyncData({ params }) {
    return fetch(`https://api.example.com/data/${params.id}`)
      .then(res => res.json())
      .then(data => {
        return { data };
      });
  }
};
</script>

親から子、孫コンポーネントに値を渡す方法

コード例

<!-- 親コンポーネント -->
<template>
  <ChildComponent :parent-value="parentValue"/>
</template>

<script>
import ChildComponent from './ChildComponent.vue';

export default {
  components: {
    ChildComponent
  },
  data() {
    return {
      parentValue: 'Value from Parent'
    };
  }
};
</script>
<!-- 子コンポーネント -->
<template>
  <div>
    <GrandchildComponent :child-value="parentValue"/>
  </div>
</template>

<script>
import GrandchildComponent from './GrandchildComponent.vue';

export default {
  components: {
    GrandchildComponent
  },
  props: {
    parentValue: {
      type: String,
      required: true
    }
  }
};
</script>
<!-- 孫コンポーネント -->
<template>
  <div>{{ childValue }}</div>
</template>

<script>
export default {
  props: {
    childValue: {
      type: String,
      required: true
    }
  }
};
</script>

親から子、孫コンポーネントに値を渡す方法:provideとinjectを使うパターン

provideinjectは、Vue.jsで深いコンポーネント階層にデータを渡すための便利な機能です。

この方法を使うと、複数階層をまたいでデータを受け渡すことができます。

ここでは具体的なコード例を用いて説明します。

  • 親コンポーネント: provideを使ってデータ(parentValue)を提供します。
  • 子コンポーネント: injectを使って親コンポーネントから提供されたデータ(sharedValue)を受け取ります。
  • 孫コンポーネント: injectを使って子コンポーネントからデータ(sharedValue)を受け取ります。

親コンポーネント

親コンポーネントでは、provideオプションを使ってデータを提供します。

<!-- ParentComponent.vue -->
<template>
  <div>
    <p>親コンポーネント: {{ parentValue }}</p>
    <ChildComponent />
  </div>
</template>

<script>
import ChildComponent from './ChildComponent.vue';

export default {
  components: {
    ChildComponent
  },
  data() {
    return {
      parentValue: 'Value from Parent'
    };
  },
  provide() {
    return {
      sharedValue: this.parentValue
    };
  }
};
</script>

子コンポーネント

子コンポーネントではinjectオプションを使ってデータを受け取ります。

このデータはさらに孫コンポーネントに渡すことも可能です。

<!-- ChildComponent.vue -->
<template>
  <div>
    <p>子コンポーネント: {{ sharedValue }}</p>
    <GrandchildComponent />
  </div>
</template>

<script>
import GrandchildComponent from './GrandchildComponent.vue';

export default {
  components: {
    GrandchildComponent
  },
  inject: ['sharedValue']
};
</script>

孫コンポーネント

孫コンポーネントでも同様にinjectオプションを使ってデータを受け取ります。

<!-- GrandchildComponent.vue -->
<template>
  <div>
    <p>孫コンポーネント: {{ sharedValue }}</p>
  </div>
</template>

<script>
export default {
  inject: ['sharedValue']
};
</script>

最後に

この記事ではVue.jsの基本概念から実践的な使用例までを詳しく解説しました。

各機能の説明と具体的なコード例を通じて、Vue.jsを効果的に学び、プロジェクトに活用できるようになっていただければ幸いです。

フリーランスフルリモート環境に興味がある方は、下記の記事をご参考ください。

  • この記事を書いた人

zuu

現役フリーランスlaravelエンジニアのスキルスタックブログです。 日々の技術的発見やフリーランスエンジニア業界についてのあれこれをご紹介します。エージェントは PE-BANK を利用しています。

-スキルアップ