
Vue.js ルーティング演習問題
基本概念まとめ 1. ルーティングの基本設定 2. ナビゲーションガード 3. 動的ルーティング 演習問題(全24問) 初級問題(6問) 基本ルーティング ナビ […]
単一ファイルコンポーネント(Single File Component、以下SFC)は、Vue.jsのコンポーネントを.vue
拡張子の1つのファイルにまとめる仕組みです。1つのファイルにテンプレート(HTML)、ロジック(JavaScript)、スタイル(CSS)をカプセル化できます。
<template>
<div class="example">{{ msg }}</div>
</template>
<script>
export default {
data() {
return {
msg: 'Hello world!'
}
}
}
</script>
<style>
.example {
color: red;
}
</style>
SFCは3つの主要なセクションで構成されます。
<template>
<div>
<h1>{{ title }}</h1>
<p>{{ content }}</p>
<button @click="handleClick">クリック</button>
</div>
</template>
<script>
export default {
name: 'MyComponent',
data() {
return {
title: 'コンポーネントのタイトル',
content: 'これはコンポーネントの内容です'
}
},
methods: {
handleClick() {
alert('ボタンがクリックされました');
}
}
}
</script>
<style scoped>
h1 {
color: #42b983;
}
button {
padding: 8px 16px;
background-color: #42b983;
color: white;
border: none;
border-radius: 4px;
}
</style>
scoped
属性でコンポーネント専用のスタイルを定義可能// main.js
import Vue from 'vue';
import MyComponent from './MyComponent.vue';
Vue.component('MyComponent', MyComponent);
new Vue({
el: '#app'
});
<script>
import MyComponent from './MyComponent.vue';
export default {
components: {
MyComponent
}
}
</script>
親コンポーネントから子コンポーネントへデータを渡します。
<!-- ParentComponent.vue -->
<template>
<ChildComponent :message="parentMessage" />
</template>
<script>
import ChildComponent from './ChildComponent.vue';
export default {
components: {
ChildComponent
},
data() {
return {
parentMessage: '親からのメッセージ'
}
}
}
</script>
<!-- ChildComponent.vue -->
<template>
<div>{{ message }}</div>
</template>
<script>
export default {
props: {
message: {
type: String,
required: true,
default: 'デフォルトメッセージ'
}
}
}
</script>
子コンポーネントから親コンポーネントへイベントを発行します。
<!-- ChildComponent.vue -->
<template>
<button @click="notifyParent">親に通知</button>
</template>
<script>
export default {
methods: {
notifyParent() {
this.$emit('child-event', '子からのデータ');
}
}
}
</script>
<!-- ParentComponent.vue -->
<template>
<ChildComponent @child-event="handleChildEvent" />
</template>
<script>
import ChildComponent from './ChildComponent.vue';
export default {
components: {
ChildComponent
},
methods: {
handleChildEvent(data) {
console.log('子コンポーネントから:', data);
}
}
}
</script>
親コンポーネントから子コンポーネントへコンテンツを渡します。
<!-- ChildComponent.vue -->
<template>
<div class="container">
<h2>タイトル</h2>
<slot>デフォルトコンテンツ</slot>
</div>
</template>
<!-- ParentComponent.vue -->
<template>
<ChildComponent>
<p>ここがスロットに挿入されるコンテンツです</p>
</ChildComponent>
</template>
複数のスロットを定義する場合に使用します。
<!-- BaseLayout.vue -->
<template>
<div class="container">
<header>
<slot name="header"></slot>
</header>
<main>
<slot></slot>
</main>
<footer>
<slot name="footer"></slot>
</footer>
</div>
</template>
<!-- ParentComponent.vue -->
<template>
<BaseLayout>
<template v-slot:header>
<h1>ヘッダーコンテンツ</h1>
</template>
<p>メインコンテンツ</p>
<template v-slot:footer>
<p>フッターコンテンツ</p>
</template>
</BaseLayout>
</template>
<component>
タグとis
属性で動的にコンポーネントを切り替えられます。
<template>
<div>
<button @click="currentComponent = 'ComponentA'">Aを表示</button>
<button @click="currentComponent = 'ComponentB'">Bを表示</button>
<component :is="currentComponent"></component>
</div>
</template>
<script>
import ComponentA from './ComponentA.vue';
import ComponentB from './ComponentB.vue';
export default {
components: {
ComponentA,
ComponentB
},
data() {
return {
currentComponent: 'ComponentA'
}
}
}
</script>
複数のコンポーネントでロジックを共有できます。
// myMixin.js
export default {
data() {
return {
mixinData: 'ミックスインのデータ'
}
},
methods: {
mixinMethod() {
console.log('ミックスインのメソッド');
}
}
}
<!-- MyComponent.vue -->
<script>
import myMixin from './myMixin.js';
export default {
mixins: [myMixin],
created() {
console.log(this.mixinData); // ミックスインのデータ
this.mixinMethod(); // ミックスインのメソッド
}
}
</script>
コンポーネント内でカスタムディレクティブを定義できます。
<template>
<div v-highlight="'yellow'">このテキストはハイライトされます</div>
</template>
<script>
export default {
directives: {
highlight: {
inserted(el, binding) {
el.style.backgroundColor = binding.value;
}
}
}
}
</script>
Vue 3のComposition APIをSFCで使用する例です。
<template>
<div>
<p>Count: {{ count }}</p>
<button @click="increment">増やす</button>
</div>
</template>
<script>
import { ref } from 'vue';
export default {
setup() {
const count = ref(0);
const increment = () => {
count.value++;
};
return {
count,
increment
};
}
}
</script>
SFCはテストが書きやすい構造です。
// MyComponent.spec.js
import { shallowMount } from '@vue/test-utils';
import MyComponent from './MyComponent.vue';
describe('MyComponent', () => {
it('クリック時にイベントを発行する', () => {
const wrapper = shallowMount(MyComponent);
wrapper.find('button').trigger('click');
expect(wrapper.emitted('click-event')).toBeTruthy();
});
});
MyComponent.vue
)<!--
@component MyButton
@desc カスタムボタンコンポーネント
@prop {String} type - ボタンのタイプ (primary|secondary)
@prop {Boolean} disabled - 無効状態
@event click - クリックイベント
@slot default - ボタン内のコンテンツ
-->
<template>
<button
:class="['my-button', type]"
:disabled="disabled"
@click="$emit('click')"
>
<slot></slot>
</button>
</template>
<script>
export default {
name: 'MyButton',
props: {
type: {
type: String,
default: 'primary',
validator: value => ['primary', 'secondary'].includes(value)
},
disabled: {
type: Boolean,
default: false
}
}
}
</script>
<style scoped>
.my-button {
padding: 8px 16px;
border-radius: 4px;
cursor: pointer;
}
.my-button.primary {
background-color: #42b983;
color: white;
}
.my-button.secondary {
background-color: #f0f0f0;
color: #333;
}
.my-button:disabled {
opacity: 0.5;
cursor: not-allowed;
}
</style>
Vue.jsの単一ファイルコンポーネント(SFC)は、現代的なフロントエンド開発に最適化された強力な機能です。.vue
ファイルにテンプレート、スクリプト、スタイルをまとめることで、コンポーネントの開発とメンテナンスが容易になります。
scoped
属性でスタイルの衝突を防止SFCを適切に活用することで、より整理された、メンテナンス性の高いVue.jsアプリケーションを構築できます。