Monacaを使って何かアプリを作ってみたいと思っても、いざとなるとアイデアが出てこないかもしれません。また、最初から大きなアプリを作ろうと思うと、何から手を付けて良いのか分からないことでしょう。

そこで、この記事では手順を踏んで簡単なアプリを開発してみます。最初の一歩として、ぜひチャレンジしてみてください。

今回はNCMB(ニフクラmobile backend)と組み合わせて、単語帳アプリを開発します。記事は全部で2回に分けており、前半になるこの記事ではアプリの概要と、単語帳を登録するまでを解説します。

利用している技術、ライブラリ

このアプリで利用している技術やライブラリは次の通りです。

今回はMonacaでFramework7のCore Tab View テンプレートを選択しています。Monaca IDEからはフレームワークテンプレート > JavaScript > Framework7 Core Tab Viewと辿って選択します。

仕様

このアプリの画面は次の通りです。

目的

単語帳アプリは英語に限らず、新しい言語を覚えることを目的にしたサンプルアプリとなっています。

単語帳は複数作成可能で、その中に単語を登録します。トレーニングモードでは、最初は単語しか表示されません。タップで回答(日本語)を表示します。

また、単語には画像も紐付けられます。画像を使うことで、単語だけでなくイメージと結びつけた記憶を促せる仕組みです。

単語帳一覧画面

作成済みの単語帳を一覧表示する画面です。

単語帳作成画面

新しい単語帳を作成します。作成すると単語帳一覧画面に戻ります。

単語一覧画面

単語帳に登録されている単語を一覧表示します。単語をタップすると、単語編集画面に遷移します。単語を右にスワイプすると、単語の削除用アクションボタンが表示されます。

単語登録画面

新しい単語を登録します。単語はテキストエリアで、一行ごとに元の単語と意味の二つをカンマ区切りで入力することでまとめて一気に登録できます。

単語編集画面

登録した単語を編集する画面です。ここでは単語に紐付けて画像をアップロードできます。アップロードした画像はトレーニング画面で表示されます。

学習画面

単語帳を覚える画面です。最初は元の言葉しか表示されません。タップで回答が表示されます。スワイプまたは左右をタップすることで次の単語に移動します。記憶したと思ったら、記憶したをタップします。これでデータは次回以降は表示されなくなります。

答えを表示した画面は次のようになります。

ユーザーデータの権限

今回は個人用を想定し、認証は設けていません。データはオープン(誰でも読み書き可能)として保存しています。

ニフクラ mobile backendのキーを取得

ニフクラ mobile backendにユーザー登録、またはログインしてアプリを作成します。その結果として、次の2つのキーが取得できます。

  • アプリケーションキー
  • クライアントキー

ライブラリのインストール

外部ライブラリとして、ncmbを追加します。JavaScriptライブラリですので、JS/CSSコンポーネントの追加と削除から行ってください。

読み込むファイルとしてncmb.min.jsをチェックするのを忘れないでください。

単語一覧をエクスポートする機能を実装するためにFileSaver.jsを利用しています。これもNCMB同様に file-saver を検索して追加してください。

NCMBの初期化

www/js/app.js を開いて、下記のようにニフクラmobile backendを初期化する処理を追加します。上記で紹介したアプリケーションキーとクライアントキーを適用してください。

const applicationKey = 'YOUR_APPLICATION_KEY';
const clientKey = 'YOUR_CLIENT_KEY';
const ncmb = new NCMB(applicationKey, clientKey);

ルーティングについて

ルーティングは、URLへアクセスした際にどの画面を出すかを js/routes.js で定義しています。

const routes = [
  // 最初に読み込まれるHTML
  {
    path: '/',
    url: './index.html',
  },
  // 最初の画面(単語帳一覧)
  {
    path: '/home/',
    componentUrl: './pages/home.html',
  },
  // 単語帳作成画面
  {
    path: '/word_books/new',
    componentUrl: './pages/word_books/new.html',
  },
  // 単語帳詳細(単語一覧)
  {
    path: '/word_books/:objectId',
    componentUrl: './pages/word_books/show.html',
  },
  // 学習画面
  {
    path: '/word_books/:objectId/training',
    componentUrl: './pages/word_books/training.html',
  },
  // 単語登録画面
  {
    path: '/word_books/:objectId/words/new',
    componentUrl: './pages/words/new.html',
  },
  // 単語編集画面
  {
    path: '/word_books/:objectId/words/:wordId/edit',
    componentUrl: './pages/words/edit.html',
  },
];

index.html の紹介

Monacaアプリで一番初めに読み込まれる www/index.html では、
画面の実装はせず、home.htmlを読み込みます。

<div id="app">
  <div class="views safe-areas">
    <div id="view-home" class="view view-main view-init" data-name="home" data-url="/home/">
    </div>
  </div>
</div>

単語帳一覧画面 (home.html)

単語帳一覧画面 home.html は、NCMBから取得した単語帳の一覧を表示します。
また、単語帳作成画面へのリンクも用意しておきます。

<div class="row text-align-center">
  <div class="col-auto">
    <div class="block-title">学習する単語帳を選択してください</div>
  </div>
