コンテンツへスキップ

hifive と Onsen UIを組み合わせてスマートフォン/タブレット向けのUIを簡単に実現する(タブ & ナビゲーション)

Onsen UIというモバイルアプリ向けのUIフレームワークがあります。HTML5とJavaScript、CSSを使ってスマートフォンアプリを作るハイブリッドアプリ用のUIフレームワークになります。UIをネイティブアプリ風にしてくれるのはもちろん、画面のスワイプであったり、リスト表示などをネイティブアプリ風の操作にしてくれます。

そんなOnsen UIをhifiveと組み合わせて使う方法を紹介します。今回はタブバーとナビゲーションを組み合わせた使い方を紹介します。

利用するソフトウェア/ライブラリ

  • Bower
  • hifive
  • Onsen UI
  • jQuery

インストール

まず各ライブラリをインストールします。インストールはBowerを使って行います。

今回は .bowerrc という設定ファイルを作成し、ライブラリのインストール先を指定しています。

index.htmlの作成

次に public/index.html を作成します。タブバーを定義します。

タブバーの画面

まず最初に表示される tab1.html の画面を用意します。タブ1の中身でナビゲーションを行いますので、ここではナビゲーションだけを定義します。

そして最初に表示するのは tab1-main.html です。

JavaScriptの実装

まずメイン画面でボタンを押したら詳細画面に移動する部分を作ります。 tab1MainController を定義します。そしてナビゲーションのpushPageを使って画面遷移します。

ここでヘッダー部の文字を詳細に変えるようにイベントを設定します。コントローラのトリガーを使います。

トリガーは js/app.js 内に定義する全体のコントローラに実装します。 {rootElement} changeTitle でイベントを受け取ることができます。

なお、 Tab1Controller と Tab2Controller は別な画面に定義されています。そのため、変数が定義されているかどうかを確認する必要があります。今回は以下のような仕組みで回避しています。変数があるかどうか調べて、なければ100ms待って変数の確認をしています。

画面遷移を戻る

詳細画面に移動したら、逆に戻ってくる処理を作ります。これは tab1-detail.html に実装します。こちらでもトリガーを使っています。

ここまでの処理でタブバーとナビゲーションバーを組み合わせた処理が実現します。


タブバーとナビゲーションバーを組み合わせた動きはスマートフォンアプリでよくある実装だと思います。hifiveのコントローラ連携を使うことで、機能を画面毎に分けつつ、分かりやすい実装が実現します。

コードはhifiveWithOnsenUI/tabbar_navigation at master · hifivemania/hifiveWithOnsenUIにアップロードされています。実装時の参考にしてください。

13.コントローラの連携 – hifive

jQueryの代わりにdocument.querySelectorを使う

jQueryはIDやクラスを指定してDOMエレメントが取得できるので便利に使っている人は多いかと思います。しかし、DOMの取得だけであれば素のJavaScriptでも簡単にできます。それがdocument.querySelectorです。

他にもIDを指定する document.getElementById 、クラスを指定する document.getElementsByClassName 、タグ名を指定する document.getElementsByTagName など何種類もあるのが分かりづらさを感じさせる原因ですが、document.querySelector と document.querySelectorAll はすべてを兼ね備えます。

ということで今回は document.querySelector / document.querySelectorAll の使い方を紹介します。

document.querySelector と document.querySelectorAll の違い

二つのメソッドの違いは返ってくるのが複数かどうかです。 document.querySelector は最初の一つしか返ってきません。クラスやリストを指定しても最初の一つだけです。それに対して document.querySelectorAll は一致するDOMすべてが返ってきます。

document.querySelectorの使い方

document.querySelector は引数にCSSセレクタを指定します。これはjQueryで使ってきたものをそのまま使えます。

返ってくるのはDOMです。

ない時には nullが返ってくる

注意点としては該当するDOMがなかった場合には null が返ってくるので、メソッドチェーンが使えません。それに対してjQueryの場合はメソッドチェーンが可能です。

これをいちいち判定しながら作るのはちょっと面倒でしょう。

簡単な関数でラップする

そこで document.querySelector を直接使わず、簡単な関数でラップしてあげます。

これはごくごく簡単な例ですが、存在しないCSSセレクタを指定してもある程度のメソッドチェーンが書けるようになります。


document.querySelectorやdocument.querySelectorAll、そしてそれがエラーを起こさないためのやり方さえ覚えてしまえばjQueryを使うことなくDOM操作を行えるようになります。jQueryは他にもたくさんの機能があって便利ですがAngularやReact、Vueとの相性が良くなかったり、使っていない機能の方が多くなりがちです。jQueryで使っているのがDOM操作ばかりだ…という方はdocument.querySelectorに乗り換えても良いでしょう。

GoではじめるWebAssebmly その2「JavaScriptイベントハンドリング」

