6. Event Handling
クラス https://www.vuemastery.com/courses/intro-to-vue-3/event-handling-vue3
VS Codeから該当フォルダを選択して、開きます。その後に、配下のgit部分をクリックして、ブランチをL6-startへ入れ替えてください。
ブランチ切り替え方法 https://qiita.com/phjg81/items/e6695eb2334d9297a318
今日のポイントはデータオブジェクトをイベントにより、変更されることです。
const app = Vue.createApp({
data() {
return {
cart:0,
product: 'Socks',
image: './assets/images/socks_blue.jpg',
inStock: true,
details: ['50% cotton', '30% wool', '20% polyester'],
variants: [
{ id: 2234, color: 'green', image: './assets/images/socks_green.jpg' },
{ id: 2235, color: 'blue', image: './assets/images/socks_blue.jpg' },
]
}
}
})
<div id="app">
<div class="nav-bar"></div>
<div class="cart">Cart({{ cart }})</div>
<div class="product-display">
<div class="product-container">
<div class="product-image">
<img v-bind:src="image">
</div>
<div class="product-info">
<h1>{{ product }}</h1>
<p v-if="inStock">In Stock</p>
<p v-else>Out of Stock</p>
<ul>
<li v-for="detail in details">{{ detail }}</li>
</ul>
<div v-for="variant in variants" :key="variant.id">{{ variant.color }}</div>
<button class="button">Add to Cart</button>
</div>
</div>
</div>
</div>
イベントに対する動作を実装するには、下記のようにdataと同レベルにてmethodsを追加して、その配下に実装したい関数を追記します。
const app = Vue.createApp({
data() {
return {
cart:0,
product: 'Socks',
image: './assets/images/socks_blue.jpg',
inStock: true,
details: ['50% cotton', '30% wool', '20% polyester'],
variants: [
{ id: 2234, color: 'green', image: './assets/images/socks_green.jpg' },
{ id: 2235, color: 'blue', image: './assets/images/socks_blue.jpg' },
]
}
},
methods: {
// method
methodName() {
// method context
}
}
})
その後に追加した部分にv-onを使って欲しいイベントを追加して見ます。
<button class="button" v-on:click="methodName">Add to Cart</button>
v-on:clickは@clickに諸略可能です。
<button class="button" @click="methodName">Add to Cart</button>
付けられるイベントは下記の内容を参照してください。
ボタンをクリックしたら、cartへ追加する仕組みを実装して見ましょう。
const app = Vue.createApp({
data() {
return {
cart:0,
...
}
},
methods: {
addToCart() {
this.cart += 1
}
}
})
<button class="button" @click="addToCart">Add to Cart</button>
mouse overイベントも追加して見ます。
data() {
return {
...
image: './assets/images/socks_blue.jpg',
...
variants: [
{ id: 2234, color: 'green', image: './assets/images/socks_green.jpg' },
{ id: 2235, color: 'blue', image: './assets/images/socks_blue.jpg' },
]
}
},
methods: {
addToCart() {
this.cart += 1
},
updateImage(variantImage) {
this.image = variantImage
}
}
<div class="product-image">
<img v-bind:src="image">
</div>
...
<div v-for="variant in variants" :key="variant.id" @mouseover="updateImage(variant.image)">{{ variant.color }}</div>
今回の課題はカートから商品を取り出すボタンを追加して見たください。
課題確認
const app = Vue.createApp({
data() {
return {
cart:0,
product: 'Socks',
image: './assets/images/socks_blue.jpg',
inStock: true,
details: ['50% cotton', '30% wool', '20% polyester'],
variants: [
{ id: 2234, color: 'green', image: './assets/images/socks_green.jpg' },
{ id: 2235, color: 'blue', image: './assets/images/socks_blue.jpg' },
]
}
},
methods: {
addToCart() {
this.cart += 1
},
// solution
removeFromCart() {
if (this.cart >= 1) {
this.cart -= 1
}
},
updateImage(variantImage) {
this.image = variantImage
}
}
})
<div id="app">
<div class="nav-bar"></div>
<div class="cart">Cart({{ cart }})</div>
<div class="product-display">
<div class="product-container">
<div class="product-image">
<img v-bind:src="image">
</div>
<div class="product-info">
<h1>{{ product }}</h1>
<p v-if="inStock">In Stock</p>
<p v-else>Out of Stock</p>
<ul>
<li v-for="detail in details">{{ detail }}</li>
</ul>
<div v-for="variant in variants" :key="variant.id" @mouseover="updateImage(variant.image)">{{ variant.color }}</div>
<button class="button" @click="addToCart">Add to Cart</button>
<!-- solution -->
<button class="button" @click="removeFromCart">Remove Item</button>
</div>
</div>
</div>
</div>
パラメータ渡し
上記のように、関数へパラメータを追加しなくても、eventは関数へ引き渡され、使えます。
<button class="button" @click="addToCart">Add to Cart</button>
const app = Vue.createApp({
data() {
return {
...
}
},
methods: {
addToCart(event) {
if (event) {
alert(event.target.tagName)
}
this.cart += 1
},
...
}
})
変数とeventを一緒に渡したい場合は、以下のように書けます。
<button class="button" @click="addToCart('addToCart!', $event)">Add to Cart</button>
<button class="button" @click="(event) => addToCart('addToCart!', event)">Add to Cart</button>
const app = Vue.createApp({
data() {
return {
...
}
},
methods: {
addToCart(message, event) {
if (event) {
event.preventDefault()
}
alert(message)
this.cart += 1
},
...
}
})
イベントの修正
<!-- クリックイベントの伝播が停止します -->
<a @click.stop="addToCart"></a>
<!-- 送信イベントはページをリロードしなくなります -->
<form @submit.prevent="onSubmit"></form>
<!-- 修飾子は連鎖できます -->
<a @click.stop.prevent="addToCart"></a>
<!-- 修飾子のみ -->
<form @submit.prevent></form>
<!-- event.targetが自分である場合のみハンドラーをトリガーします -->
<!-- i.e. 子エレメントからではトリガーしません -->
<div @click.self="addToCart">...</div>
<!-- イベントリスナーを追加するときにキャプチャモードを使用する -->
<!-- i.e. 子エレメントを対象とするイベントは、これによって処理される前にここで処理されます -->
<div @click.capture="addToCart">...</div>
<!-- クリックイベントは最大で1回実行されます -->
<a @click.once="addToCart"></a>
<!-- `event.preventDefault()`が含まれている場合 -->
<!-- `onScroll`が完了するのを待つ代わりに -->
<!-- スクロールイベントのデフォルトの動作(スクロール)が発生します -->
<div @scroll.passive="onScroll">...</div>
キーイベント
down => press => up順で発生されます。
<!-- `Enter`キーを押下した時のみ`addToCart`を呼び出します -->
<input @keyup.enter="addToCart" />
<!-- `Enter`キーを押下時のみ`vm.submit()`を呼び出します -->
<input @keydown.enter="addToCart" />
<input @keypress.enter="addToCart" />
イベントの結合
<!-- Alt + Enter -->
<input @keyup.alt.enter="addToCart" />
<!-- Ctrl + Click -->
<div @click.ctrl="addToCart">Ctrl + Click</div>
<!-- これは、システムキー(ctrl、alt、shiftなど)が押されていない場合にのみ起動します -->
<button @keyup.exact="addToCart">システムキー</button>
マウスイベント
<!-- マウス左が押下時にイベントが発生します -->
<button @click.left="addToCart">left</button>
<!-- マウス右が押下時にイベントが発生します -->
<button @click.right="addToCart">right</button>
<!-- マウス中央が押下時にイベントが発生します -->
<button @click.middle="addToCart">middle</button>
vueのイベントハンドリング https://vuejs.org/guide/essentials/event-handling.html#calling-methods-in-inline-handlers
vueのキーハンドリング https://vuejs.org/guide/essentials/event-handling.html#key-modifiers