Vue.js / Web Speech API で作る、 PWA対応 英単語学習ソフト


この記事は「PWA Advent Calendar 2019」の18日目の記事です。

今年の春、Progressive Web Apps や Firebase の練習がてら、英単語学習ソフトを開発しました。
(が、そのまま放置していた)

作りっぱなしももったいないので、アドベントカレンダーに乗じてご紹介します。

以下のような特徴があります。

  • Vue.js を利用したMPA(Multi-page Application)
  • Progressive Web Apps 対応。Windows10/スマホにインストールして、オフラインで動作。
  • 英単語の発音をクリックして確認できる (Web Speech API 利用)
  • Firebase のHosting機能を利用して公開
  • 選択肢と回答をランダムに生成。英単語アプリにありがちな「同じ選択肢と回答が繰り返され、出題パターンを覚えてしまう」ことがないようにした。(800の4乗x10問で、組み合わせは4兆通りぐらい?)

開発中のメモをもとに、いくつか備忘録を記述します。

Web Speech API による英語音声の確認

アプリを起動すると、英単語と4つの選択肢が表示されます。英単語をクリック・タップすると、英語の発音を確認できます。
Speech Synthesis API という、Web Speech APIの音声合成機能を利用しました。

          pronounce: function () {

            // confirm English word's pronounciation

            let u = new SpeechSynthesisUtterance();
            u.lang = 'en-US';
            u.text = document.getElementById('englishWord').innerHTML;
            u.volume = "1";
            speechSynthesis.speak(u);

          }

※Speech Synthesis API の使い方については拙稿「Web Speech API を 利用して 英単語の音声確認をするアプリを作る」にまとめました。

Service Worker によるデータキャッシュ

html・CSS・効果音などのアセットファイル類を、Service Worker でまとめてキャッシュしています。

バージョンをキャッシュのキーとして登録。バージョン情報に更新があった場合、キャッシュパージ後、ファイルをキャッシュしなおすようにしました。

const CACHE_NAME = `BasicEnglish800-${version}`;

---- 中略 ----

// Service Worker へファイルをインストール

self.addEventListener('install', function (event) {
  event.waitUntil(
    caches.open(CACHE_NAME)
      .then(function (cache) {
        console.log('Opened cache');
        return cache.addAll(urlsToCache);
      })
  );
});

// リクエストされたファイルが Service Worker にキャッシュされている場合
// キャッシュからレスポンスを返す

self.addEventListener('fetch', function (event) {
  if (event.request.cache === 'only-if-cached' && event.request.mode !== 'same-origin')
    return;
  event.respondWith(
    caches.match(event.request)
      .then(function (response) {
        if (response) {
          return response;
        }
        return fetch(event.request);
      }
      )
  );
});

// Cache Storage にキャッシュされているサービスワーカーのkeyに変更があった場合
// 新バージョンをインストール後、旧バージョンのキャッシュを削除する
// (このファイルでは CACHE_NAME をkeyの値とみなし、変更を検知している)

self.addEventListener('activate', event => {
  event.waitUntil(
    caches.keys().then(keys => Promise.all(
      keys.map(key => {
        if (!CACHE_NAME.includes(key)) {
          return caches.delete(key);
        }
      })
    )).then(() => {
      console.log(CACHE_NAME + "activated");
    })
  );
});

※Service Workerの使い方や詳細については拙稿「Progressive Web Apps (PWA) 学習者のメモ その1  (Service Worker)」にまとめました。

Vue.js で問題を生成、回答記録を追跡

Vue.js を利用して、回答数を記録。
最初に10問分の英単語・選択肢・回答を、ランダムに生成。
配列に単語・回答・選択肢のデータを格納。
問題を解いて「次へ」をクリック・タップすることで、配列を切り替え、次の問題を表示。
1問解くたびに、次の問題へ切り替え。

10問終了後に正誤のデータを確認し、回答を記録するようにしました。


      const vm = new Vue({
        el: '#el',
        data() {
          return {
            arr: answerList,
            count: 0,
            choice: quizList,
            result: [],
          }
        },
        methods: {
          check: function (event) {

            // check user's answer each by each

            let target = document.getElementById("answerOptions");

            target.setAttribute('style', 'pointer-events: none;');
            let rightAnswer = this.arr[this.count].Japanese;
            let chosenAnswer = event.target.innerHTML;

            if (rightAnswer === chosenAnswer) {

              correctSound.play();
              message.innerHTML = "正解!";
              addAnswer("");

            } else {

              wrongSound.play();
              message.innerHTML = "残念!";
              addAnswer("×");

            }

            this.count === 9 ? complete() : unComplete();
          },

※Vue.js を利用した回答の切り替え(=配列の切り替え)については、拙稿「Vue.js で 配列とJSONの切り替え表示を行う」にまとめました。

振り返り

一つ一つは単純なコードですが、組み合わせることで、それなりにアプリとして形になった気がしました。

できれば

  • Firebase のユーザー認証を利用して、リアルタイムDBに回答記録を保存
  • 全アプリユーザーの間で、どの単語の誤答率が高いか、統計を取る

までやってみたかったのですが、時間切れで実装できず。
Firebaseの利用はHostingのみとなりました。

そのうち時間を作ってチャレンジしてみたいと思います。

備考

以下のサイトのデータ・情報を元に開発しました。