【Vue】ウォッチャー（watch）を使ったバリデーションとボタンの非活性

## はじめに
[Vueチュートリアル](https://ja.vuejs.org/tutorial/#step-10)で学んだwatchを実際の開発でさわる機会があり、理解を深めるために機能を自分で作ってみました。

## ウォッチャー(watch)とは？
特定のデータを監視し、変更が発生するたびに処理を自動的に実行するためのオプションです。

### watchの書き方（例）
今回は[CompositionAPI](https://ja.vuejs.org/api/composition-api-setup.html#composition-api-setup)の書き方で説明します。
```vuejs
watch(監視するデータ, (変更後の値) => {
// データが変更されるたびに実行する処理を書く
    console.log(newVal);
});
```

監視するデータを第1引数として、refのリアクティブな値などを指定できます。
変更後の値（もしくは値が格納された変数）を第2引数として、変更が発生した場合に実行する関数を定義します。

## 実装例
[```ref```](https://qiita.com/k12da/items/b596514c36bf9ff542a2)や[```v-bind```](https://qiita.com/k12da/items/6cf923edb38ca7f9c9bd)などの前提知識については、前回の投稿をご覧ください🙏
### フォーム入力のバリデーション
```vuejs
<template>
  <div>
    <label class="label">名前</label><br>
    <input v-model="name" placeholder="名前を入力してね" /><br>
    <p v-show="error" :class="{ error }">{{ error }}</p><br>
    <button class="button" :disabled="error">更新</button>
  </div>
</template>

<script setup>
import { ref, watch } from 'vue';

const name = ref('');
const error = ref(null);

watch(name, (newName) => {
  if (newName.length <= 10) {
    error.value = null;
  } else {
    error.value = "10文字以内で入力してね";
  }
});
</script>

<style scoped>
  label {
    font-size: 0.9rem;
  }
  
  input {
    padding: 5px; 
    font-size:1rem;
  }
  
  button {
    border: none;
    border-radius: 5px;
    background-color: #1e90ff;
    color: #ffffff;
    font-size: 0.9rem;
    cursor: pointer;
  }
  button:disabled {
    opacity: 0.5;
    cursor: not-allowed
  }
  
  .error {
    font-size: 1rem;
    color: red;
  }
</style>
```

#### 仕様
- 名前のフィールドに11文字以上入力されたら、エラーメッセージを表示する
- エラーメッセージが表示された時は、ボタンを無効にする（cssの擬似クラス[```:disabled```](https://developer.mozilla.org/ja/docs/Web/CSS/:disabled)）を使用しています

#### デザイン
今回はデータ送信前のバリデーションとボタンの非活性を実装しています。

**（エラー表示なし）**
![スクリーンショット 2024-07-21 17.26.09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/677000/e8ddd4b6-9e4c-0bd6-224e-83fbca2e9481.png)

**（エラー表示あり）**
![スクリーンショット 2024-07-21 17.27.04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/677000/354b8c8c-41b1-6a68-6acd-375e619dc087.png)

#### 実際の動作
![watch.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/677000/472b0644-a825-bf88-3a67-1c8d37e3a6a3.gif)

## ユーザービリティの観点
### ボタン無効の時はグレーアウトしないほうが良い？？
>多くのデザイナーはこの無効状態をユーザーに伝える方法として、ボタンをグレーアウトにします。ただし、この方法ではボタンの有効状態が無効状態に似ていないため、ユーザーは同様に驚くことになります。

>無効状態のボタンが透明な場合、ユーザーは有効状態のボタンの外観を確認できます。ボタンはフェードアウトされていますが、ユーザーが認識できるように一部のカラーは透けて見えます。そのため、無効状態のボタンが有効状態に移行しても、その外観にユーザーが不意をつかれることはありません。

>さらに、透明なボタンは背景に溶け込みますが、グレーのボタンは前景に残ります（背景がグレーでない場合）。前景要素は、ユーザーにとってより目立ちやすいものです。ユーザーはボタンを操作するものとして認識する傾向があり、ボタンがグレーアウトされた無効状態でも操作してしまう可能性を示唆します。

（記事「[UXデザイナーから学ぶ、無効状態のボタンをグレーアウトにしない理由](https://coliss.com/articles/build-websites/operation/work/why-you-shouldnt-gray-out-disabled-buttons.html#google_vignette)」より抜粋）

### 自分なりの解釈
つまり一般的には、
- 透明なボタンは無効な状態
- 色付きで目立つボタンは有効な状態
として認識されることが多いため、グレーアウトされていても操作が可能なボタンとして誤認される可能性がある。


## まとめ
vueにおけるwatchオプションは、データを監視して変更が発生するたびに処理を実行してくれる。
実際に自分で考えて実装してみて、ユーザービリティの勉強にもなりました。


## 参考記事
- [ウォッチャー(Vue.jsチュートリアル)](https://ja.vuejs.org/tutorial/#step-10)
- [ウォッチャー(Vue.js公式ドキュメント)](https://ja.vuejs.org/guide/essentials/watchers)
- [:disabled（MDN）](https://developer.mozilla.org/ja/docs/Web/CSS/:disabled)
- [UXデザイナーから学ぶ、無効状態のボタンをグレーアウトにしない理由](https://coliss.com/articles/build-websites/operation/work/why-you-shouldnt-gray-out-disabled-buttons.html#google_vignette)