WebAssebmlyはWebブラウザ上でバイナリファイル(テキスト形式もあり)を実行できる環境です。JavaScriptと異なりコードの漏洩がなく、実行速度も高速というのがメリットです。

WebAssebmlyは元々Rustで開発することが多かったですが、最近では様々なプログラミング言語が対応しています。その一つがGoです。Go 1.11からWebAssembly向けにもコンパイルできるようになっています。

一般的なWebAssemblyはDOMやネットワーク操作が行えません。それに対してGo 1.11ではJavaScript APIを使えるようにした syscall/js パッケージを用いることで、DOMやネットワーク操作を可能にしています。

そこで今回はDOMのクリックイベントをWebAssemblyで扱う方法を紹介します。

まずGoのコードです。今回はmain.goとしています。最初に syscall/js をインポートします。

そして、トップレベルのDOMであるドキュメントを作成します。

IDやクラスを使ってDOMを取得します。

取得したボタンに対してコールバックを指定します。

ボタンのクリックイベントにコールバックを指定します。

最後にプログラムが終了しないようにチャネルを待ち受けます。

これで完成です。全体のコードは次のようになります。

HTMLを準備する

HTMLはボタンを貼り付けだけのものです。

JavaScriptファイルを用意する

専用のJavaScriptファイルを設置します。

Goをコンパイルする

最後にGoファイルをコンパイルして WebAssebmly化します。

サーバを立ち上げる

Webサーバは goexec を用います。インストールは go get -u github.com/shurcooL/goexec になります。インストールされたら以下のコマンドでHTTPサーバを立ち上げます。

これで http://localhost:8080/ でアクセスできます。

試す

では実際に試しているところです。ボタンをクリックすると開発者ツールのコンソールにログが出力されます。

このようにしてGoのコードからイベントハンドリングができます。


Goを使うことでWebアプリケーションをまるっとWebAssemblyで提供できる可能性が出てきました。高速、かつコードの隠蔽化も実現しますのでWebアプリケーションの可能性を飛躍的に向上できるでしょう。

ぜひトライしてみてください。

GoではじめるWebAssebmly その1「Hello World」

WebAssebmlyはWebブラウザ上でバイナリファイル(テキスト形式もあり)を実行できる環境です。JavaScriptと異なりコードの漏洩がなく、実行速度も高速というのがメリットです。

WebAssebmlyは元々Rustで開発することが多かったですが、最近では様々なプログラミング言語が対応しています。その一つがGoです。Go 1.11からWebAssembly向けにもコンパイルできるようになっています。

この記事ではWebAssembly · golang/go Wikiに沿ってGoでWebAssemblyを実行するまでを紹介します。

環境

WebAssebmlyはモダンなWebブラウザが対応していますが、Goが提供するJavaScriptコードがSafariでは動きませんでした。以下はGoogle Chromeで試しています。

Goのコード

今回はとてもシンプルなコードです。 main.go として作成します。

このコードをGoでコンパイルします。

これで main.wasm というファイルが作成されます。

HTMLについて

HTMLはテンプレートになっており、以下を使います。

JavaScriptについて

WebAssebmlyを解釈するのにGoが提供しているJavaScriptライブラリを使います。

この3つのファイルで実行します。

goexecのインストール

HTTPサーバを立てる必要があるので、goexecをインストールします。

これで準備完了です。

実行する

HTTPサーバを立てます。

http://localhost:8080/ でHTTPサーバが立ち上がるので、Google Chromeからアクセスします。

開発者ツールのコンソールに Hello, WebAssembly! と出力されれば完成です。


GoでWebAssemblyを書く場合、特別なテクニックが必要という訳ではありません。普段のGoの書き方で、コンパイル方法を指定するだけです。Goであれば、よりモダンな書き方でWebAssemblyが使えるようになりますのでお勧めです。

PWAでWeb APIを使う際の注意点

Webアプリにおいて、Web APIを使わないことはほぼ皆無でしょう。PWAにおいてももちろん同じようにWeb APIを使って実装されるでしょう。しかし、幾つかのハマりどころがあるので注意が必要です。

キャッシュ時にはヘッダー情報などが使われない

キャッシュは以下のようなフォーマットで実装されます。

 

単純にURLをキーとして、そのレスポンスを登録するだけなので、Web APIアクセスする際にヘッダー情報を追加したり、細かなカスタマイズができません。そこで、ネットワークが使える際にコンテンツをWebブラウザ側で取得し、その結果をService Workerで登録します。

例えばレスポンスが req 、結果が body という変数であったならば、以下のように Service Workerを呼び出します。

 

 

そしてService Worker側でコンテンツを保存します。Responseオブジェクトを使ってレスポンスを動的に作るのがコツです。Webブラウザ側のResponseオブジェクトをそのまま渡せないので注意してください。

 

 

 

こうすると、該当URLへのアクセスすると、ヘッダー情報を無視して結果が取得できます。HTTPメソッドも無視されるので注意してください。

