Vue.jsでかっこいいチュートリアル画面作成

つべこべ言うのは止めますｗ
表題の通りです！

以下、手順になります。

- VueでProjectを作成（Vue-cliなどで）
- [vue-tour](https://github.com/pulsardev/vue-tour)をインストールします。

- コード内を修正していきます。
※ここではVue-cli3で作成した雛形を元に説明を行います。

まずはmain.jsを修正していきます。

```main.js
import Vue from 'vue'
import App from './App.vue'
import router from './router'
import VueTour from 'vue-tour' //vue-tourをimport

Vue.use(VueTour)//useにVueTourを登録
require('vue-tour/dist/vue-tour.css')
//↑ここはvue-tourのデフォルトレイアウトが必要ない場合はrequireしなくても大丈夫です。

Vue.config.productionTip = false

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

```

次にHelloWorld.vue内を修正していきます。


```HelloWorld.vue
<template>
  <div class="hello">
    <h1>{{ msg }}</h1>
    <p>
      For guide and recipes on how to configure / customize this project,<br>
      check out the
      <a href="https://cli.vuejs.org" target="_blank" rel="noopener">vue-cli documentation</a>.
    </p>
    <h3>Installed CLI Plugins</h3>
    <ul>
      <li id="v-step-0"><a href="https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-babel" target="_blank" rel="noopener">babel</a></li>
      <li id="v-step-1"><a href="https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-eslint" target="_blank" rel="noopener">eslint</a></li>
    </ul>
    <!--コンポーネントを分割してもtourが発火するか試したかったので分割しております-->
    <Parts1/>
    <Parts2/>
    <tour/>
  </div>
</template>
<script>

import Parts1 from '../components/parts/part1'
import Parts2 from '../components/parts/part2'
import tour from '../components/Mytour/tour'

export default {
  name: 'HelloWorld',
  props: {
    msg: String
  },
  components: {
    Parts1,
    Parts2,
    tour
  }
}
</script>
```

part1とpart2は最初のHelloWorldを分割しただけです。

```part1.vue
<template>
  <div>
    <h3>Essential Links</h3>
    <ul>
      <li id="v-step-2"><a href="https://vuejs.org" target="_blank" rel="noopener">Core Docs</a></li>
      <li><a href="https://forum.vuejs.org" target="_blank" rel="noopener">Forum</a></li>
      <li><a href="https://chat.vuejs.org" target="_blank" rel="noopener">Community Chat</a></li>
      <li><a href="https://twitter.com/vuejs" target="_blank" rel="noopener">Twitter</a></li>
      <li><a href="https://news.vuejs.org" target="_blank" rel="noopener">News</a></li>
    </ul>
  </div>
</template>

```

```part2.vue
<template>
  <div>
    <h3>Ecosystem</h3>
      <ul>
        <li id="v-step-3"><a href="https://router.vuejs.org" target="_blank" rel="noopener">vue-router</a></li>
        <li><a href="https://vuex.vuejs.org" target="_blank" rel="noopener">vuex</a></li>
        <li><a href="https://github.com/vuejs/vue-devtools#vue-devtools" target="_blank" rel="noopener">vue-devtools</a></li>
        <li><a href="https://vue-loader.vuejs.org" target="_blank" rel="noopener">vue-loader</a></li>
        <li><a href="https://github.com/vuejs/awesome-vue" target="_blank" rel="noopener">awesome-vue</a></li>
      </ul>
  </div>
</template>
```

次にtour.vueコンポーネントを準備します。
※元moduleの内容をオーバーライドしてカスタマイズする際には、コンポーネントを用意した方が
柔軟性がありそうです。
[ここを参照](https://pulsar.gitbooks.io/vue-tour/customizing-the-template.html)

```tour.vue
<template>
  <div>
    <button @click="$tours['myTour'].start()" class="btn btn-lg">Start the tour</button>
    <button @click="nextStep" class="btn btn-lg">Next step</button>
    <button @click="showLastStep" class="btn btn-lg">Show last step</button>

    <v-tour name="myTour" :steps="steps" :callbacks="callbacks">
      <template slot-scope="tour">
        <transition name="fade">
          <v-step
            v-if="tour.currentStep === index"
            v-for="(step, index) of tour.steps"
            :key="index"
            :step="step"
            :previous-step="tour.previousStep"
            :next-step="tour.nextStep"
            :stop="tour.stop"
            :isFirst="tour.isFirst"
            :isLast="tour.isLast"
          >
            <template v-if="tour.currentStep === 2">
              <div slot="actions">
                <button @click="tour.previousStep" class="btn btn-primary">Previous step</button>
                <button @click="tour.nextStep" class="btn btn-primary">Next step</button>
              </div>
            </template>
          </v-step>
        </transition>
      </template>
    </v-tour>
  </div>
</template>

<script>
  export default {
    name: 'my-tour',
    data () {
      return {
        steps: [
          {
            target: '#v-step-0',
            content: `Discover <strong>Vue Tour</strong>!`
          },
          {
            target: '#v-step-1',
            header: {
              title: 'Vue Tour'
            },
            content: 'An awesome plugin made with Vue.js!'
          },
          {
            target: '#v-step-2',
            content: 'Try it, you\'ll love it!<br>You can put HTML in the steps and completely customize the DOM to suit your needs.',
            params: {
              placement: 'top'
            }
          },
          {
            target: '#v-step-3',
            params: {
              placement: 'left'
            }
          }
        ],
        callbacks: {
          onPreviousStep: this.myCustomPreviousStepCallback,
          onNextStep: this.myCustomNextStepCallback
        }
      }
    },
    mounted: function () {
      this.$tours['myTour'].start()

      // A dynamically added onStop callback
      this.callbacks.onStop = () => {
        document.querySelector('#v-step-0').scrollIntoView({behavior: 'smooth'})
      }
    },
    methods: {
      nextStep () {
        this.$tours['myTour'].nextStep()
      },
      showLastStep () {
        this.$tours['myTour'].currentStep = this.steps.length - 1
      },
      myCustomPreviousStepCallback (currentStep) {
        console.log('[Vue Tour] A custom previousStep callback has been called on step ' + (currentStep + 1))
      },
      myCustomNextStepCallback (currentStep) {
        console.log('[Vue Tour] A custom nextStep callback has been called on step ' + (currentStep + 1))

        if (currentStep === 1) {
          console.log('[Vue Tour] A custom nextStep callback has been called from step 2 to step 3')
        }
      }
    }
  }
</script>

<style scoped>
  .fade-enter-active, .fade-leave-active {
    transition: opacity .5s;
  }

  .fade-enter, .fade-leave-to {
    opacity: 0;
  }
</style>

```

ベースはこの部分が担っており

```ｊｓ
<button @click="$tours['myTour'].start()" class="btn btn-lg">Start the tour</button>
<button @click="nextStep" class="btn btn-lg">Next step</button>
<button @click="showLastStep" class="btn btn-lg">Show last step</button>
```

この部分や

```js
<transition name="fade">
          <v-step
            v-if="tour.currentStep === index"
            v-for="(step, index) of tour.steps"
            :key="index"
            :step="step"
            :previous-step="tour.previousStep"
            :next-step="tour.nextStep"
            :stop="tour.stop"
            :isFirst="tour.isFirst"
            :isLast="tour.isLast"
          >
```
この部分のステータスやif文を調整することで、表示の方法やn回目のヒントで状態を変えたい時などができるようです。

```js
<template v-if="tour.currentStep === 2">
 <div slot="actions">
  <button @click="tour.previousStep" class="btn btn-primary">Previous step</button>
  <button @click="tour.nextStep" class="btn btn-primary">Next step</button>
 </div>
</template>
```

stepのArrayの中に表示したい文言やターゲット要素を指定することで、Viewに反映させるようです。

```js
export default {
    name: 'my-tour',
    data () {
      return {
        steps: [
          {
            target: '#v-step-0',//このidを要素に付与
            content: `Discover <strong>Vue Tour</strong>!`//説明書き
          },
          {
            target: '#v-step-1',
            header: {//説明時のツールチップにHeaderを持たせられる
              title: 'Vue Tour'//headerのtitle
            },
            content: 'An awesome plugin made with Vue.js!'
          },
          {
            target: '#v-step-2',
            content: 'Try it, you\'ll love it!<br>You can put HTML in the steps and completely customize the DOM to suit your needs.',
            params: {
              placement: 'top'//ツールチップの表示位置のレイアウト調整
            }
          },
          {
            target: '#v-step-3',
            params: {
              placement: 'left'
            }
          }
        ]
//以下、略

```

##サンプル画面

チュートリアル（ヒント）をツールチップで示したい要素にtargetで指定したid`(v-step-0)`などを付与してあげれば完成です。
※尚、targetはidだけではなくclassやdata属性でも可能みたいです。


![チュートリアル.gif](https://qiita-image-store.s3.amazonaws.com/0/135375/cc93b4ab-0124-6a39-9f88-e49a96cda277.gif)


コンポーネントを分割していてもrootになる（今回はHelloWorld.vue）にtourコンポーネントをimportしてあげれば問題なく動きます。


[vue-tour](https://github.com/pulsardev/vue-tour)のREADMEなどに詳細は記載されているので、みなさんもかっこいい導入画面を作ってみてください！！


[vue-intorjs](https://github.com/alex-oleshkevich/vue-introjs)こちらはintor.jsをvueで使いやすくしているものなので、もっとかっこいい導入画面を作れますが、商用だとライセンス購入しないといけないのでプロダクトで使う場合は注意が必要です

こっちも試してみよう！