まめわざは、Googleが推奨するスマホ向け高速表示規格AMPに対応しています。
Javascriptの利用制限のあるAMPで、動的表現を実現するamp-bindを実装し、カレンダーが次月・前月に移動できるようになりました。
ここでは、amp-bindの実装方法を例とともに解説します。
AMPはAccelerated Mobile Pagesの略で、Googleが推奨するスマホ用のホームページ高速表示の規格です。
この規格に則ったホームページを用意すれば、Google検索結果でホームページをタップした際に、かなりの高速で表示されます。
AMPについては公式サイトの説明やまめわざのブログ記事をご参考願います。
AMPでは、高速表示を実現させるために、Javascriptが利用できない仕様になっています。
画像のカルーセル表示(横スライド)・シェアボタン・Youtubeなど、汎用の動的表現はAMPの仕様に組み込まれており、利用が可能です。
一方で、各ホームページ固有のJavascriptを使った動的表現は利用が出来ませんでした。
最近になって登場したamp-bindは、この汎用型の動的表現とは一線を画す自由度で、「特定ルール内で自由に使えるJavascript」というような位置づけです。
これにより、今回まめわざで実装したカレンダーをめくる(次月・前月に移動する)ような、AMPで提供されていない動的表現が可能になりました。
amp-bindの仕様は公式サイトに詳しく掲載されています(英語)。
Javascriptの多くの部分を削ぎ落とした仕様とあって、大変シンプルです。
イベントに応じて変数を変え、それに応じてタグの属性値を変えます。
「あるイベントに応じて、class="hidden"を付与し、divを非表示化する」といった動作で動的表現を実現します。
まずは以下のscriptタグをhead内に設置してamp-bindを利用可能にします。
<script async custom-element="amp-bind" src="https://cdn.ampproject.org/v0/amp-bind-0.1.js"></script>
次に、amp-bindを構成する以下の3つのパーツについて、例を挙げながら解説します。
以下の例では、{id123:{tab:'a'}}という変数を定義しています。ルートのプロパティ名はamp-stateのid属性でセットします。
<amp-state id="id123">
<script type="application/json">
{"tab":"a"}
</script>
</amp-state>
以下の例では、Bグループというボタン(li)をtapすると、id.123.tabがbに変わります。
<li on="tap:AMP.setState({id123:{tab:'b'}})">Bグループ</li>
以下の例では、id123.tab=bの場合はclass="on"が付与されます。
<li [class]="id123.tab == 'b' ? 'on' : ''">Bグループ</li>
AMPのデバッグは、Google Chromeのデベロッパーツールで行います。
キーボードのF12キー押下でデベロッパーツールを起動させ、デバッグするページのアドレスの末尾に「#development=1」を付与してページを開くと、デベロッパーツールの「Console」に検証結果が出力されます。
<amp-state id="id123">
<script type="application/json">
{"tab":"a"}
</script>
</amp-state>
<ul class="tab">
<li class="on" [class]="id123.tab == 'a' ? 'on' : ''" on="tap:AMP.setState({id123:{tab:'a'}})" role="button" tabindex="0">Aグループ</li>
<li [class]="id123.tab == 'b' ? 'on' : ''" on="tap:AMP.setState({id123:{tab:'b'}})" role="button" tabindex="0">Bグループ</li>
<li [class]="id123.tab == 'c' ? 'on' : ''" on="tap:AMP.setState({id123:{tab:'c'}})" role="button" tabindex="0">Cグループ</li>
</ul>
<div class="contents">
<div [class]="id123.tab != 'a' ? 'hidden' : ''">
Aグループ
</div>
<div class="hidden" [class]="id123.tab != 'b' ? 'hidden' : ''">
Bグループ<br />Bグループ
</div>
<div class="hidden" [class]="id123.tab != 'c' ? 'hidden' : ''">
Cグループ<br />Cグループ<br />Cグループ
</div>
</div>
ul.tabがタブ部分、div.contentsがコンテンツ部分です。
ul.tabをtapすることで、定義したid123.tabの値が変化します。
id123.tabの変化に応じて、ul.tabではliにclass="on"を付与し、div.contentsではclass="hidden"を付与します。
<amp-state id="id777">
<script type="application/json">
{
"apple": {
"src": "amp-bind-img-apple.jpg",
"alt": "美味しそうなリンゴです",
"width": "640",
"height": "428"
},
"banana": {
"src": "amp-bind-img-banana.jpg",
"alt": "食べごろの完熟バナナです",
"width": "640",
"height": "563"
},
"grape": {
"src": "amp-bind-img-grape.jpg",
"alt": "たわわに実ったぶどうです",
"width": "640",
"height": "426"
}
}
</script>
</amp-state>
<div class="image">
<amp-img src="./amp-bind-img-apple.jpg" [src]="'./' + id777[fruit || 'apple'].src" width="640" [width]="id777[fruit || 'apple'].width" height="428" [height]="id777[fruit || 'apple'].height" layout="responsive"></amp-img>
<p [text]="id777[fruit || 'apple'].alt">美味しそうなリンゴです</p>
<ul class="thumbnail">
<li on="tap:AMP.setState({fruit:'apple'})" class="on" [class]="fruit == 'apple' || fruit == null ? 'on' : ''" role="button" tabindex="0"><amp-img src="./amp-bind-img-apple.jpg" width="75" height="50" layout="fixed"></amp-img></li>
<li on="tap:AMP.setState({fruit:'banana'})" [class]="fruit == 'banana' ? 'on' : ''" role="button" tabindex="0"><amp-img src="./amp-bind-img-banana.jpg" width="57" height="50" layout="fixed"></amp-img></li>
<li on="tap:AMP.setState({fruit:'grape'})" [class]="fruit == 'grape' ? 'on' : ''" role="button" tabindex="0"><amp-img src="./amp-bind-img-grape.jpg" width="75" height="50" layout="fixed"></amp-img></li>
</ul>
</div>
div.image内に画像amp-img、画像のキャプションであるp、サムネイル画像リストのul.thumbnailが設置されています。
サムネイル画像をtapすることで、未定義の変数fruitが変化し、これをプロパティ名として代入した各所の属性値が変化します。
この変化により、画像のパス・サイズ、キャプションの文言が変化します。
ここでは、デバッグ時のエラーを回避するために、変数fruitが未定義の場合の処理(「fruit || 'apple'」や「fuit == null」など)を追加しています。
<div class="container">
<amp-state id="id_xyz">
<script type="application/json">
{
"dfn": {
"ja": {
"h2": "夏祭りのお知らせ",
"p": "来週土曜日10:00から市内アーケードにて夏祭りがスタートします。"
},
"en": {
"h2": "Summer Festical",
"p": "Our summer festival will start in the arcade street from 10:00 next Saturday."
}
},
"val": "ja"
}
</script>
</amp-state>
<select on="change:AMP.setState({id_xyz:{val:event.value}})">
<option value="ja">日本語</option>
<option value="en">English</option>
</select>
<h2 [text]="id_xyz.dfn[id_xyz.val].h2">夏祭りのお知らせ</h2>
<p [text]="id_xyz.dfn[id_xyz.val].p">来週土曜日10:00から市内アーケードにて夏祭りがスタートします。</p>
</div>
言語選択用のselectと、メインコンテンツであるh2とpが配置されています。
selectをchangeすることで、定義済みのid_xyz.valが変化し、これをプロパティ名として代入したh2とpが変化します。
[text]属性値は、属性値を変化させる[class]などとは異なり、タグの中身のテキストを変化させます。
この変化により、h2・pの内容が変化します。
amp-bindはまめわざのカレンダー・項目別カレンダーに組み込まれた機能です。
これらのブロックを使用した場合、スマホでGoogleから直接訪問する際に表示されるAMPページを開くと、amp-bindを利用したカレンダーが表示されます。
以上から、「amp-bindを使う」ことを意識する必要はありません。
まめわざでは、amp-bindの利用範囲拡大を検討中です。利用できそうな部分には積極的に導入し、こちらのブログで報告いたします。
amp-bindに限らず、AMPの仕様は整備中のため、新しい機能が次々とリリースされています。まめわざに利用できそうな機能は、今後も導入をしてまいります。