Onsen UI + Monacaでクイズアプリを10分で作る

  • 3
    いいね
  • 0
    コメント

:christmas_tree:Onsen UI Advent Calendar 2016:christmas_tree: 10日目の記事です。

前回、Onsen UIを使うと手軽でかつスピーディにアプリが作れるよーということを書きました。
今回は本当にサクッと作れるのかどうか実証してみましょうということで、簡単なクイズアプリを10分で作ってみました。

環境構築を時短するためにMonaca上でアプリを作ります。
Monacaで「Onsen UI V2 JS Minimum」テンプレートを選択し、新規作成したプロジェクトを開いたところからチャレンジスタートです!

動画

(お急ぎの方は適当に飛ばし飛ばし見ても問題ないです)


8分44秒で作れました:grinning:
チャレンジ成功!

以下がソースコード全文です。

index.html
<!DOCTYPE HTML>
<html>
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
  <meta http-equiv="Content-Security-Policy" content="default-src * data:; style-src * 'unsafe-inline'; script-src * 'unsafe-inline' 'unsafe-eval'">
  <script src="components/loader.js"></script>
  <script src="lib/onsenui/js/onsenui.min.js"></script>

  <link rel="stylesheet" href="components/loader.css">
  <link rel="stylesheet" href="lib/onsenui/css/onsenui.css">
  <link rel="stylesheet" href="lib/onsenui/css/onsen-css-components.css">
  <link rel="stylesheet" href="css/style.css">

  <script>
    var questions = [
        {
            title: "段落を表すタグはどれ?",
            answer: ["body", "img", "a", "p"],
            correct: 3
        },
        {
            title: "画像を表すタグはどれ?",
            answer: ["body", "img", "a", "p"],
            correct: 1
        },
        {
            title: "リンクを表すタグはどれ?",
            answer: ["body", "img", "a", "p"],
            correct: 2
        }
    ];
    var score = 0;
    var current = 0;

    document.addEventListener("init", function(event) {
        var page = event.target;
        if(page.id === "question-page") {
            var title = "第" + (current+1) + "問:" + questions[current].title;
            page.querySelector("#title").textContent = title;

            var btns = page.querySelectorAll(".btn");
            btns.forEach(function(target, index) {
                target.textContent = questions[current].answer[index];
                target.addEventListener("click", function() {
                    var icon;
                    if(index === questions[current].correct) {
                        icon = "circle-o";
                        score++;
                    } else {
                        icon = "ion-close";
                    }

                    var navi = document.querySelector("#navi");
                    navi.pushPage("result.html")
                    .then(function(page) {
                        page.querySelector("#result-icon").setAttribute("icon", icon);
                        page.querySelector("#next-btn").addEventListener("click", function() {
                            current++;
                            if(current < questions.length) {
                                navi.pushPage("question.html");
                            } else {
                                var msg = questions.length + "問中" + score + "問正解でした!";
                                ons.notification.alert(msg);
                                current = 0;
                                score = 0;
                                navi.resetToPage("question.html");
                            }
                        })
                    })
                })
            })
        }
    })
  </script>
</head>
<body>
    <ons-navigator id="navi" page="question.html"></ons-navigator>
    <ons-template id="question.html">
        <ons-page id="question-page">
            <h1 id="title">タイトル</h1>
            <ons-list>
                <ons-list-item modifier="longdivider">
                    <ons-button modifier="large" class="btn">XXX</ons-button>
                </ons-list-item>
                <ons-list-item modifier="longdivider">
                    <ons-button modifier="large" class="btn">XXX</ons-button>
                </ons-list-item>
                <ons-list-item modifier="longdivider">
                    <ons-button modifier="large" class="btn">XXX</ons-button>
                </ons-list-item>
                <ons-list-item modifier="longdivider">
                    <ons-button modifier="large" class="btn">XXX</ons-button>
                </ons-list-item>
            </ons-list>
        </ons-page>
    </ons-template>
    <ons-template id="result.html">
        <ons-page id="result-page">
            <div style="text-align:center;height:300px">
                <ons-icon icon="circle-o" size="300px" id="result-icon"></ons-icon>
            </div>
            <ons-button id="next-btn" modifier="large">次へ</ons-button>
        </ons-page>
    </ons-template>
</body>
</html>

しかし後から気づいたんですが、iPhoneだと選択肢のボタンが動かない……:disappointed_relieved:
どうもiPhone(iPhone SE/iOS10.1.1の環境でテストしました)のブラウザでは、NodeListのforEachがまだ実装されていないようです。
iPhoneでも動くようにするには 43行目 のソースコードを以下のように変更する必要があります。

変更前
btns.forEach(function(target, index) {
変更後
Array.prototype.forEach.call(btns, function(target, index) {

あと、結果のページに移動したときに、〇または×のアイコンが表示されるまでに少しタイムラグがあるために「次へ」ボタンが下にカクッと動いてしまうのがかっこ悪いですね。
あらかじめ 100行目 にあるアイコン表示エリアの高さを固定しておいたほうが良さそうです。

変更前
<div style="text-align:center">
変更後
<div style="text-align:center;height:300px">

まとめ

今回作成したのは簡単なサンプルアプリでしたが、スクラッチ開発で10分かからずにアプリを完成させるところまで持っていけるというのは、かなりすごいのではないでしょうか?
Onsen UIを使えば、素早く効率的にアプリ開発ができる、ということが伝わっていれば幸いです。

最後にOnsen UI Advent Calendar 2016 について、、、前半は隙間なく埋まっていましたが後半がスカスカですー!:scream:
(いるかわかりませんが)書いてみたいけど特にネタがないよーという方、あなたも10分チャレンジやってみませんか!
皆さまのご参加をお待ちしています!

この投稿は Onsen UI Advent Calendar 201610日目の記事です。