Vue.js 3 初心者向け問題

Vue.jsを学ぶにあたって、[公式リファレンス](https://ja.vuejs.org/)を読んで心くじけたことがあるのは私だけではないと思いたいです。

さて、自身のアウトプットのために問題作ってみました。
Vue.jsに限らず、ケアレスミスでうまく処理が走らないのは初心者あるあるだと思います。
処理がうまくいかない際、どこを確認したら良いのか。この問題で慣れてもらえたらと嬉しいです。

:::note info
問題を作るにあたってのコードなどは、[これからはじめるVue.js 3実践入門](https://www.amazon.co.jp/dp/4815613362)を参考にさせて頂いています。
:::

### 問題1\. マウントが行われない
#### 以下の処理を実装したが、ブラウザ上では{{ text }}としか表示されない。何故か？
```html:question_1.html
<!DOCTYPE html>
<html>
    <body>
        <script src="https://cdn.jsdelivr.net/npm/vue@3.5.13/dist/vue.global.min.js"></script>
        <script src="question_1.js"></script>
        <div id="app">
        <p>{{ text }}</p>
        </div>
    </body>
</html>
```
```javascript:question_1.js
Vue.createApp({
  data() {
    return {
      text:'ようこそ！',
    };
  }
}).mount('#app');
```
理想形：
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3489679/056b326b-a56e-5351-7653-28667f46c178.png)
実行結果：
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3489679/d91d033f-ea80-c0d6-3463-3b09c01c75ed.png)



### 問題2\. 値が上書きされる
#### petNameプロパティにある「●●」の部分のみを「ハチ」に書き換えるため、以下のコードを書いたが理想形にならなかった。何故か。
```html:question_2.html
<!DOCTYPE html>
<html>
    <body>
        <div id="app">
            <p v-text="petName">ペットの名前：●●</p>
        </div>
        <script src="https://cdn.jsdelivr.net/npm/vue@3.5.13/dist/vue.global.min.js"></script>
        <script src="question_2.js"></script>
    </body>
</html>
```
```javascript:question_2.js
Vue.createApp({
  data() {
    return {
      petName:'ハチ'
    };
  }
}).mount('#app');
```

理想形：
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3489679/7aa378fd-0a92-d018-8970-161eab78bac1.png)

実行結果：
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3489679/5d274801-e5d5-54cd-5a3d-0ba04a29d7af.png)

### 問題3\. インデックス番号が表示されない
#### 画面上に1から始まる連番を付与したいが{{NaN}}といった表記になってしまう。何故か。
```html:question_3.html
<!DOCTYPE html>
<head>
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-9ndCyUaIbzAi2FUVXJi0CjmCapSmO7SnpJef0486qhLnuZ2cdeRhO02iuK6FUUVM" crossorigin="anonymous">
</head>
<html>
    <body>
        <table class="table">
            <tr>
                <th>No</th>
                <th>言語</th>
                <th>種類</th>
            </tr>
            <tr v-for="language in programmingLanguage">
                <td>{{ i + 1 }}</td>
                <td>{{ language.name }}</td>
                <td>{{ language.type }}</td>
            </tr>
        </table>
        <script src="https://cdn.jsdelivr.net/npm/vue@3.5.13/dist/vue.global.min.js"></script>
        <script src="question_2.js"></script>
    </body>
</html>
```
```javascript:question_3.js
Vue.createApp({
  data() {
    return {
      programmingLanguage: [
        {
          name: "JavaScript",
          type: "フロントエンド",
        },
        {
          name: "TypeScript",
          type: "フロントエンド",
        },
        {
          name: "PHP",
          type: "バックエンド",
        },
        {
          name: "Java",
          type: "バックエンド",
        }
       ]
    };
  },
}).mount('#app');
```
理想結果：
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3489679/c1ad7355-4655-9f00-f601-57e466d2c199.png)

実行結果：
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3489679/cece7004-d2d1-efd5-b00d-393e6b5ff45f.png)


### 問題1\. の答え
**scriptタグの記述位置が誤っているから**

`Vue.createApp({ ~ }).mount('#app');`と記述がありますが、これは「`id="app"`にVue.jsの中にある`createApp`メソッドと紐づけますよ」といった意味合いになります。この紐づける行為を **マウント** と言います。
今回マウントしたい対象は`id="app"`ですが、この対象を先に書かなかったことでVue.jsがマウント対象を見つけられず、ブラウザ上に「ようこそ！」のテキストが表示されませんでした。

正しくは以下になります。
```html:question_1.html
<!DOCTYPE html>
<html>
    <body>
        <div id="app">
            <p>{{ text }}</p>
        </div>
        <script src="https://cdn.jsdelivr.net/npm/vue@3.5.13/dist/vue.global.min.js"></script>
        <script src="question_1.js"></script>
    </body>
</html>
```
```javascript:question_1.js
Vue.createApp({
  data() {
    return {
      text:'ようこそ！',
    };
  }
}).mount('#app');
```
[createApp関数について](https://ja.vuejs.org/guide/essentials/application)

### 問題2\. の答え
**v-textを使っているから**

HTML側からVue.js側にアクセスして値を取り出すには以下の2種類の方法があります。
　・`{{ ・・・ }}`（マスタッシュ構文と言います）
　・`v-*****`属性(ディレクティブと言います）

`v-text`はディレクティブの内一つで、マスタッシュ構文と`v-text`の働きはほとんど同じです。1点違うのは、`v-text`の場合は既存の値を上書きしてしまうところです。
今回ならVue.js側の値である「ハチ」に上書きされています。部分的に値を変えたい場合はマスタッシュ構文を使う必要があるので、正しくは以下になります。
```html:question_2.html
<!DOCTYPE html>
<html>
    <body>
        <script src="https://cdn.jsdelivr.net/npm/vue@3.5.13/dist/vue.global.min.js"></script>
        <script src="question_1.js"></script>
        <div id="app">
            <p>ペットの名前：{{ petName }}</p>
        </div>
    </body>
</html>
```
```javascript:question_2.js
Vue.createApp({
  data() {
    return {
      petName:'ハチ'
    };
  }
}).mount('#app');
```
[v-textについて](https://ja.vuejs.org/api/built-in-directives)


### 問題3\. の答え
**v-forにインデックス番号の指定を行っていないから**
インデックス番号とは配列の要素に自動的に割り振られる番号のことを指し、0からスタートします。`{{ i + 1 }}`という記述で0+1, 1+1, 1+2・・・という処理を繰り返し行い、画面上には1,2,3と出ることを望んでいました。正しくは`v-for="(language, i)・・・"`といったようにインデックス番号を表すプロパティを記述し、`()`で括らなくてはいけません。

```html:question_3.html
<!DOCTYPE html>
<head>
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-9ndCyUaIbzAi2FUVXJi0CjmCapSmO7SnpJef0486qhLnuZ2cdeRhO02iuK6FUUVM" crossorigin="anonymous">
</head>
<html>
    <body>
        <table class="table">
            <tr>
                <th>No</th>
                <th>言語</th>
                <th>種類</th>
            </tr>
            <tr v-for="(language, i) in programmingLanguage">
                <td>{{ i + 1 }}</td>
                <td>{{ language.name }}</td>
                <td>{{ language.type }}円</td>
            </tr>
        </table>
        <script src="https://cdn.jsdelivr.net/npm/vue@3.5.13/dist/vue.global.min.js"></script>
        <script src="question_2.js"></script>
    </body>
</html>
```


今回はここまで。随時更新していきます。

**履歴** 
| 日付 | 内容 |
|:-:|:-:|
| 2025/01/28  | 問題3を追加 |