ただし、この方法だとオンライン時のキャッシュの更新が必要で複雑になりすぎる可能性があったり、検索のようにクエリーが動的に変わる場合に対応できないでしょう。

navigator.onLineを使う

もう一つはnavigator.onLineを使って、オンラインの場合はWeb APIを呼び出して、オフラインの場合は自作のキャッシュを使う方法があります。キャッシュはネットワークアクセスの結果をlocalStorageやIndexedDBに保存すれば良いでしょう。

この方法の場合はオンライン、オフライン時の条件分岐が増えてしまう問題があります。できればクラスでラッピングし、アプリケーションからはネットワークの状態を気にせずに利用できるようにするのが良いでしょう。

この方法の利点はHTTPメソッドごとの処理を細かく制御できることで、同じURLになりがちな一覧の取得とデータ作成(GET / と POST /)を分けられることです。


PWAにおいてはネットワークの状態をきちんと制御するのが肝になるでしょう。それによってユーザ体験が大きく変わってきます。ユーザが不自然に感じたり、使いづらいと感じないシステムを作るためにも、キャッシュを上手に活用しましょう。

複雑なService Workerを作る際にはimportScriptsを使おう

Service WorkerはWebブラウザ側で実行されるJavaScript(メインスレッド)とは別で実行されます。バックグラウンド処理に使うこともできますし、メインスレッドで行うと画面が固まってしまうような重たい処理を実行させることもできます。

そんなService Workerを活用していく中で、処理が肥大化していくならば別ファイルとして切り出していきましょう。その際に使えるのがimportScriptsです。

importScriptsの使い方

例えばメインスレッド側のJavaScriptでは次のように処理を書きます。

そしてService Worker(sw.js)を以下のように記述します。

self.importScripts という書き方もありますが、どちらも同じ意味です。 import.js は以下のように記述します。

こうすることで、外部ファイルを読み込んでService Workerの中で利用できます。なお、複数ファイルの読み込みも可能です。

読み込みは同期処理

コードを見て分かる通り、importScripts は同期処理で実行されます。読み込み完了時のコールバックもなく、返り値がPromiseな訳でもありません。さらに言えば、インポートされるファイルで最後に return を書いたり、moduleexport は使えません。

読み込まれるファイルの特徴

インポートされるファイルは元ファイルと同じく self が使えます。これは ServiceWorkerGlobalScope であり、IndexedDB も利用可能です。また、インポートされるファイルを編集しても、元になるService Workerファイルが更新されていないとWebブラウザは更新してくれませんので注意してください。


importScriptsを使うことで、メインスレッドとワーカースレッドで同じライブラリを活用できるようになるでしょう。特に重たい計算処理の伴うようなものについては、ワーカースレッドで計算して結果だけメインスレッドで受け取って描画するといった使い分けもできそうです。

Pitalium ExplorerをDockerで動かす

先日Pitaliumがmavenに登録されたことで使い始める敷居がぐっと下がりました。そこで前回はPitaliumがMaven対応したのでDockerと組み合わせて使ってみる | hifive開発者ブログとして、PitaliumをDockerベースで試す方法を紹介しました。

Pitaliumの動作自体はDockerで完結しますが、その結果ファイルを確認するPitalium Explorerはこのままでは使えません。Pitalium ExplorerのためにJavaやTomcatをセットアップするのは面倒ははずです。そこでDockerを使ってPitalium Explorerを簡単に試せるようにしましょう。

Dockerfileについて

最初に答えを書いてしまうと次のようになります。

ベースになるのはlibrary/tomcat – Docker Hubです。公式イメージなので安心です。そしてDockerの中でPitaliumのZipファイルをダウンロードして展開、その中にあるPitalium Explorerのwarファイルを展開して設定ファイルを書き換えます。それをTomcatのwebappsフォルダに配置します。

ビルド

Dockerfileをダウンロードしたら、ビルドを実行します。

$ docker build . -t pitalium-explorer:latest

これで完了です。

使い方

Pitalimの結果ファイルがあるresultsフォルダと同じ階層に移動してDockerを実行します。

$ docker run -it --rm -p 8888:8080 -v $PWD/results:/usr/results pitalium-explorer

これで results フォルダがDockerコンテナの/usr/resultsに配置されます。このディレクトリはPitaliumの設定ファイルで指定しています。

Webブラウザで http://localhost:8080 を開くとPitalium Explorerの画面が表示されるはずです。

Pitalium Explorer

結果の確認も特に問題なく行えるでしょう。

Pitalium Explorerの結果確認


Dockerを使っていますのでローカルの環境を汚すことなくセットアップが行えます。PitaliumをDockerで使う際には、ぜひこの方法でPitalium ExplorerもDocker化して使ってみてください!

Pitalium(hifiveリグレッションテストライブラリ) – hifive