Vueでスライドショーを自作した

# はじめに

Vue.js(以下Vue)いいですよね！！！
私はまだまだVue初心者です。
今年の6月頃から趣味で触り始めたVueですが、個人的にかなりハマり、自社アプリをVueでリプレイスしたり、実際の案件でも利用するまでになりました。
しかも関西でVueのコミュニティが立ち上がるので、さらにVueを深めて行かなければ…という気持ちですね。
そんな私ですがVueが好きすぎるので、ある発表スライドをVueで自作するというバカげたことをやりましたwww
このスライドは12/20に京都で開催された[v-kansai Vue.js/Nuxt.js meetup #1](https://vuekansai.connpass.com/event/110542/)での発表スライドにしたものです。

## 前提条件

Vueファイルに直接書くのではなく、Pug / Scss / TypeScriptに書くようにして、Vueファイルに読み込ませるようにしています。

```
<template src="./hoge.pug" lang="pug"></template>

<script src="./hoge.ts" lang="ts"></script>

<style src="./hoge.scss" lang="scss"></style>
```

## 完成品

[**私のGitHub**](https://github.com/ryo-is/vue-slideshow)にPushしてあります。
基本的にソースコードの一部を抜粋して説明しているので、詳細はリポジトリに上がっているソースコードを参照してください。
あまりきれいに書けてないと思われるのでご了承くださいmm
`git clone` して `npm i` して `npm run serve` とやればローカルでスライドを確認することができます。 

![vue-slideshow.gif](https://qiita-image-store.s3.amazonaws.com/0/95875/b9e497a0-e43d-a883-17f4-b1a0769cbec8.gif)



## 工夫したところ

### デザインごとにComponentを分ける

使い回しのできる部分は一つのComponentにする
例) 各ページのタイトル
<img width="600" alt="slide_title.png" src="https://qiita-image-store.s3.amazonaws.com/0/95875/11ab19a2-1d53-2463-8d87-cbae315bc27f.png">

文字の内容(「工夫した点」など)はpropで各Componentに渡す(ここはVuex使えばよかったかも……)

親Component(スライドページ)。タイトルパーツのComponentに `pageTitleText` を渡す。

```pug

.main-contents
  PageTitle(:title-text="pageTitleText")
```

子Component(各パーツ)。親から受け取った `pageTitleText` が `titleText` に代入されているので、Templateで表示する

```pug
.page-title
  .text {{ titleText }}
```

```ts

import { Component, Vue, Prop } from "vue-property-decorator";

@Component({})
export default class Conclusion extends Vue {
  @Prop() private titleText!: string;
}
```

### 動的セグメントを利用して、なるべくRouterを汚さない

基本的に一つのスライドに一つのPathが必要になってきます。
一つのPathごとにRouteを切っていたらRouterの中身ががが……となるので、動的セグメントを有効活用して、できるだけRouterを汚さないようにします。
ただ当然ですが、こうすると一つのComponentで複数のスライドを表現しなければいけないので、それはそれで工夫が必要です。(共通部分のComponentを作ったり、動的セグメントでTemplateを切り替えたり……)

```ts
import Vue from "vue";
import Router from "vue-router";
...
// 省略
...
Vue.use(Router);

export default new Router({
  mode: "history",
  base: process.env.BASE_URL,
  routes: [
    {
      path: "/",
      name: "title",
      component: Title
    },
    {
      path: "/selfIntroduction",
      name: "selfIntroduction",
      component: SelfIntroduction
    },
    {
      path: "/introduction/:pageName", // こういう書き方
      name: "introduction",
      component: Introduction
    },
    {
      path: "/summary/:pageName", // こういう書き方
      name: "summary",
      component: Summary
    },
    ...
    // 省略
    ...
  ]
});
```

### 画面(スライド)の切り替え

スライドなので、前後のスライドへ切り替えられるようにしなければなりません。
常に画面の一番上(前面)に要素を配置し、右半分に「次のスライドに進む」イベントを、左半分に「前のスライドに戻る」イベント持たせる。
表示中のスライドの前後のスライドが何かという情報はComponentに持たせる

```ts
transitionPageInfo: transitionPageInfoType = {
  preb: "",
  next: ""
};
```

イメージ的にはこんな感じ
![スクリーンショット 2018-12-11 15.43.44.png](https://qiita-image-store.s3.amazonaws.com/0/95875/611c3a44-85bd-7296-cb46-bd04fe4fadea.png)

```pug

el-row.transition-page-area
  el-col(:span="12")
    .preb-page(@click="transitionPage('preb')" @mouseenter="showArrow('preb')" @mouseleave="hiddenArrow('preb')")
      .preb-arrow(v-show="prebArrow")
        img(src="../../assets/left_arrow.png", alt="")
  el-col(:span="12")
    .next-page(@click="transitionPage('next')" @mouseenter="showArrow('next')" @mouseleave="hiddenArrow('next')")
      .next-arrow(v-show="nextArrow")
        img(src="../../assets/right_arrow.png", alt="")
```

```ts
// ページ切り替え
public transitionPage(action: string) {
  // 表示中スライドのComponentから前後スライドのrouteを取得
  const targetRoute: string = this.$parent.$children[0].$children[1].$data
    .transitionPageInfo[action];
  if (targetRoute !== "") {
    router.push(targetRoute);
  }
}

// 矢印の表示
public showArrow(action: string) {
  switch (action) {
    case "preb":
      this.prebArrow = true;
      break;
    case "next":
      this.nextArrow = true;
      break;
    default:
      break;
  }
}

// 矢印の非表示
public hiddenArrow(action: string) {
  switch (action) {
    case "preb":
      this.prebArrow = false;
      break;
    case "next":
      this.nextArrow = false;
      break;
    default:
      break;
  }
}
```

## さいごに

実際にVueでスライドを作ってみて、今まで知らなかった機能というか書き方を知ることができた、使うことができたのでいい機会だったなと思いました。
断片的にソースの紹介などをいたしましたが、実際のソースコードを見ていただいたほうがイメージ付きやすいと思います。
あとだーいぶサボって書いた部分が多いので、変数名とか、命名規則とかボロボロなところがあります。きっといつか直します。
今後Vueのイベントで登壇する機会があったらまたスライド作ろうかなーって思ってます。
ではまた！！！