テンプレート構文
Vue3はHTMLベースのテンプレート構文でDOMとデータを同期します。テンプレートは有効なHTMLで、内部的に最適化されたJavaScriptにコンパイルされます。
データバインディング
<script setup>
let greeting = "こんにちは Vue3"
let userAge = 20
let items = [
{name:"本", cost:1500, qty:2},
{name:"ペン", cost:300, qty:5}
]
function calcTotal() {
return items.reduce((sum, item) => sum + item.cost * item.qty, 0)
}
</script>
<template>
<p>{{ greeting }}</p>
<p>年齢: {{ userAge }}, 成人: {{ userAge >= 20 ? 'はい' : 'いいえ' }}</p>
<p>合計金額: {{ calcTotal() }}円</p>
</template>
属性バインディング
<script setup>
const siteData = {
logo: "/images/logo.png",
url: "https://example.com"
}
</script>
<template>
<a :href="siteData.url">
<img :src="siteData.logo" :alt="siteData.name">
</a>
</template>
イベント処理
<script setup>
import { ref } from 'vue'
let count = ref(0)
function increment() {
count.value++
}
</script>
<template>
<button @click="increment">カウントアップ</button>
<button @click.prevent="submitForm">送信</button>
<p>カウント: {{ count }}</p>
</template>
リアクティブシステム
<script setup>
import { ref, reactive } from 'vue'
let counter = ref(0)
let profile = reactive({ name: "太郎", age: 25 })
function updateAge() {
profile.age++
}
</script>
条件付きレンダリング
<script setup>
import { ref } from 'vue'
let isVisible = ref(true)
</script>
<template>
<div v-if="isVisible">表示コンテンツ</div>
<div v-else>代替コンテンツ</div>
<div v-show="isVisible">CSS表示制御</div>
</template>
リストレンダリング
<script setup>
import { reactive } from 'vue'
let products = reactive([
{ id: 1, name: "ノート", price: 300 },
{ id: 2, name: "消しゴム", price: 100 }
])
</script>
<template>
<ul>
<li v-for="(item, index) in products" :key="item.id">
{{ index+1 }}. {{ item.name }} - {{ item.price }}円
</li>
</ul>
</template>
双方向バインディング
<script setup>
import { ref } from 'vue'
let username = ref('')
let selectedOption = ref('1')
</script>
<template>
<input type="text" v-model="username">
<select v-model="selectedOption">
<option value="1">東京</option>
<option value="2">大阪</option>
</select>
</template>
算出プロパティ
<script setup>
import { computed, reactive } from 'vue'
const author = reactive({
books: ["Vueガイド", "React入門"]
})
const hasPublished = computed(() => {
return author.books.length > 0 ? 'はい' : 'いいえ'
})
</script>
ウォッチャ
<script setup>
import { watch, ref } from 'vue'
let searchQuery = ref('')
watch(searchQuery, (newVal, oldVal) => {
console.log(`検索語: ${oldVal} → ${newVal}`)
fetchResults(newVal)
})
</script>
ライフサイクルフック
<script setup>
import { onMounted, onUpdated } from 'vue'
onMounted(() => {
console.log("コンポーネントマウント完了")
})
onUpdated(() => {
console.log("DOM更新完了")
})
</script>
コンポーネント設計
基本構造
// App.vue
<template>
<Header />
<Navigation />
<MainContent />
</template>
コンポーネント間通信
// ChildComponent.vue
<script setup>
defineProps({ message: String })
const emit = defineEmits(["notifyParent"])
function sendData(data) {
emit("notifyParent", data)
}
</script>
ルーティングシステム
ルーター設定
import { createRouter, createWebHistory } from 'vue-router'
import HomePage from './views/Home.vue'
import ProductList from './views/Products.vue'
const router = createRouter({
history: createWebHistory(),
routes: [
{ path: '/', component: HomePage },
{ path: '/products', component: ProductList },
{ path: '/:pathMatch(.*)*', redirect: '/' }
]
})
ルーター使用例
<template>
<router-link to="/">ホーム</router-link>
<router-link to="/products">商品一覧</router-link>
<router-view></router-view>
</template>