公式ホームページのIntro to Vue 3クラス6 (Event Handling)

# 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

今日のポイントはデータオブジェクトをイベントにより、変更されることです。

```javascript:main.js
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' },
            ]
        }
    }
})

```

```html:index.html
    <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を追加して、その配下に実装したい関数を追記します。

```javascript:main.js
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を使って欲しいイベントを追加して見ます。

```html:index.html
    <button class="button" v-on:click="methodName">Add to Cart</button>
```

v-on:clickは@clickに諸略可能です。

```html:index.html
    <button class="button" @click="methodName">Add to Cart</button>
```

付けられるイベントは下記の内容を参照してください。
> https://developer.mozilla.org/ja/docs/Web/Events

ボタンをクリックしたら、cartへ追加する仕組みを実装して見ましょう。

```javascript:main.js
const app = Vue.createApp({
    data() {
        return {
            cart:0,
            ...
        }
    },
    methods: {
        addToCart() {
            this.cart += 1
        }
    }
})

```

```html:index.html
    <button class="button" @click="addToCart">Add to Cart</button>
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2516328/bb34428d-8568-98f3-791c-fe97d84432ca.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2516328/ac215646-7301-9fee-6bad-dfe8d613700e.png)

mouse overイベントも追加して見ます。

```javascript:main.js
    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
          }
    }

```

```html:index.html
          <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>
```

今回の課題はカートから商品を取り出すボタンを追加して見たください。

<details>
<summary>課題確認</summary><div>

```javascript:main.js
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
        }
    }
})

```

```html:index.html
    <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>
```
</div>
</details>

## パラメータ渡し

上記のように、関数へパラメータを追加しなくても、eventは関数へ引き渡され、使えます。

```html:index.html
            <button class="button" @click="addToCart">Add to Cart</button>
```

```javascript:main.js
const app = Vue.createApp({
    data() {
        return {
            ...
        }
    },
    methods: {
        addToCart(event) {
            if (event) {
                alert(event.target.tagName)
            }
            this.cart += 1
        },
        ...
    }
})

```

変数とeventを一緒に渡したい場合は、以下のように書けます。

```html:index.html
            <button class="button" @click="addToCart('addToCart!', $event)">Add to Cart</button>
            <button class="button" @click="(event) => addToCart('addToCart!', event)">Add to Cart</button>
```

```javascript:main.js
const app = Vue.createApp({
    data() {
        return {
            ...
        }
    },
    methods: {
        addToCart(message, event) {
            if (event) {
                event.preventDefault()
            }
            alert(message)
            this.cart += 1
        },
        ...
    }
})

```

## イベントの修正

```html:index.html
<!-- クリックイベントの伝播が停止します -->
<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順で発生されます。

```html:index.html
<!-- `Enter`キーを押下した時のみ`addToCart`を呼び出します  -->
<input @keyup.enter="addToCart" />

<!-- `Enter`キーを押下時のみ`vm.submit()`を呼び出します  -->
<input @keydown.enter="addToCart" />

<input @keypress.enter="addToCart" />

```

## イベントの結合

```html:index.html
<!-- Alt + Enter -->
<input @keyup.alt.enter="addToCart" />

<!-- Ctrl + Click -->
<div @click.ctrl="addToCart">Ctrl + Click</div>

<!-- これは、システムキー(ctrl、alt、shiftなど)が押されていない場合にのみ起動します -->
<button @keyup.exact="addToCart">システムキー</button>
```

## マウスイベント

```html:index.html
<!-- マウス左が押下時にイベントが発生します -->
<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