Vue.jsを利用したクイズアプリ

Image from Gyazo

ルーティングとは

ルーティング(Routing) とはVue.jsにおいて, リクエストされたURLに応じて,コンポーネントを選択して表示する仕組みのことです. シングルページアプリケーション(Single Page Application: SPA) と呼ばれる 単一のWebページで動的にコンテンツを切り替える設計方法を実現するために用いられます. Webページの遷移が発生しないため,サーバとの通信を減らし高速なコンテンツの遷移が可能になることに加え, ネイティブアプリ(JavaやSwiftで開発されたアプリ)の代替としても採用されます. 今回はこのルーティングを利用してクイズアプリを実装してみましょう.

クイズアプリ

それでは, クイズアプリ を実装して行きましょう. 下記が完成したソースコードです. 「問題」をクリックするとクイズの問題が表示され, 「解答」をクリックすると対応するクイズの解答が表示されます.

See the Pen クイズアプリ by Naoto Mukai (@nmukai) on CodePen.

CDNのリンク

ルーティングを実装するには,vue.js に加え, vue-route.js を導入する必要があります. CodePenのSettingsで下記のようにCDNを追加してください.

Image from Gyazo

ルータの作成

それではルーティングの役割を担う VueRouter クラスのインスタンスをを作成しましょう. このルータには,2つのコンポーネント(component)を登録します. コンポーネントの実体は,変数のQuizBlockAnsBlockで宣言しています. それぞれのコンポーネントには,pathnameのプロパティを設定します. pathはリクエストされるURL,nameはルートの名前を表します. また,Vue クラスに router をプロパティとして登録しておきます.

var QuizBlock = {
  template: "<div> question </div>"
}

var AnsBlock = {
  template: "<div> answer </div>"
}

var router = new VueRouter({
  routes: [
    {
      path: "/quiz",
      name: "quiz",
      component: QuizBlock
    },
    {
      path: "/answer",
      name: "answer",
      component: AnsBlock
    }
  ]
})

new Vue({
  el: "#main",
  router
})

ルーティングを利用するにはrouter-linkタグを利用します. to属性は表示したいコンポーネントのpathを指定します. router-linkタグは,リンクを表すaタグとして表示されます. また,router-viewタグは,コンポーネントを表示する領域です.

<div id="main">
  <p>クイズ</p>
  <router-link to="/quiz" >問題</router-link>
  <router-link to="/answer" >解答</router-link>
  <router-view />
</div>

ここまで実装すると,下記のようになります. 問題をクリックするとrouter-viewタグに,QuizBlockのコンポーネントが表示されます. 同様に解答をクリックするとrouter-viewタグに,AnsBlockのコンポーネントが表示されます.

Image from Gyazo

Image from Gyazo

ルートパラメータ

router-linkタグで表示するコンポーネントにデータを渡すには ルートパラメータ という方法を用います. この方法では,path属性にパラメータ(キーと値のペア)が埋め込まれ,表示されるコンポーネントでデータを受け取ることができます.

まず,ルータのpathプロパティに,パラメータのキーを記述します. 例えば,quizという名前のキーであれば,:quizを最後に追加します.

次にrouter-linkタグのto属性を修正します. v-bindディレクティブを利用して,to属性にはオブジェクトを指定します. このオブジェクトには,nameparams を指定します. name はルートの名前,paramsはコンポーネントに渡すパラメータ(キーと値のペア)を指定します.

コンポーネントでは,ルートパラメータで取得したデータを $route.params.[パラメータのキー]で参照できます. ここでは,$route.params.quizを参照し,“question"と"answer"の文字列を表示しています.

var QuizBlock = {
  template: "<div> {{ $route.params.quiz }} </div>"
}

var AnsBlock = {
  template: "<div> {{ $route.params.quiz }} </div>"
}

var router = new VueRouter({
  routes: [
    {
      path: "/quiz/:quiz",
      name: "quiz",
      component: QuizBlock
    },
    {
      path: "/answer/:quiz",
      name: "answer",
      component: AnsBlock
    }
  ]
})
<div id="main">
  <p>クイズ</p>
  <router-link v-bind:to="{name: 'quiz', params: {'quiz': 'question'}}" >問題</router-link>
  <router-link v-bind:to="{name: 'answer', params: {'quiz': 'answer'}}" >解答</router-link>
  <router-view />
</div>

クイズの作成

最後にクイズの問題と解答を作成しましょう. Vueクラスのdataプロパティでquizzesに問題と解答のデータを保持させます.

new Vue({
  el: "#main",
  router,
  data: {
    quizzes: [
      {
        question: "Q. ぼうしの中に入っている動物はなに?",
        answer: "A. うし"
      },
      {
        question: "Q. 飲むとおこられるジュースってなに?",
        answer: "A. コーラ"        
      }
    ]
  }
})

v-forディレクティブを利用して,quizzesの要素数だけ繰り返して,問題と解答のリンクを表示します. このとき,Mustache構文を利用して,問題番号を表示しています. また,ルートパラメータのパラメータとして,文字列ではなくオブジェクト(quizzesの要素)を指定していることに注意してください.

<div id="main">
  <p>クイズ</p>
  <template v-for="(quiz, i) in quizzes">
    <p>
      <router-link v-bind:to="{name: 'quiz', params: {'quiz': quiz}}" >問題{{ i }}</router-link>
      <router-link v-bind:to="{name: 'answer', params: {'quiz': quiz}}" >解答{{ i }}</router-link>
    </p>
  </template>

  <router-view />
</div>

ルートパラメータはオブジェクトであり,questionanswerを参照することができます. 問題や解答のリンクをクリックすると対応する文字列が表示されれば完成です.

var QuizBlock = {
  template: "<div> {{ $route.params.quiz.question }} </div>"
}

var AnsBlock = {
  template: "<div> {{ $route.params.quiz.answer }} </div>"
}

Image from Gyazo

参考書籍