1. Vue.js ãšã¯ïŒ ð€
Vue.jsïŒãŽã¥ãŒã»ãžã§ã€ãšã¹ãçºé³ã¯ /vjuË/ 㧠“view” ãšåãïŒã¯ããŠãŒã¶ãŒã€ã³ã¿ãŒãã§ãŒã¹ïŒUIïŒãæ§ç¯ããããã®ããã°ã¬ãã·ããªJavaScriptãã¬ãŒã ã¯ãŒã¯ã§ããGoogleã§AngularJSã®éçºã«æºãã£ãŠããEvan YouïŒãšãŽã¡ã³ã»ãšãŒïŒæ°ã«ãã£ãŠå人çãªãããžã§ã¯ããšããŠéçºãéå§ããã2014幎2æã«æåã®ããŒãžã§ã³ããªãªãŒã¹ãããŸããã
Vue.jsã¯ãWebãµã€ããWebã¢ããªã±ãŒã·ã§ã³ã®èŠãç®éšåïŒããã³ããšã³ãïŒãå¹ççã«éçºããããã«èšèšãããŠããŸããç¹ã«ãã·ã³ã°ã«ããŒãžã¢ããªã±ãŒã·ã§ã³ïŒSPAïŒã®æ§ç¯ã«é©ããŠããããã®ã·ã³ãã«ããæè»æ§ãããã©ãŒãã³ã¹ã®é«ããããäžçäžã®éçºè ã³ãã¥ããã£ã§æ¥éã«äººæ°ãéããŠããŸãã
Vue.js ã®æŽå²
Vue.jsã®äž»ãªããŒãžã§ã³ã®æŽå²ã¯ä»¥äžã®éãã§ãã
- 2014幎2æ: Vue.js åç (v0.8) ãªãªãŒã¹
- 2015幎10æ: v1.0 “Evangelion” ãªãªãŒã¹
- 2016幎10æ: v2.0 “Ghost in the Shell” ãªãªãŒã¹ (ä»®æ³DOMãæ¡çš)
- 2020幎9æ: v3.0 “One Piece” ãªãªãŒã¹ (Composition APIãªã©ãå°å ¥)
- 2022幎2æ: Vue 3 ãããã©ã«ãããŒãžã§ã³ã«
- 2023幎12æ31æ¥: Vue 2 ã®ãµããŒãçµäº (EOL – End Of Life)
- 2024幎9æ: v3.5 “Tengen Toppa Gurren Lagann” ãªãªãŒã¹ (ããã©ãŒãã³ã¹åäžãªã©)
äœè ã®ãšãŽã¡ã³ã»ãšãŒæ°ããã³ã¬å¥œãã§ããããšãããã¡ãžã£ãŒããŒãžã§ã³ã«ã¯æ¥æ¬ã®ãã³ã¬ãã¢ãã¡ã«ã¡ãªãã ã³ãŒãããŒã ãä»ããããŠããŸãã
Vue.js ã®äž»ãªç¹åŸŽ âš
- ããã°ã¬ãã·ããã¬ãŒã ã¯ãŒã¯ (Approachable & Versatile): Vueã¯ã段éçã«å°å ¥ã§ããããã«èšèšãããŠããŸããæ¢åã®ãããžã§ã¯ãã«å°ããã€é©çšããããšããå®å šã«Vueã ãã§å€§èŠæš¡ãªSPAãæ§ç¯ããããšãå¯èœã§ããã³ã¢ã©ã€ãã©ãªã¯Viewå±€ã«çŠç¹ãåœãŠãŠãããå¿ èŠã«å¿ããŠã«ãŒãã£ã³ã°ïŒVue RouterïŒãç¶æ 管çïŒPiniaïŒãªã©ã®å ¬åŒã©ã€ãã©ãªãè¿œå ã§ããŸãã
- åŠç¿ã³ã¹ãã®äœã (Approachable): åºæ¬çãªHTMLãCSSãJavaScriptã®ç¥èãããã°ãæ¯èŒç容æã«åŠç¿ãå§ããããšãã§ããŸããå ¬åŒããã¥ã¡ã³ããéåžžã«å å®ããŠãããæ¥æ¬èªã®æ å ±ãè±å¯ã§ããæ§æãã·ã³ãã«ã§çŽæçã§ãã
- é«ãããã©ãŒãã³ã¹ (Performant): ä»®æ³DOMïŒVirtual DOMïŒãæ¡çšããŠãããDOMæäœãæé©åããããšã§é«éãªã¬ã³ããªã³ã°ãå®çŸããŸãããŸããã³ã³ãã€ã«æã®æé©åã«ãããã©ã³ã¿ã€ã ã®ãªãŒããŒããããåæžãããŠããŸããVue 3ã§ã¯ããã«ããã©ãŒãã³ã¹ãåäžããŸããã
- ãªã¢ã¯ãã£ãã·ã¹ãã (Reactivity): Vueã®æ žãšãªãæ©èœã®äžã€ã§ããJavaScriptã®ããŒã¿ïŒç¶æ ïŒãå€æŽããããšãããã«å¿ããŠé¢é£ããDOMãèªåçã«æŽæ°ãããŸããããã«ãããéçºè ã¯DOMãçŽæ¥æäœããæéãã解æŸãããããŒã¿ç®¡çã«éäžã§ããŸãã
- ã³ã³ããŒãã³ãããŒã¹ã¢ãŒããã¯ã㣠(Component-Based): ã¢ããªã±ãŒã·ã§ã³ãåå©çšå¯èœãªç¬ç«ããã³ã³ããŒãã³ãïŒéšåïŒã«åå²ããŠæ§ç¯ããŸããããã«ãããã³ãŒãã®èŠéããè¯ããªããä¿å®æ§ãåå©çšæ§ãåäžããŸãã
-
è±å¯ãªããŒã«ãšãšã³ã·ã¹ãã :
éçºãå¹çåããããã®å
¬åŒCLIïŒ
create-vue
/ Vue CLIïŒããã©ãŠã¶æ¡åŒµæ©èœïŒVue DevToolsïŒãã«ãŒãã£ã³ã°ã©ã€ãã©ãªïŒVue RouterïŒãç¶æ 管çã©ã€ãã©ãªïŒPiniaïŒãªã©ãæäŸãããŠããŸãã
2. Vue.js ãå§ããŠã¿ãã ð ïž
Vue.jsããããžã§ã¯ãã«å°å ¥ããã«ã¯ãããã€ãã®æ¹æ³ããããŸãã
CDN ã䜿ãæ¹æ³
æãæ軜ãªæ¹æ³ã¯ãCDNïŒContent Delivery NetworkïŒãå©çšããããšã§ããHTMLãã¡ã€ã«ã«<script>
ã¿ã°ãè¿œå ããã ãã§ãããã«Vue.jsã䜿ãå§ããããšãã§ããŸããæ¢åã®HTMLããŒãžã«Vueã®æ©èœãå°ãã ãè¿œå ãããå Žåãããããã¿ã€ãã³ã°ã«äŸ¿å©ã§ãã
<!DOCTYPE html>
<html>
<head>
<title>My Vue App</title>
<!-- Vue.js æ¬äœãèªã¿èŸŒã -->
<script src="https://unpkg.com/vue@3"></script>
</head>
<body>
<div id="app">
{{ message }}
<button @click="changeMessage">Change Message</button>
</div>
<script>
const { createApp, ref } = Vue;
createApp({
setup() {
const message = ref('Hello Vue from CDN!');
function changeMessage() {
message.value = 'Message Changed!';
}
return {
message,
changeMessage
};
}
}).mount('#app');
</script>
</body>
</html>
Node.js ãšãã«ãããŒã« (Vite) ã䜿ãæ¹æ³
ããæ¬æ Œçãªéçºãç¹ã«åäžãã¡ã€ã«ã³ã³ããŒãã³ãïŒSFC: Single File ComponentsïŒãå©çšããSPAéçºã§ã¯ãNode.jsããŒã¹ã®ãã«ãããŒã«ã䜿ãã®ãäžè¬çã§ããVue 3ããã¯ãé«éãªéçºãµãŒããŒãšãã«ãããŒã«ã§ãã Vite (ãŽã£ãŒã) ãæšå¥šãããŠããŸãã
ãŸããNode.js (ããŒãžã§ã³ 18.3 以äžæšå¥š) ãã€ã³ã¹ããŒã«ãããŠããããšã確èªããŠãã ããã次ã«ãã¿ãŒããã«ã§ä»¥äžã®ã³ãã³ããå®è¡ããŸãã
# npm ã䜿ãå Žå
npm create vue@latest
# yarn ã䜿ãå Žå
yarn create vue
# pnpm ã䜿ãå Žå
pnpm create vue@latest
# bun ã䜿ãå Žå
bun create vue@latest
ãã®ã³ãã³ããå®è¡ãããšãcreate-vue
ãšããå
¬åŒããŒã«ãèµ·åãããããžã§ã¯ãåãTypeScriptã®å©çšãVue RouterãPiniaã®å°å
¥ãªã©ã察話圢åŒã§èšå®ã§ããŸããèšå®ãå®äºãããšããããžã§ã¯ããã£ã¬ã¯ããªãäœæãããŸãã
# ãããžã§ã¯ããã£ã¬ã¯ããªã«ç§»å
cd <your-project-name>
# äŸåé¢ä¿ãã€ã³ã¹ããŒã«
npm install # ãŸã㯠yarn install ã pnpm install, bun install
# éçºãµãŒããŒãèµ·å
npm run dev # ãŸã㯠yarn dev, pnpm dev, bun dev
éçºãµãŒããŒãèµ·åãããã衚瀺ãããURLïŒé垞㯠http://localhost:5173
ãªã©ïŒã«ãã©ãŠã¶ã§ã¢ã¯ã»ã¹ãããšãäœæãããVueã¢ããªã±ãŒã·ã§ã³ã衚瀺ãããŸãã ð
3. Vue.js ã®ã³ã¢ã³ã³ã»ãã ð§
Vue.jsãç解ããäžã§éèŠãªãããã€ãã®åºæ¬çãªæŠå¿µãèŠãŠãããŸãããã
Vue ã¢ããªã±ãŒã·ã§ã³ã€ã³ã¹ã¿ã³ã¹
ãã¹ãŠã®Vueã¢ããªã±ãŒã·ã§ã³ã¯ãcreateApp
é¢æ°ã§æ°ããã¢ããªã±ãŒã·ã§ã³ã€ã³ã¹ã¿ã³ã¹ãäœæããããšããå§ãŸããŸãã
import { createApp } from 'vue';
// ã«ãŒãã³ã³ããŒãã³ããã€ã³ããŒã (éåžž App.vue)
import App from './App.vue';
// ã¢ããªã±ãŒã·ã§ã³ã€ã³ã¹ã¿ã³ã¹ãäœæ
const app = createApp(App);
// HTMLèŠçŽ ã«ããŠã³ããã
app.mount('#app');
mount()
ã¡ãœããã¯ãã¢ããªã±ãŒã·ã§ã³ã€ã³ã¹ã¿ã³ã¹ãç¹å®ã®DOMèŠçŽ ïŒãã®äŸã§ã¯id="app"
ãæã€èŠçŽ ïŒã«é¢é£ä»ãããã®èŠçŽ å
ã§Vueã¢ããªã±ãŒã·ã§ã³ãã¬ã³ããªã³ã°ããŸãã
ãã³ãã¬ãŒãæ§æ
Vueã¯ãHTMLããŒã¹ã®ãã³ãã¬ãŒãæ§æã䜿çšããã¬ã³ããªã³ã°ãããDOMãåºç€ãšãªãJavaScriptã®ç¶æ ïŒããŒã¿ïŒã«å®£èšçã«ãã€ã³ãããŸãã
-
ããã¹ãå±é (Text Interpolation):
äºéäžæ¬åŒ§
{{ }}
(ãã¹ã¿ãã·ã¥æ§æ) ã䜿ã£ãŠãããŒã¿ããããã£ã®å€ãããã¹ããšããŠè¡šç€ºããŸãã<span>ã¡ãã»ãŒãž: {{ msg }}</span>
-
å±æ§ãã€ã³ãã£ã³ã° (Attribute Bindings):
v-bind
ãã£ã¬ã¯ãã£ãïŒçç¥åœ¢ã¯:
ïŒã䜿ã£ãŠãHTMLèŠçŽ ã®å±æ§ã«åçãªå€ããã€ã³ãããŸãã<!-- å®å šãªæ§æ --> <div v-bind:id="dynamicId"></div> <!-- çç¥åœ¢ --> <div :id="dynamicId"></div> <!-- ããŒã«å€å±æ§ã®ãã€ã³ãã£ã³ã° --> <button :disabled="isButtonDisabled">ãã¿ã³</button>
-
JavaScript åŒã®äœ¿çš:
{{ }}
ãv-bind
ã®äžã§ã¯ãåäžã®JavaScriptåŒã䜿çšã§ããŸãã{{ number + 1 }} {{ ok ? 'YES' : 'NO' }} {{ message.split('').reverse().join('') }} <div :id="`list-${id}`"></div>
-
ãã£ã¬ã¯ãã£ã (Directives):
v-
æ¥é èŸãæã€ç¹å¥ãªå±æ§ã§ãDOMã«ç¹å¥ãªãªã¢ã¯ãã£ããªæ¯ãèããé©çšããŸããv-if
/v-else
/v-else-if
: æ¡ä»¶ã«åºã¥ããŠèŠçŽ ãã¬ã³ããªã³ã°ããŸããv-for
: é åããªããžã§ã¯ãã«åºã¥ããŠèŠçŽ ã®ãªã¹ããã¬ã³ããªã³ã°ããŸããv-on
(çç¥åœ¢@
): DOMã€ãã³ãã賌èªããã€ãã³ãçºçæã«JavaScriptã³ãŒããå®è¡ããŸããv-model
: ãã©ãŒã ã®<input>
ã<textarea>
ã<select>
èŠçŽ ã«åæ¹åãã€ã³ãã£ã³ã°ãäœæããŸããv-show
: æ¡ä»¶ã«åºã¥ããŠèŠçŽ ã®CSSdisplay
ããããã£ãåãæ¿ããŸããv-bind
(çç¥åœ¢:
): HTMLå±æ§ããªã¢ã¯ãã£ãã«æŽæ°ããŸãã
ãªã¢ã¯ãã£ããã£ãŒã®åºç€ (Reactivity Fundamentals)
Vue 3ã§ã¯ãComposition APIãšããæ°ããAPIã¹ã¿ã€ã«ãå°å ¥ããããªã¢ã¯ãã£ããªç¶æ ãäœæããããã®é¢æ°ãæäŸãããŠããŸãã
-
ref()
: ããªããã£ãå€ïŒæååãæ°å€ãçåœå€ãªã©ïŒããªããžã§ã¯ãããªã¢ã¯ãã£ãã«ããããã«äœ¿ããŸããref
ã¯.value
ããããã£ãæã€ãªããžã§ã¯ããè¿ããŸããã¹ã¯ãªããå ã§ã¯.value
ã§ã¢ã¯ã»ã¹ãããã³ãã¬ãŒãå ã§ã¯èªåçã«ã¢ã³ã©ãããããŠçŽæ¥ã¢ã¯ã»ã¹ã§ããŸããimport { ref } from 'vue'; const count = ref(0); // ãªã¢ã¯ãã£ããªåç §ãäœæ console.log(count.value); // 0 count.value++; // å€ãå€æŽ console.log(count.value); // 1
<template> <div>{{ count }}</div> <!-- ãã³ãã¬ãŒãå ã§ã¯ .value ã¯äžèŠ --> </template>
-
reactive()
: äž»ã«ãªããžã§ã¯ãïŒãã¬ãŒã³ãªJavaScriptãªããžã§ã¯ããé åïŒããªã¢ã¯ãã£ãã«ããããã«äœ¿ããŸããããã¯ãªããžã§ã¯ãèªèº«ããªã¢ã¯ãã£ããªãããã·ã«å€æããŸããref
ãšã¯ç°ãªãã.value
ã¯äžèŠã§ãéåžžã®ãªããžã§ã¯ãã®ããã«ããããã£ã«ã¢ã¯ã»ã¹ããŸããimport { reactive } from 'vue'; const state = reactive({ count: 0, user: { name: 'Alice' } }); console.log(state.count); // 0 state.count++; console.log(state.user.name); // Alice state.user.name = 'Bob';
泚æ:
reactive()
ã§äœæãããªã¢ã¯ãã£ããªããžã§ã¯ããåå²ä»£å ¥ãããšããªã¢ã¯ãã£ããã£ã倱ãããå¯èœæ§ããããŸããåå²ä»£å ¥ããå Žåã¯toRefs()
ãtoRef()
ã䜿çšããŸãã
ç®åºãããã㣠(Computed Properties)
ãã³ãã¬ãŒãå ã§è€éãªããžãã¯ã䜿ã代ããã«ãç®åºããããã£ãå©çšã§ããŸããç®åºããããã£ã¯ãäŸåãããªã¢ã¯ãã£ããªå€ã«åºã¥ããŠãã£ãã·ã¥ãããäŸåé¢ä¿ãå€æŽãããå Žåã«ã®ã¿åè©äŸ¡ãããŸããããã©ãŒãã³ã¹ã®æé©åã«åœ¹ç«ã¡ãŸãã
import { ref, computed } from 'vue';
const firstName = ref('John');
const lastName = ref('Doe');
// ç®åºããããã£ãå®çŸ©
const fullName = computed(() => {
console.log('Calculating full name...'); // äŸåé¢ä¿ãå€ãããªãéãå®è¡ãããªã
return firstName.value + ' ' + lastName.value;
});
// fullName.value ã«ã¢ã¯ã»ã¹ãããšèšç®çµæãåŸããã
console.log(fullName.value); // "John Doe"
lastName.value = 'Smith'; // äŸåé¢ä¿ãå€æŽ
console.log(fullName.value); // "John Smith" (åèšç®ããã)
<template>
<p>Full Name: {{ fullName }}</p>
</template>
ãŠã©ããã£ãŒ (Watchers)
ç¹å®ã®ãªã¢ã¯ãã£ããªããŒã¿ãœãŒã¹ãå€æŽããããšãã«ãå¯äœçšïŒéåææäœãDOMæäœãªã©ïŒãå®è¡ãããå ŽåããããŸãããã®ãããªå Žåã«ãŠã©ããã£ãŒã䜿çšããŸãã
import { ref, watch } from 'vue';
const question = ref('');
const answer = ref('質åã«ã¯éåžž ? ãå«ãŸããŸãã');
// question ã®å€æŽãç£èŠ
watch(question, async (newQuestion, oldQuestion) => {
if (newQuestion.includes('?')) {
answer.value = 'èãäž...';
try {
const res = await fetch('https://yesno.wtf/api'); // äŸ: å€éšAPIåŒã³åºã
answer.value = (await res.json()).answer;
} catch (error) {
answer.value = 'ãšã©ãŒïŒAPIã«å°éã§ããŸããã§ããã ' + error;
}
}
});
<template>
<p>
ã¯ã/ããã ã§çãã質åãããŠãã ãã:
<input v-model="question" />
</p>
<p>{{ answer }}</p>
</template>
ã¯ã©ã¹ãšã¹ã¿ã€ã«ã®ãã€ã³ãã£ã³ã°
v-bind:class
ïŒçç¥åœ¢ :class
ïŒãš v-bind:style
ïŒçç¥åœ¢ :style
ïŒã䜿ã£ãŠãèŠçŽ ã®ã¯ã©ã¹ãªã¹ããã€ã³ã©ã€ã³ã¹ã¿ã€ã«ãåçã«æäœã§ããŸãããªããžã§ã¯ãæ§æãé
åæ§æããµããŒãããŠããŸãã
<!-- ãªããžã§ã¯ãæ§æ (ã¯ã©ã¹) -->
<div :class="{ 'active': isActive, 'text-danger': hasError }"></div>
<!-- é
åæ§æ (ã¯ã©ã¹) -->
<div :class="[activeClass, errorClass]"></div>
<!-- ãªããžã§ã¯ãæ§æ (ã¹ã¿ã€ã«) -->
<div :style="{ color: activeColor, fontSize: fontSize + 'px' }"></div>
<!-- é
åæ§æ (ã¹ã¿ã€ã«ãè€æ°ã®ã¹ã¿ã€ã«ãªããžã§ã¯ããçµå) -->
<div :style="[baseStyles, overridingStyles]"></div>
// script setup å
ã®äŸ
import { ref, reactive } from 'vue';
const isActive = ref(true);
const hasError = ref(false);
const activeClass = ref('active');
const errorClass = ref('text-danger');
const activeColor = ref('red');
const fontSize = ref(16);
const baseStyles = reactive({ color: 'blue', fontSize: '14px' });
const overridingStyles = reactive({ fontWeight: 'bold' });
æ¡ä»¶ä»ãã¬ã³ããªã³ã° (Conditional Rendering)
-
v-if
,v-else-if
,v-else
: æ¡ä»¶ãçã®å Žåã«ã®ã¿èŠçŽ ãŸãã¯ã³ã³ããŒãã³ããã¬ã³ããªã³ã°ïŒãŸãã¯ç Žæ£ïŒããŸããåãæ¿ãã³ã¹ããé«ãã§ãã<div v-if="type === 'A'">A</div> <div v-else-if="type === 'B'">B</div> <div v-else-if="type === 'C'">C</div> <div v-else>Not A/B/C</div>
-
v-show
: æ¡ä»¶ã«é¢ãããåžžã«ã¬ã³ããªã³ã°ãããCSSã®display
ããããã£ãåãæ¿ããããšã§è¡šç€º/é衚瀺ãå¶åŸ¡ããŸããåæã¬ã³ããªã³ã°ã³ã¹ãã¯é«ãã§ãããåãæ¿ãã³ã¹ãã¯äœãã§ããé »ç¹ã«åãæ¿ããèŠçŽ ã«é©ããŠããŸãã<h1 v-show="ok">Hello!</h1>
ãªã¹ãã¬ã³ããªã³ã° (List Rendering)
v-for
ãã£ã¬ã¯ãã£ãã䜿çšããŠãé
åããªããžã§ã¯ãã®ããŒã¿ããªã¹ããšããŠã¬ã³ããªã³ã°ããŸãã
<!-- é
åã®å Žå -->
<ul>
<li v-for="(item, index) in items" :key="item.id">
{{ index }} - {{ item.message }}
</li>
</ul>
<!-- ãªããžã§ã¯ãã®å Žå -->
<ul>
<li v-for="(value, key, index) in myObject" :key="key">
{{ index }}. {{ key }}: {{ value }}
</li>
</ul>
:key
å±æ§ã¯ãVueãåããŒãã®åäžæ§ã远跡ããæ¢åã®èŠçŽ ãåå©çšããã³äžŠã¹æ¿ããããã«å¿
é ã§ããéåžžãäžæãªIDãããŒãšããŠäœ¿çšããŸãã
ã€ãã³ããã³ããªã³ã° (Event Handling)
v-on
ãã£ã¬ã¯ãã£ãïŒçç¥åœ¢ @
ïŒã䜿çšããŠãDOMã€ãã³ãã賌èªããã€ãã³ãçºçæã«ã¡ãœãããã€ã³ã©ã€ã³åŒãå®è¡ããŸãã
<!-- ã¡ãœãããã³ãã©ãŒ -->
<button @click="greet">Greet</button>
<!-- ã€ã³ã©ã€ã³ãã³ãã©ãŒ -->
<button @click="count++">Add 1</button>
<!-- ã€ãã³ã修食å (.prevent, .stop ãªã©) -->
<form @submit.prevent="onSubmit">...</form>
<!-- ããŒä¿®é£Ÿå (.enter, .tab ãªã©) -->
<input @keyup.enter="submit" />
// script setup å
ã®äŸ
import { ref } from 'vue';
const count = ref(0);
function greet(event) {
alert('Hello!');
if (event) {
console.log(event.target.tagName); // ã€ãã³ããªããžã§ã¯ãã«ã¢ã¯ã»ã¹å¯èœ
}
}
function onSubmit() {
console.log('Form submitted');
}
function submit() {
console.log('Submitted on Enter');
}
ãã©ãŒã å ¥åãã€ã³ãã£ã³ã° (Form Input Bindings)
v-model
ãã£ã¬ã¯ãã£ãã䜿çšãããšããã©ãŒã ã®å
¥åèŠçŽ ïŒ<input>
, <textarea>
, <select>
ïŒãšã¢ããªã±ãŒã·ã§ã³ã®ç¶æ
ãšã®éã«åæ¹åããŒã¿ãã€ã³ãã£ã³ã°ãç°¡åã«äœæã§ããŸãããŠãŒã¶ãŒã®å
¥åãèªåçã«ããŒã¿ã«åæ ãããããŒã¿ã®å€æŽããã©ãŒã èŠçŽ ã«åæ ãããŸãã
<!-- ããã¹ãå
¥å -->
<input v-model="message" placeholder="edit me" />
<p>Message is: {{ message }}</p>
<!-- ãã§ãã¯ããã¯ã¹ (åäž) -->
<input type="checkbox" id="checkbox" v-model="checked" />
<label for="checkbox">{{ checked }}</label>
<!-- ãã§ãã¯ããã¯ã¹ (è€æ°ãé
åã«ãã€ã³ã) -->
<input type="checkbox" id="jack" value="Jack" v-model="checkedNames">
<label for="jack">Jack</label>
<input type="checkbox" id="john" value="John" v-model="checkedNames">
<label for="john">John</label>
<p>Checked names: {{ checkedNames }}</p>
<!-- ã©ãžãªãã¿ã³ -->
<input type="radio" id="one" value="One" v-model="picked">
<label for="one">One</label>
<input type="radio" id="two" value="Two" v-model="picked">
<label for="two">Two</label>
<p>Picked: {{ picked }}</p>
<!-- ã»ã¬ã¯ãããã¯ã¹ -->
<select v-model="selected">
<option disabled value="">Please select one</option>
<option>A</option>
<option>B</option>
</select>
<p>Selected: {{ selected }}</p>
// script setup å
ã®äŸ
import { ref } from 'vue';
const message = ref('');
const checked = ref(false);
const checkedNames = ref([]); // è€æ°ã®ãã§ãã¯ããã¯ã¹çš
const picked = ref(''); // ã©ãžãªãã¿ã³çš
const selected = ref(''); // ã»ã¬ã¯ãããã¯ã¹çš
v-model
ã«ã¯ã.lazy
, .number
, .trim
ãšãã£ã修食åããããå
¥åã®æåã調æŽã§ããŸãã
ã³ã³ããŒãã³ãã®åºç€ (Component Basics)
ã³ã³ããŒãã³ãã¯Vueã®æã匷åãªæ©èœã®äžã€ã§ããUIãç¬ç«ããåå©çšå¯èœãªéšåã«åå²ããããšãã§ããŸããåäžãã¡ã€ã«ã³ã³ããŒãã³ãïŒSFCïŒã§ã¯ãéåžž.vue
ãšããæ¡åŒµåã®ãã¡ã€ã«ã«ã³ã³ããŒãã³ãã®ãã³ãã¬ãŒãïŒHTMLïŒãã¹ã¯ãªããïŒJavaScriptïŒãã¹ã¿ã€ã«ïŒCSSïŒããŸãšããŠèšè¿°ããŸãã
ãããã㣠(Props): 芪ã³ã³ããŒãã³ãããåã³ã³ããŒãã³ããžããŒã¿ãæž¡ãããã®ã«ã¹ã¿ã å±æ§ã§ããåã¯defineProps
ã䜿ã£ãŠåãåãããããã£ã宣èšããŸãã
ã€ãã³ã (Events): åã³ã³ããŒãã³ããã芪ã³ã³ããŒãã³ããžéä¿¡ïŒéç¥ïŒããããã®ä»çµã¿ã§ããåã¯defineEmits
ã䜿ã£ãŠçºè¡ããã€ãã³ãã宣èšããemit
é¢æ°ã§ã€ãã³ããçºè¡ããŸãã芪ã¯v-on
ïŒãŸãã¯@
ïŒã䜿ã£ãŠåã®ã€ãã³ãã賌èªããŸãã
以äžã¯ç°¡åãªäŸã§ãã
ChildComponent.vue
(åã³ã³ããŒãã³ã):
<script setup>
import { defineProps, defineEmits } from 'vue';
// 芪ããåãåãããããã£ã宣èš
const props = defineProps({
message: String,
count: Number
});
// 芪ã«çºè¡ããã€ãã³ãã宣èš
const emit = defineEmits(['increment-count']);
function handleClick() {
// 'increment-count' ã€ãã³ããçºè¡ããæ°ããã«ãŠã³ãå€ãæž¡ã
emit('increment-count', props.count + 1);
}
</script>
<template>
<div class="box">
<h4>Child Component</h4>
<p>Message from parent: {{ message }}</p>
<p>Current count: {{ count }}</p>
<button class="button is-primary" @click="handleClick">
Increment Count (from child)
</button>
</div>
</template>
<style scoped>
.box {
border: 1px solid #ccc;
padding: 1rem;
margin-top: 1rem;
}
</style>
ParentComponent.vue
(芪ã³ã³ããŒãã³ã):
<script setup>
import { ref } from 'vue';
import ChildComponent from './ChildComponent.vue';
const parentMessage = ref('Hello from Parent!');
const parentCount = ref(0);
// åã³ã³ããŒãã³ããçºè¡ãã 'increment-count' ã€ãã³ãããã³ãã«ããã¡ãœãã
function handleIncrement(newCount) {
parentCount.value = newCount;
}
</script>
<template>
<div>
<h3 class="title is-3">Parent Component</h3>
<p>Parent count: {{ parentCount }}</p>
<!-- åã³ã³ããŒãã³ããäœ¿çš -->
<ChildComponent
:message="parentMessage" <!-- ããããã£(message)ãåã«æž¡ã -->
:count="parentCount" <!-- ããããã£(count)ãåã«æž¡ã -->
@increment-count="handleIncrement" <!-- åã®ã€ãã³ã(increment-count)ãè³Œèª -->
/>
</div>
</template>
ãã®ããã«ã³ã³ããŒãã³ããçµã¿åãããããšã§ãè€éãªUIã管çããããæ§ç¯ã§ããŸãã
4. Vue 3 ã®ãã€ã©ã€ã âš: Composition API
Vue 3ã§æã泚ç®ãã¹ãæ°æ©èœã®äžã€ãComposition APIã§ããããã¯ãåŸæ¥ã®Options APIïŒdata
, methods
, computed
ãªã©ã®ãªãã·ã§ã³ã§ã³ã³ããŒãã³ããæ§æããã¹ã¿ã€ã«ïŒã«ä»£ãããæ°ããã³ã³ããŒãã³ãã®ããžãã¯æ§ææ¹æ³ãæäŸããŸãã
Composition APIã®äž»ãªå©ç¹:
- ããè¯ãããžãã¯ã®åå©çš: é¢é£ããããžãã¯ïŒç¶æ ãã¡ãœããããŠã©ããã£ãŒãªã©ïŒããã³ã³ããŒã¶ãã«é¢æ°ããšããŠæœåºããè€æ°ã®ã³ã³ããŒãã³ãéã§ç°¡åã«åå©çšã§ããŸããããã¯ãåŸæ¥ã®ããã¯ã¹ã€ã³ãæ±ããŠããåé¡ã解決ããŸãã (VueUseã®ãããªã©ã€ãã©ãªã¯ããã®åã瀺ããŠããŸãã)
- ããæè»ãªã³ãŒãæ§æ: Options APIã§ã¯ãé¢é£ããããžãã¯ãè€æ°ã®ãªãã·ã§ã³ã«åæ£ããã¡ã§ããããComposition APIã§ã¯é¢å¿äºïŒæ©èœïŒããšã«ã³ãŒãããŸãšããããšãã§ããŸããããã«ãããç¹ã«å€§èŠæš¡ã§è€éãªã³ã³ããŒãã³ãã®å¯èªæ§ãšä¿å®æ§ãåäžããŸãã
- ããè¯ãåæšè«: Composition APIã¯äž»ã«ãã¬ãŒã³ãªå€æ°ãšé¢æ°ã§æ§æããããããTypeScriptãšã®çžæ§ãéåžžã«è¯ãã§ããåæšè«ãèªç¶ã«æ©èœããåå®å šãªã³ãŒããæžãããããªããŸããVue 3èªäœãTypeScriptã§æžãããŠããŸãã
-
ããå°ããæ¬çªãã³ãã«ãšå°ãªããªãŒããŒããã:
Composition APIã®ã³ãŒãã¯ãOptions APIã«æ¯ã¹ãŠãããå¹ççã«ãããã¡ã€ïŒå§çž®ïŒã§ããŸãããŸãã
<script setup>
æ§æã䜿çšãããšãã³ã³ãã€ã«æã«ããæé©åãããã©ã³ã¿ã€ã ã®ããã©ãŒãã³ã¹ãåäžããŸãã
Composition API ã¯ãsetup()
ãªãã·ã§ã³å
ããŸãã¯ããç°¡æœãª<script setup>
æ§æå
ã§äœ¿çšãããŸããåè¿°ã®ãªã¢ã¯ãã£ããã£ã®åºç€ïŒref
, reactive
ïŒãç®åºããããã£ïŒcomputed
ïŒããŠã©ããã£ãŒïŒwatch
ïŒãªã©ã¯ãã¹ãŠComposition APIã®äžéšã§ãã
<script setup>
// ãªã¢ã¯ãã£ããã£é¢æ°ãã©ã€ããµã€ã¯ã«ããã¯ãªã©ãã€ã³ããŒã
import { ref, onMounted } from 'vue';
// ãªã¢ã¯ãã£ããªç¶æ
const count = ref(0);
// ç¶æ
ãå€æŽããé¢æ°
function increment() {
count.value++;
}
// ã©ã€ããµã€ã¯ã«ããã¯
onMounted(() => {
console.log(`The initial count is ${count.value}.`);
});
// setup ã¹ã³ãŒãå
ã§å®£èšãããå€æ°ãé¢æ°ã¯ããã³ãã¬ãŒãã§çŽæ¥å©çšå¯èœ
</script>
<template>
<button @click="increment">Count is: {{ count }}</button>
</template>
Vue 3ã§ã¯Composition APIãæšå¥šãããŠããŸãããåŸæ¥ã®Options APIãåŒãç¶ãå®å šã«ãµããŒããããŠãããäž¡æ¹ãæ··åšãããããšãå¯èœã§ãããããžã§ã¯ãã®èŠæš¡ãããŒã ã®å¥œã¿ã«å¿ããŠéžæã§ããŸãã
5. Vue ãšã³ã·ã¹ãã ð³
Vue.jsã®ã³ã¢ã©ã€ãã©ãªã¯UIã¬ã³ããªã³ã°ã«çŠç¹ãåœãŠãŠããŸãããå®å šãªã¢ããªã±ãŒã·ã§ã³ãæ§ç¯ããã«ã¯ãå€ãã®å Žåãè¿œå ã®ããŒã«ãå¿ èŠã§ããVueã«ã¯ãå ¬åŒã«ãµããŒããããŠãã匷åãªã©ã€ãã©ãªãããŒã«çŸ€ïŒãšã³ã·ã¹ãã ïŒããããŸãã
Vue Router
Vue Router ã¯ãVue.jsã®å ¬åŒã«ãŒãã£ã³ã°ã©ã€ãã©ãªã§ããã·ã³ã°ã«ããŒãžã¢ããªã±ãŒã·ã§ã³ïŒSPAïŒã«ãããŠãURLãšã³ã³ããŒãã³ãã®ãããã³ã°ã管çããããŒãžé·ç§»ãå®çŸããŸãã
- URLã«å¿ããã³ã³ããŒãã³ãã®è¡šç€ºåãæ¿ã
- ãã¹ããããã«ãŒã/ãã¥ãŒ
- åçãªã«ãŒããããã³ã°ïŒäŸ:
/users/:id
ïŒ - ã«ãŒããã©ã¡ãŒã¿ãã¯ãšãªãããã·ã¥ã®åŠç
- ã³ã³ããŒãã³ãå ããã²ãŒã·ã§ã³ã¬ãŒãïŒé·ç§»ååŸã®åŠçïŒ
- ãã©ã³ãžã·ã§ã³ãšãã§ã¯ã
- é 延èªã¿èŸŒã¿ïŒLazy LoadingïŒã«ããããã©ãŒãã³ã¹æé©å
Vue Routerã䜿ãããšã§ããŠãŒã¶ãŒäœéšãæãªãããšãªããè€æ°ã®ãããŒãžããæã€è€éãªã¢ããªã±ãŒã·ã§ã³ãæ§ç¯ã§ããŸãã
Pinia (ç¶æ 管ç)
Pinia (ããã¢) ã¯ãVue.jsã®å ¬åŒãªç¶æ 管çã©ã€ãã©ãªã§ãïŒVue 3以éãåŸæ¥ã®Vuexã«ä»£ããæšå¥šã©ã€ãã©ãªãšãªããŸããïŒãã¢ããªã±ãŒã·ã§ã³å šäœã§å ±æãããç¶æ ïŒããŒã¿ïŒãäžå 管çããããã®ä»çµã¿ãæäŸããŸãã
ã³ã³ããŒãã³ãã®éå±€ãæ·±ããªããšãããããã£ïŒPropsïŒãã€ãã³ãïŒEventsïŒã ãã§ã®ç¶æ ã®åãæž¡ãïŒãã±ããªã¬ãŒïŒã¯è€éã«ãªããã¡ã§ããPiniaã¯ãã¹ãã¢ããšããã°ããŒãã«ãªç¶æ ã³ã³ãããæäŸããã©ã®ã³ã³ããŒãã³ãããã§ãç¶æ ã«ã¢ã¯ã»ã¹ããããç¶æ ãå€æŽïŒãã¥ãŒããŒã·ã§ã³ïŒãããã§ããããã«ããŸãã
- äžå€®éæš©çãªç¶æ 管ç
- ç¶æ ïŒStateïŒãã²ãã¿ãŒïŒGettersãç®åºããããã£ã®ãããªãã®ïŒãã¢ã¯ã·ã§ã³ïŒActionsãç¶æ ãå€æŽããã¡ãœããïŒã§æ§æãããã¹ãã¢
- TypeScriptã®å®å šãµããŒããšåªããåæšè«
- ã¢ãžã¥ãŒã«æ§ãé«ããã¹ãã¢ãåå²ããŠç®¡çãããã
- Vue DevToolsãšã®é£æºã«ãããããã°ã®å®¹æã
- ãµãŒããŒãµã€ãã¬ã³ããªã³ã°ïŒSSRïŒã®ãµããŒã
Piniaã¯éåžžã«è»œéã§ãComposition APIãšãèªç¶ã«é£æºããçŽæçã§äœ¿ããããAPIãæäŸããŸãã
// ã¹ãã¢ã®å®çŸ©äŸ (stores/counter.js)
import { defineStore } from 'pinia';
import { ref, computed } from 'vue';
export const useCounterStore = defineStore('counter', () => {
// State
const count = ref(0);
// Getters
const doubleCount = computed(() => count.value * 2);
// Actions
function increment() {
count.value++;
}
function decrement() {
count.value--;
}
return { count, doubleCount, increment, decrement };
});
<!-- ã³ã³ããŒãã³ãã§ã®äœ¿çšäŸ -->
<script setup>
import { useCounterStore } from '@/stores/counter';
const counter = useCounterStore();
</script>
<template>
<div>
<p>Count: {{ counter.count }}</p>
<p>Double Count: {{ counter.doubleCount }}</p>
<button @click="counter.increment">Increment</button>
<button @click="counter.decrement">Decrement</button>
</div>
</template>
Vue DevTools
Vue DevTools ã¯ãVueã¢ããªã±ãŒã·ã§ã³ããããã°ããã³æ€æ»ããããã®ãã©ãŠã¶æ¡åŒµæ©èœïŒChrome, Firefox, Edgeã§å©çšå¯èœïŒã§ããéçºæã«ã¯å¿ é ãšãèšããããŒã«ã§ãã
- ã³ã³ããŒãã³ãéå±€ã®æ€æ»
- ã³ã³ããŒãã³ãã®ç¶æ ïŒããŒã¿ãããããã£ãç®åºããããã£ïŒã®ç¢ºèªãšç·šé
- Vue Routerã®ã«ãŒãæ å ±ã®ç¢ºèª
- Piniaã¹ãã¢ã®ç¶æ ã®ç¢ºèªãšã¿ã€ã ãã©ãã«ãããã°ïŒç¶æ å€æŽå±¥æŽã®è¿œè·¡ïŒ
- ã«ã¹ã¿ã ã€ãã³ãã®è¿œè·¡
- ããã©ãŒãã³ã¹ã®ãããã¡ã€ãªã³ã°
Vue DevToolsã䜿ãããšã§ãã¢ããªã±ãŒã·ã§ã³å éšã§äœãèµ·ãã£ãŠããããèŠèŠçã«ç解ããåé¡ã®ç¹å®ãšè§£æ±ºãè¿ éã«è¡ãããšãã§ããŸãã
ãã®ä»ã®ããŒã«ãšã©ã€ãã©ãª
- Vite: é«éãªããã³ããšã³ããã«ãããŒã«ã§ãããéçºãµãŒããŒãVue 3ãããžã§ã¯ãã®æšæºçãªãã«ãã»ããã¢ããã
- Nuxt: Vue.jsãããŒã¹ãšããé«ã¬ãã«ãã¬ãŒã ã¯ãŒã¯ããµãŒããŒãµã€ãã¬ã³ããªã³ã°ïŒSSRïŒãéçãµã€ãçæïŒSSGïŒããã¡ã€ã«ããŒã¹ã«ãŒãã£ã³ã°ãªã©ãããå€ãã®æ©èœãæäŸã
- VueUse: Composition APIã掻çšãã䟿å©ãªã³ã³ããŒã¶ãã«é¢æ°ïŒåå©çšå¯èœãªããžãã¯ïŒã®ã³ã¬ã¯ã·ã§ã³ã
- UI ãã¬ãŒã ã¯ãŒã¯: Vuetify, Quasar Framework, Element Plus, Naive UI ãªã©ãVueãšçµã¿åãããŠäœ¿ããè±å¯ãªUIã³ã³ããŒãã³ãã©ã€ãã©ãªãååšããŸãã
6. ãŸãšãïŒãªã Vue.js ãéžã¶ã®ãïŒ ð
Vue.jsã¯ãã¢ãã³ãªWebããã³ããšã³ãéçºã«ãããŠéåžžã«é åçãªéžæè¢ã§ãã
- åŠç¿ãããã: ã·ã³ãã«ãªAPIãšåªããããã¥ã¡ã³ãã«ãããåå¿è ã§ãæ¯èŒççæéã§ç¿åŸã§ããŸãã
- æè»æ§ãšæ¡åŒµæ§: ã³ã¢ã¯è»œéã§ãããªãããå¿ èŠã«å¿ããŠå ¬åŒã©ã€ãã©ãªããµãŒãããŒãã£è£œããŒã«ãçµã¿åãããŠæ©èœãæ¡åŒµã§ããŸããå°èŠæš¡ãã倧èŠæš¡ãªã¢ããªã±ãŒã·ã§ã³ãŸã§å¯Ÿå¿å¯èœã§ãã
- é«ãããã©ãŒãã³ã¹: ä»®æ³DOMãšã³ã³ãã€ã«æã®æé©åã«ãããé«éãªã¢ããªã±ãŒã·ã§ã³ãå®çŸããŸãã
- éçºäœéšã®è¯ã: Composition APIãåäžãã¡ã€ã«ã³ã³ããŒãã³ããé«éãªãã«ãããŒã«ïŒViteïŒã䟿å©ãªéçºããŒã«ïŒVue DevToolsïŒãªã©ããå¿«é©ãªéçºäœéšãæäŸããŸãã
- 掻çºãªã³ãã¥ããã£: äžçäžã«å€ãã®éçºè ããããæ å ±äº€æããµããŒãã掻çºã«è¡ãããŠããŸãã
ãã¡ãããReactãAngularãšãã£ãä»ã®ãã¬ãŒã ã¯ãŒã¯ã«ãããããåªããç¹ããããŸãããVue.jsã¯ç¹ã«åŠç¿ã®å®¹æããæè»æ§ãéçºäœéšã®ãã©ã³ã¹ã«åªããŠãããšèšããã§ãããã
ãã®å ¥éã¬ã€ãããããªãã®Vue.jsåŠç¿ã®ç¬¬äžæ©ãšãªãã°å¹žãã§ãããã²å ¬åŒããã¥ã¡ã³ããèªã¿é²ããå®éã«ã³ãŒããæžããŠãVue.jsã®äžçãæ¢æ±ããŠã¿ãŠãã ããïŒð
ã³ã¡ã³ã