Vue.jsについて

## はじめに

いくつかフロントエンドフレームワークについてまとめて自分用のメモとして残すため記事にしました。  
初歩的なものになるので、初心者さん向けかと思います。

### Vue.js って？

公式の引用は以下です。

> Vue (発音は /vjuː/、view と同様) は、ユーザーインターフェースの構築のための JavaScript フレームワークです。標準的な HTML、CSS、JavaScript を土台とする、コンポーネントベースの宣言的なプログラミングモデルを提供します。シンプルなものから複雑なものまで、ユーザーインターフェースの開発を効率的に支えるフレームワークです。

Vue.js は初学者でも扱いという記載が多いため、SPA の開発をしたことない方で、とりあえず何か触ってみたい場合使ってみるのもの良いかもしれないですね。

# 早速使ってみる

[Reactについて](https://qiita.com/runa_s/items/1d8ab299dec9a56983bf) で作ったシンプルな TODO リストを Vue 版で作ってみたいと思います。

### Vue のセットアップ

#### セットアップ

```bash
npm create vue@latest
```

色々聞かれるので、適当に答える

![スクリーンショット 2024-03-16 23.50.52.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/251276/0c66b809-2def-fdc8-cd84-69d5d982c7de.png)


```bash
cd simple-todo-list/
```

### コンポーネント作成

- App.vue

```html
<template>
  <header>
    <h1>TODO リスト</h1>
  </header>

  <main>
    <div>
      <input type="text" v-model="addText" class="text-input" />
      <button type="button" @click="handleAddButton" :disabled="addText === ''">
        追加
      </button>
    </div>
    <div>
      <TodoList :todoList="todoList" @toggle="handleCheck" />
    </div>
  </main>
</template>

<script setup lang="ts">
  import { ref } from "vue";
  import TodoList from "./components/TodoList.vue";

  type Todo = {
    id: number;
    text: string;
    completed: boolean;
  };

  const todoList = ref<Todo[]>([]);
  const addText = ref<string>("");

  /**
   * 追加ボタンハンドラ
   */
  const handleAddButton = () => {
    const newId =
      todoList.value.length > 0
        ? todoList.value[todoList.value.length - 1].id + 1
        : 1;
    todoList.value.push({
      id: newId,
      text: addText.value,
      completed: false,
    });
    addText.value = "";
  };

  /**
   * チェックボックスハンドラ
   */
  const handleCheck = (id: number) => {
    todoList.value = todoList.value.map((todo) => {
      if (todo.id !== id) {
        return todo;
      }
      return { ...todo, completed: !todo.completed };
    });
  };
</script>

<style scoped>
  .container {
    margin: 10px;
  }

  .text-input {
    margin-right: 10px;
  }
</style>
```

- TodoList.vue

```html
<template>
  <div class="todo-list">
    <template v-for="todo in todoList">
      <TodoItem :todo="todo" @toggle="handleCheckbox" />
    </template>
  </div>
</template>

<script setup lang="ts">
  import TodoItem from "./TodoItem.vue";

  type Todo = {
    id: number;
    text: string;
    completed: boolean;
  };

  const props = defineProps<{
    todoList: Todo[];
  }>();

  const emit = defineEmits<{
    (e: "toggle", id: number): void;
  }>();

  const handleCheckbox = (id: number) => {
    emit("toggle", id);
  };
</script>

<style scoped>
  .todo-list {
    max-width: 500px;
    margin-top: 10px;
    padding: 0 10px;
    box-sizing: border-box;
  }
</style>
```

- TodoItem.vue

```html
<template>
  <div :key="todo.id" className="todo-item">
    <input
      type="checkbox"
      :checked="todo.completed"
      class="check-box"
      @change="handleCheckbox"
    />
    <span :class="todo.completed ? 'text--done' : 'text'">{{ todo.text }}</span>
  </div>
</template>

<script setup lang="ts">
  import { defineProps } from "vue";

  interface Todo {
    id: number;
    text: string;
    completed: boolean;
  }

  const props = defineProps<{
    todo: Todo;
  }>();

  const emit = defineEmits<{
    (e: "toggle", id: number): void;
  }>();
  const handleCheckbox = () => {
    emit("toggle", props.todo.id);
  };
</script>

<style scoped>
  .todo-item {
    display: flex;
    min-height: 20px;
    padding: 5px 0;
    border-bottom: 1px solid #ddd;
  }

  .check-box {
    margin-right: 5px;
  }

  .text--done {
    text-decoration: line-through;
  }
</style>
```

```bash
npm run dev
```

実際に確認するとこんな感じ

![画面収録 2024-03-17 12.43.02.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/251276/d49f48f2-4cd4-e866-cafc-a82ca7b538d7.gif)


以前は Options API を使用して書いていたので、今回は Composition API を使用してみました。 　
そのため`<script setup>`を使用しましたが、初めてこの形で書くので少々手こずりました。。  


#### ちなみに
またReactとの違いですが、ReactはJSXをコンポーネント形式で採用しているのに対し、Vue.jsはSFC（単一ファイルコンポーネント）を採用しています。
HTMLの知識がある場合はVue.jsの方が扱いやすいかと思います。

また、Reactはライブラリとして設計されているのに対して、Vue.jsはフレームワークとして設計されており、状態管理やルーティングが組み込まれた形になっています。補助ライブラリを使用すればこれらの機能を使うことができます。
(Reactはサードパーティライブラリに依存します。）

## まとめ

最近久しぶりに Vue.js を使った案件に入ったので、再勉強がてら調べてみました。
また今回 Composition API を使用してみましたが、あまり慣れていなかったので時間がかかりましたが、通常の javascript に慣れてる身からすると分かりやすいなと感じました。


# 参考
https://ja.vuejs.org/guide/extras/composition-api-faq

https://appmaster.io/ja/blog/vuejstofan-ying