</div>
<div class="row">
  <div class="col text-align-center" id="no_word_book">
    <div>まだ単語帳がありません</div>
    <a href="/word_books/new" class="item-link list-button">
      <div class="item-inner">
        <div class="item-title">単語帳を作成する</div>
      </div>
    </a>
  </div>
  <div id="exist_word_book" class="col-auto">
    <div class="list">
      <ul>
      </ul>
    </div>
  </div>
</div>

単語帳の取得

単語帳の一覧を取得する処理は、画面を表示する度に行いたいので pageBeforeIn イベントで実行します。取得した単語帳が0件だった場合と、あった場合で表示するDOMを変えています。

pageBeforeIn: async function(e, page) {
  // 登録されている単語帳を取得
  this.wordBooks = await this.getWordBooks();
  // 単語帳の有無で画面の表示を切り分け
  if (this.wordBooks.length === 0) {
    $$('#exist_word_book').hide();
    $$('#no_word_book').show();
  } else {
    $$('#no_word_book').hide();
    $$('#exist_word_book').show();
    // 単語帳がある場合は画面に表示
    this.showWordBooks(this.wordBooks);
    // 表示した単語帳に、単語帳を選択した際のイベントを設定
    $$('.show-word-book').on('click', this.showWordBook);
  }
},

getWordBooks メソッドは次のようになります。

getWordBooks: async function() {
  const { ncmb } = this.$app.data;
  const WordBook = ncmb.DataStore('WordBook');
  return await WordBook.fetchAll();
}

そして、この取得した単語帳を showWordBooks メソッドで表示します。
ここではHTMLを構築しているのみになります。

// 単語帳一覧を表示
showWordBooks: function(wordBooks) {
  $$('#exist_word_book ul').html(wordBooks.map(wb => {
    return `<li><a href="#" data-object-id="${wb.objectId}" class="show-word-book">
      <div class="item-content">
          <div class="item-media">
            <i class="f7-icons">book</i>
          </div>
          <div class="item-inner">
              <div class="item-title">
                ${wb.name}
              </div>
              <div class="item-after">
                ${wb.words_count || 0 }単語
              </div>
          </div>
      </div>
    </a></li>`;
  }).join(''));        
},

画面に表示した後、 $$('.show-word-book') に対してタップイベント showWordBook を設定しています。

これは単語帳詳細(単語一覧)画面へ遷移する処理です。

// 選択された単語帳に移動する処理
showWordBook: function(e) {
  // 選択された単語帳のobjectIdを取得
  const objectId = $$(e.target).parents('a').data('object-id');
  if (!objectId) return;
  // objectIdで対象の単語帳を特定
  const wordBook = this.wordBooks.filter(w => w.objectId === objectId)[0];
  // 単語帳データを次の画面に引き継いで移動
  this.$router.navigate(
    /word_books/show,
    {
      context: { wordBook }
    }
  )
},

単語帳登録画面 (word_books/new.html)

では次に単語帳登録画面 pages/word_books/new.html について説明します。

ここでは単語帳の名前を入力する画面を表示します。

<div class="page-content">
  <div class="row">
    <div class="col-auto text-align-center">
      <div class="block-title">単語帳の名前を決めてください</div>
    </div>
    <div class="col-auto">
      <div class="list">
        <ul>
          <li class="item-content item-input">
            <div class="item-inner">
              <div class="item-title item-label">単語帳の名前</div>
              <div class="item-input-wrap">
                <input type="text" name="name">
                <span class="input-clear-button"></span>
              </div>
            </div>
          </li>
        </ul>
      </div>
      <a href="#" class="item-link list-button" @click="saveWordBook">
        <div class="item-inner">
          <div class="item-title">単語帳を作成する</div>
        </div>
      </a>
    </div>
  </div>
</div>

登録の処理は 「@click」 を使って、ボタンタップ時に saveWordBook メソッドを呼び出す指定をしています。

saveWordBook メソッドについて

saveWordBookは入力された単語帳名を、NCMBのデータストアに保存します。

クラス名(データベースのテーブル相当)は、WordBookとしています。
単語帳を作成した時点では単語はないので words_count は0として初期化しています。また、保存後はFramework7のルーティング機能を使って前の画面に戻っています。

// 単語帳を作成する処理
saveWordBook: async function(e) {
  const { ncmb } = this.$app.data;
  // 単語帳のインスタンスを作成
  const wordBook = new (ncmb.DataStore('WordBook'));
  // 必要なデータをセットして保存
  await wordBook
    .set('name', $$('[name="name"]').val())
    .set('words_count', 0)
    .save();
  // 前の画面に戻る
  this.$router.back();
},

これで単語帳の作成処理が完成です。

まとめ

ここまでの流れで単語帳アプリにおける単語帳作成までが完成となります。Framework7はOnsen UI以上にUIコンポーネントが多く、多彩なUIが実現できます。慣れるまで、学習期間が必要だと思いますが、ぜひ試してみてください。

次回は単語の登録と編集、そして学習画面を作っていきます。