Vue.jsドキュメントのスロットで躓いた箇所についての覚書①


# はじめに
最近Vue.jsを学習中です。
Vuetifyに手を出した際にスロットに関する理解が不十分であることに気づいたので、[Vue.js公式ドキュメント](https://jp.vuejs.org/v2/guide/components-slots.html)を一通り読みながら動かしてみようと思ったのですが、いくつか躓いた点があるので残しておきます。(※2020/1/8時点の内容です。)
Vue.js最近触り始めたよーって方の参考になれば幸いです。

※できるだけ分かりやすく書きますが完全に初心者向けの内容というわけではないので、完全初心者の方は公式ドキュメントの「基本的な使い方」あたりを見てからの方が理解できると思います。
ちなみにVue.jsの初学者向けの書籍としては[猫本](https://www.amazon.co.jp/%E5%9F%BA%E7%A4%8E%E3%81%8B%E3%82%89%E5%AD%A6%E3%81%B6-Vue-js-mio/dp/4863542453)がおすすめです。

# 事前準備
試しで動かすためにVueCLI4でプロジェクトのひな型を作ります。

#####１. VueCLI4をインストールする。  [※参考](https://cli.vuejs.org/guide/installation.html#installation)  

```
npm install -g @vue/cli
```  

##### ２. プロジェクトを作りたいディレクトリで`create`する。 [※参考](https://cli.vuejs.org/guide/creating-a-project.html#vue-create)

```
vue create my-app
```

上記のコマンド実行後にプロジェクトの構成を聞かれますが、`default`でOKです。

```
? Please pick a preset: (Use arrow keys)
> default (babel, eslint)
  Manually select features
```

しばらく待ってひな形のプロジェクトの完成です。

##### 3. サーバを立ち上げる

以下のようにディレクトリを変更して、サーバを起動するように促されますので、言われた通りにコマンドを実行します。

```
�🎉  Successfully created project my-app.
�👉  Get started with the following commands:

 $ cd my-app
 $ npm run serve
```

以下のように表示されたらサーバが立ち上がっているので`http://localhost:8080/`にブラウザからアクセスします。
(VSCodeの場合は`Ctrl`を押しながらクリックするとブラウザで開けて便利！)

```
 DONE  Compiled successfully in 6349ms

  App running at:
  - Local:   http://localhost:8080/
  - Network: http://192.168.100.100:8080/
```

以下のような画面が表示されていればOKです。

![キャプチャ11111.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/278934/e7a1d989-8b4d-5a87-10a2-fdafda364848.png)

ちなみにサーバの停止はVSCodeの場合、`Ctrl`+`C`でできます。
以下が出力されるので`y`を入力すればOKです。

```
バッチ ジョブを終了しますか (Y/N)?
```

基本的に作業中は立ち上げっぱなしで問題ないです。
※VSCode自体を閉じても停止します。

##### ４. ソースを修正する
自動で出力されたソースを修正して、この後の動作確認を行いやすくします。
対象のファイルを以下のように修正します。

```vuejs:src\App.vue
<template>
  <div id="app">
    <HelloWorld />
  </div>
</template>

<script>
import HelloWorld from "./components/HelloWorld.vue";

export default {
  name: "app",
  components: {
    HelloWorld
  }
};
</script>
```

```vuejs:src\components\HelloWorld.vue
<template>
  <div>Slot Practice</div>
</template>

<script>
export default {
  name: "HelloWorld"
};
</script>
```
かなりスッキリしました。
再度ブラウザで`http://localhost:8080/`を開くと「Slot Practice」が左上に表示されているだけであることを確認してください。

ちなみに構成としては`App.vue`が親コンポーネント、`HelloWorld.vue`が子コンポーネントとなっています。
Slotはざっくり言うと親が子のコンポーネントを呼び出す際にデータなどを与える仕組みだと思うので、親と子の関係がある点を抑えておくとよいかと思います。

# 躓いた点
## [スロットコンテンツ](https://jp.vuejs.org/v2/guide/components-slots.html#%E3%82%B9%E3%83%AD%E3%83%83%E3%83%88%E3%82%B3%E3%83%B3%E3%83%86%E3%83%B3%E3%83%84)
### ①`url`が見つからない
とりあえず載ってる通りに修正したら最初っから詰まりました。
※コンポーネントの名前は変えるのがめんどくさかったので`HelloWorld`のままにしてます。
分かりにくければ`navigation-link`に読み替えてもらえればと思います。

```vuejs:src\App.vue
<template>
  <div id="app">
    <HelloWorld url="/profile">
      Your Profile
    </HelloWorld>
  </div>
</template>

<script>
import HelloWorld from "./components/HelloWorld.vue";

export default {
  name: "app",
  components: {
    HelloWorld
  }
};
</script>
```

```vuejs:src\components\HelloWorld.vue
<template>
  <a v-bind:href="url" class="nav-link">
    <slot></slot>
  </a>
</template>

<script>
export default {
  name: "HelloWorld"
};
</script>
```

上記のように修正ところ、VSCode上ではエラーなどはなかったのですが、Chrome上でエラーが発生していました。
(Chormeのデベロッパーツールは`F12`で開けます。便利！)
エラーの内容は以下です。
![キャプチャ11.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/278934/c2f8c0db-b7a7-e01d-b6fd-ccea29ac921c.png)

ごちゃごちゃ書いてありますが、要は以下の2点です。
　・「`url`が使われているが、定義されていない」
　・「src/components/HelloWorld.vueが原因」

### ①解決
`HelloWorld.vue`で`href`属性に`v-bind`している`url`が定義されていないことが原因でした。
なので`data`を追加して、urlに適当に値を設定してあげます。

```vuejs:src\components\HelloWorld.vue
<template>
  <a v-bind:href="url" class="nav-link">
    <slot></slot>
  </a>
</template>

<script>
export default {
  name: "HelloWorld",
  data() {
    return {
      url: "https://www.google.com/"
    };
  }
};
</script>
```

ちなみにコンポーネントのdataオプションは関数である必要があります。　[※参考](https://jp.vuejs.org/v2/guide/components.html#data-%E3%81%AF%E9%96%A2%E6%95%B0%E3%81%A7%E3%81%AA%E3%81%91%E3%82%8C%E3%81%B0%E3%81%AA%E3%82%8A%E3%81%BE%E3%81%9B%E3%82%93)

上記に修正したところ、Chorme上のエラーが消えて、「Your Profile」がリンクになり、「https://www.google.com/」
を開けるようになりました。

### ②`<font-awesome-icon>`が見つからない
親側(App.vue)で子コンポーネントタグの中にコンポーネントも含むことができるよの説明の中で、Font awesomeが使われていました。
とりあえず以下のように修正。

```vuejs:src\App.vue
<template>
  <div id="app">
    <HelloWorld url="/profile">
      <!-- コンポーネントを使ってアイコンを追加 -->
      <font-awesome-icon name="user"></font-awesome-icon>Your Profile
    </HelloWorld>
  </div>
</template>

<script>
import HelloWorld from "./components/HelloWorld.vue";

export default {
  name: "app",
  components: {
    HelloWorld
  }
};
</script>
```
上記の修正を行ってChormeを確認したところ、以下のようなエラーが発生していました。
![キャプチャ1.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/278934/a6c89abe-b239-dcd2-6a63-c3fbd80a4875.png)
`font-awesome-icon`が見つからないとのこと。

### ②解決
ググって一番上にあった以下の記事を参考に、Font awesomeを`install`します。
[Font awesome を Vue.js で使ってみよう](https://qiita.com/kurararara/items/d76776a7dc2d763a068b)

※installコマンドを実行する前にサーバを停止します。

```
> npm install --save @fortawesome/fontawesome-svg-core
> npm install --save @fortawesome/free-solid-svg-icons
> npm install --save @fortawesome/vue-fontawesome
```

更に先ほどの記事を参考に`src/main.js`を以下のように修正します。

```javascript:src/main.js
import Vue from 'vue'
import App from './App.vue'
import { library } from '@fortawesome/fontawesome-svg-core'
import { faCoffee } from '@fortawesome/free-solid-svg-icons'
import { FontAwesomeIcon } from '@fortawesome/vue-fontawesome'

library.add(faCoffee)

Vue.component('font-awesome-icon', FontAwesomeIcon)

Vue.config.productionTip = false

new Vue({
  render: h => h(App),
}).$mount('#app')
```

この状態で再度サーバを立ち上げて、ブラウザで確認します。
新たに以下のエラーが出ていました。。。
![キャプチャ2.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/278934/3dde3644-231d-722d-1062-7e46c4d5220a.png)

1つ目のエラーについて、とりあえず先ほどの参考記事の下の方まで確認すると、[ここ](https://qiita.com/kurararara/items/d76776a7dc2d763a068b#%E7%A2%BA%E8%AA%8D%E3%81%97%E3%82%88%E3%81%86)で`<font-awesome-icon icon="coffee" />`としている部分を見つけました。
`name`ではなく`icon`を指定するようです。
また、[公式Githubの使用方法](https://github.com/FortAwesome/vue-fontawesome#usage)にも同様に`icon`を指定している記述がありました。
`App.vue`を以下のように修正します。

```vuejs:src\App.vue
<template>
  <div id="app">
    <HelloWorld url="/profile">
      <!-- コンポーネントを使ってアイコンを追加 -->
      <font-awesome-icon icon="user"></font-awesome-icon>Your Profile
    </HelloWorld>
  </div>
</template>

<script>
import HelloWorld from "./components/HelloWorld.vue";

export default {
  name: "app",
  components: {
    HelloWorld
  }
};
</script>
```
ブラウザを確認すると1つ目のエラーがなくなっていることを確認できました。
![キャプチャ22.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/278934/195140ab-7ea5-afcd-58bd-8a5360906691.png)

2つ目のエラーについては、なかなか原因が分からなかったのですが、先程の[公式Githubの使用方法](https://github.com/FortAwesome/vue-fontawesome#usage)をよく確認すると、`src/App.vue`で`user-secret`のアイコンを使用するために、`src/main.js`において`{ faUserSecret }`をimportしていることに気づきました。
どうやら使用したいアイコンによってimportするアイコンを指定する必要があるようです。
これに倣って、`main.js`のimport部分とadd部分を修正します。

```javascript:src/main.js
import Vue from 'vue'
import App from './App.vue'
import { library } from '@fortawesome/fontawesome-svg-core'
import { faUser } from '@fortawesome/free-solid-svg-icons'
import { FontAwesomeIcon } from '@fortawesome/vue-fontawesome'

library.add(faUser)

Vue.component('font-awesome-icon', FontAwesomeIcon)

Vue.config.productionTip = false

new Vue({
  render: h => h(App),
}).$mount('#app')
```

上記の修正後、Chormeでエラーが出ていないことと、画面上でユーザーのアイコンが表示されていることを確認できました。
![キャプチャ3.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/278934/3e839144-739f-28e7-0a90-67936098e30b.png)

# 続く
長くなってしまったので次回に続きます。