Vue.jsとかいう

## Vue.jsとは
Vue.jsはJavascriptフレームワークで主にユーザーインターフェイス（UI）やシングルページアプリケーション（SPA）の構築に使われる。
{{}}を利用してUIとデータを同期させたりUIをコンポーネントとして管理できたりする
## 環境構築
Node.jsをインストール

https://nodejs.org/ja

Vueプロジェクトの作成
VisualStudioコードのターミナルで以下のように打ちます
```bash
npm create vue@latest
```
なんか選択しが出てきます(以下一例。詳しい情報は別途調べてください)
```bash
✔ Project name: › <プロジェクト名>
✔ Add TypeScript? … No
✔ Add JSX Support? … No
✔ Add Vue Router? … No
✔ Add Pinia for state management? … No
✔ Add Vitest for testing? … No
✔ Add ESLint for code quality? … Yes
✔ Add Prettier for formatting? … Yes
```
作成したプロジェクトへ移動
```bash
cd プロジェクト名
```
依存関係のインストール
```bash
npm install
```
サーバー起動
```bash
npm run dev  //開発者モードみたいな

npm run build
npm run preview
```
ターミナルにローカルサーバーのURLが表示されるので
ブラウザでアクセスすれば開発画面が確認できます。
## ディレクトリ構造
基本的なファイルの構成図
```
プロジェクト
    ├─ .vscode           // VSCodeの設定ファイルの保存場所
    ├─ node_modules      // npmでインストールされたパッケージやライブラリ
    ├─ public            // 公開用の静的ファイル(画像やfavicon等)
    ├─ src               // ソースコードのメインディレクトリ
    │   ├─ app.vue       // Vueのメインコンポーネント
    │   ├─ main.js       // アプリケーションの起動スクリプト
    ├─ .gitattributes    // Gitの動作設定ファイル
    ├─ .gitignore        // Gitコミットに含めないファイルを指定
    ├─ index.html        // ベースとなるHTMLファイル
    ├─ package.json      // プロジェクトの設定や依存関係
    ├─ package-lock.json // バージョン固定のためのファイル
    ├─ .editorconfig     // コードフォーマットの設定
    ├─ .prettierrc.json  // Prettierの設定
    ├─ .eslint.config.js // ESLintの設定
    ├─ README.md         // プロジェクトドキュメント
    ├─ vite.config.js    // Viteの設定
    └─ jsconfig.json     // エディター用JavaScript設定
```
## 内部処理
読むための用語的な...
DOM → ウェブページの構造（HTML・XML）をツリー構造で表現し、プログラムからその構造を操作するためのAPI
仮想DOM → 軽量なオブジェクトで実際のDOMを効率よく操作するための中間表現
### １.テンプレートの解析
Vueコンパイラがテンプレート構文を解析し仮想DOM(Virtual DOM)を生成する。
{{ }}内で宣言された変数や式はJavaScriptコードとして解釈される。
### ２.仮想ＤＯＭの生成
Vueがデータとテンプレートの構造を基にして仮想DOMを作り上げる
### ３.実際のＤＯＭへのマウント
仮想DOMの内容が解析され、ブラウザに表示される実際のHTML要素（DOM）にマウントされる。idやclassはこの時点で設定されブラウザにレンダリングされる。
### ４.リアクティブな更新
データが変更されると、Vueのリアクティブシステムが変更を検知する。
仮想DOMが差分（diff）を計算し、実際のDOMに効率的に適用（更新）される。
### その他
・開発タブのネットワークセクションから処理工程が見られる
→ Vueがどのようにリクエストやデータ処理を実行しているか見ることができる
## テンプレート
### template
Vueコンポーネントのビュー(画面)を定義する部分。
HTMLのような構造を持ちつつ、Vueのディレクティブを使用して動的にデータを操作できる。
### script
Vueコンポーネントのデータ管理やメソッドを記述する部分。(ほぼjavascript)
setupを使用するとコードが簡潔になる。
### style
Vueコンポーネントの見た目を整えるスタイルを定義する部分(ほぼCSS)
scopedを指定すると、このコンポーネントないだけでスタイルが適用される
```vuejs
<template>
    <div>
        <h1>{{ title }}</h1>
    </div>
</template>

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

const title = ref("Vue.js");
</script>

<style scoped>
h1{
    color: white;
}
</style>
```
・ {{}}の中でのみjavascriptの式が使える・javascript内での変数や参考演算子も使用可能
→ 使える変数はトップレベルで宣言する必要がある。1行で完結するもののみ使える
## リアクティブ（ref,reactive）
**リアクティブとは➔データが変化すると自動的にUIが更新される仕組みのこと**
・**ref**や**reactive**を使用してリアクティブデータを作成。
・リアクティブデータが更新されると自動的にUI側も更新される。
・データアクセス時には変数名.valueでアクセス（テンプレート内ではvalueを省略可能）
・階層的にリアクティブデータになる（親オブジェクトがリアクティブの場合子プロパティもリアクティブになる）➔ 子オブジェクトだけがリアクティブの場合は明示的にvalueを付けなければいけない
```vuejs
<script setup>
import { ref } from 'vue';
import { reactive } from 'vue';

// リアクティブな値を定義
const count = ref(0);
//オブジェクトをリアクティブ化
const user = reactive({ name: 'Simakixi', age: 3 });

// インクリメント関数
const increment = () => {
  count.value++;
};
</script>
<template>
  <div>
    <p>ユーザー名: {{ user.name }}</p>
    <p>年齢: {{ user.age }}</p>
    <p>現在のカウント: {{ count }}</p>
    <button @click="increment">カウントアップ</button>
  </div>
</template>
```
## ディレクティブ
ディレクティブとはテンプレート内で特定の動作や機能を実現するための特別なマークアップ。Vueのリアクティブシステムと連携して動的な挙動を構築する。
### ディレクティブの形
v-on:click.prevent="changeData"
左から名前(v-on:),引数(click),装飾子(.prevent),値("changeData")
動的に[]を利用して引数は利用可能
```vuejs
<template>
  <button @[eventType].prevent="changeData">クリック</button>
</template>

<script setup>
const eventType = 'click';

const changeData = () => {
  console.log('データが変更されました！');
};
</script>
```
### v-html
指定したHTMLをそのまま挿入するディレクティブ
ただしXSS攻撃のリスクがあるため内部からのデータのみを使用すること
```vuejs
<template>
  <div v-html="html"></div>
</template>

<script setup>
    const html = '<p>これはHTMLから挿入された文字列です。</p>';
</script>
```
### v-bind
動的にHTML要素の属性をバインドする。省略系で【：属性】でも書ける。
・変数名と同じ場合は【=値】を省略可能
・null/undefinedも利用可能
・1つのタグに複数属性を１度に指定可能
```vuejs
<script setup>
const UserId = 'user-id';
const StyleClass = 'highlight';
const nullvalue = null; // ここでは値を未指定
//複数属性の動的指定
const link = {
  href: 'https://example.com',
  target: '_blank',
  rel: 'noopener noreferrer',
};
</script>

<template>
  <!-- 動的にidとclassをバインド -->
  <div :id="UserId" :class="StyleClass"></div>

  <!-- 変数名と同じなら省略可能 -->
  <button :disabled>クリック不可</button>

  <!-- nullやundefinedの取り扱い -->
  <input :value="nullvalue" placeholder="値がなくてもエラーにならない">

  <a v-bind="link">リンクはこちら</a>
</template>
```
### v-on
イベントリスナーを動的に設定するためのディレクティブ
・v-on:を@に省略可能
・イベントハイドラも利用可能
・preventDefault(ブラウザのデフォルト操作を防ぐ)を省略可能
・stopPropagation(親要素のイベントを引き継がない)を省略可能
```vuejs
<script setup>
const handleClick = () => {
  console.log('ボタンがクリックされました！');
};

const handleSubmit = () => {
  console.log('フォームが送信されました！');
};

const handleInput = (event) => {
  console.log('入力値:', event.target.value);
};

const Submit = () => {
  console.log("フォーム送信を防ぎました！");
};

const handleParentClick = () => {
  console.log("親要素がクリックされました！");
};

const handleChildClick = () => {
  console.log("子要素がクリックされました！");
};
</script>

<template>
  <button @click="handleClick">クリック</button>
  <form @submit.prevent="handleSubmit">
    <input @input="handleInput($event)" placeholder="文字を入力">
  </form>
  <form @submit.prevent="Submit">
    <input type="text" placeholder="名前を入力してください" />
    <button type="submit">送信</button>
  </form>
  <div @click="handleParentClick">親要素
    <button @click.stop="handleChildClick">子要素（クリックしても親へは伝わらない）</button>
  </div>
</template>
```
### v-model
双方向バインディングを実現するためのディレクティブ
フォーム入力値とJavascriptのデータがリアルタイムで同期する
```vuejs
<script setup>
import { ref } from 'vue';

// リアクティブな変数を作成（空）
const userInput = ref('');
</script>

<template>
  <div>
    <input v-model="userInput" placeholder="ここに入力してください" />
    <p>あなたが入力した内容: {{ userInput }}</p>
  </div>
</template>
```
## 監視メカニズム
### computed
リアクティブデータ処理を効率的にする仕組み
・内部で利用されるリアクティブなオブジェクトを常に監視し、変更が発生した場合のみ結果を更新する
・非同期型の処理やトップレベルでの変数の値の変更は不可（副作用の防止）
```vuejs
<script setup>
import { ref } from 'vue';
import { computed } from 'vue';

// リアクティブデータの定義
const firstName = ref('');
const lastName = ref('');

// 変更があった場合のみfullNameに新しい名前を代入する
const fullName = computed(() => `${firstName.value} ${lastName.value}`);
</script>

<template>
  <div>
    <p>フルネーム: {{ fullName }}</p>
    <input v-model="firstName" placeholder="名を入力してください" />
    <input v-model="lastName" placeholder="姓を入力してください" />
  </div>
</template>
```
### Watch
リアクティブなデータの変化を監視する仕組み
特定の値やプロパティが変わった際に指定した処理を実行する。
明示的に監視対象を指定したい場合に使用（特定のデータや、監視対象が限定的である場合に適する）
・第一引数に監視したいリアクティブデータ（関数や配列も利用可能）を取る
・第二引数にデータが変化した時に実行されるコールバック関数を書く
・リアクティブオブジェクトを監視する場合アロー関数を用いる
・第一引数を空白にしたり第三引数にimmediateを設定するとWatchEffectのように動作する。
```vuejs
<script>
import { ref, watch } from 'vue';

const data = ref(0)
//newValueには最新のデータが入りoldValueには古い値が入る(記入しなくても良い)
watch(data,(newValue,oldValue)=>{
    //dataに変更が加えられた際に実行される
})

const user = reactive({ name: 'simakixi', age: 3 });

// アロー関数でプロパティを指定
watch(() => user.name, (newValue, oldValue) => {
  console.log(`名前が変更されました: ${oldValue} → ${newValue}`);
});

watch(
  data,
  (newValue) => {
    console.log(`値: ${newValue}`);
  },
  { immediate: true } // 初回実行を有効化
);
</script>
```
### WatchEffect
リアクティブなデータを監視して動的な処理を行うための仕組み。
アクセスされるリアクティブなデータを検出しそれが変更された場合に処理を実行する
### computedとの違い
|特徴| WatchEffect | computed |
|:-:|:-:|:-:|
| 監視対象 | 自動的に検出 | 明示的に依存するデータを設定 |
| 実行タイミング | 即時実行 + データ変更時 | データ変更時 |
| 用途 | 動的な監視処理や副作用の追加 | 読み取り専用の計算結果を生成する |
```vuejs
<script>
import { ref, watchEffect } from 'vue';

const count = ref(0);

// リアクティブなデータを自動的に検出して処理を実行
watchEffect(() => {
  console.log(`カウント: ${count.value}`);
});

count.value++; // countが変更されるとログ出力が実行される
</script>
```
## class属性に対する設定
・オブジェクトを書きtrue/falseで書きクラス適用を制御
・関数・配列でも可能
・静的なクラスも同時に利用可能
・スタイル属性でも可能
```Vue.js
<script setup>
import { ref } from 'vue';

// リアクティブなデータ定義
const isActive = ref(true);
const isBold = ref(false);
</script>

<template>
  <div>
    <!-- オブジェクトでのクラス制御 -->
    <div :class="{ active: isActive, 'text-bold': isBold }">
      オブジェクトでのクラス
    </div>

    <!-- 配列でのクラス設定 -->
    <div :class="[isActive ? 'active' : '', isBold ? 'text-bold' : '']">
      配列でのクラス
    </div>

    <!-- 静的クラスと動的クラスの組み合わせ -->
    <div class="static-class" :class="{ active: isActive }">
      静的クラス＋動的クラス
    </div>

    <!-- 動的なスタイル属性の設定 -->
    <div :style="{ color: isActive ? 'blue' : 'gray', fontWeight: isBold ? 'bold' : 'normal' }">
      動的なスタイル
    </div>
  </div>
</template>
```
## Laravelとの連携
別の記事で書きます