こんにちは!
さて今回はMagentoのローディング表示制御のカスタマイズ編です。
前回、前々回ではMagentoに標準で用意されている初歩的な使い方やAjaxでの便利な呼び出し方法についてご紹介しましたが、mage/loaderはローディング表示の内容をカスタマイズしたり特定の領域に対してマスクをかけたりすることが出来ますので今回はその方法について触れたいと思います。
特定の領域にローディングマスクを表示する
動的に画面書き換えを行うときなどで特定の領域にローディングマスクを表示したい場合があると思います。そのやり方について解説したいと思います。早速サンプルを作成してみましょう。
基本編で作成したサンプルを下記の様に変更してローディングマスクを表示する領域などを用意します。#fs-loading-overlay-custom-container がローディングマスクを表示する領域の要素です。
ブロックのテンプレート
app/code/FutureSpirits/LoadingOverlay/view/frontend/templates/loading-overlay.phtml
<p>
<div id="fs-loading-overlay-custom-container">
<p>ここにローディングオーバーレイが表示されます。ここにローディングオーバーレイが表示されます。ここにローディングオーバーレイが表示されます。ここにローディングオーバーレイが表示されます。</p>
<button type="button" id="fs-loading-overlay-btn">
ローディングのテスト
</button>
</div>
</p>
<script type="text/javascript">
require(['jquery', 'FutureSpirits_LoadingOverlay/js/loading-overlay']);
</script>
次に、#fs-loading-overlay-custom-container 要素を指定してmage/loaderを初期化します。初期化の際はローディングアイコンを指定しておきます。
Javascriptソースコード
app/code/FutureSpirits/LoadingOverlay/view/frontend/web/js/loading-overlay.js
define([
'jquery',
'mage/loader'
], function ($) {
'use strict';
// ローディングマスクを表示する領域の要素を取得
var $customContainer = $('#fs-loading-overlay-custom-container');
// ローディングマスクを初期化
$customContainer.loader({
icon: require.toUrl('images/loader-1.gif')
});
$('#fs-loading-overlay-btn').on('click', function () {
// ローディングを表示
$customContainer.trigger('processStart');
// 3秒後にローディングを非表示
setTimeout(function () {
$customContainer.trigger('processStop');
}, 3000);
});
});
このようにすることで要素に対してローディングマスクを初期化&バインドし、その要素のprocessStartのイベントをトリガーすることで指定領域にローディングマスクを表示することが出来ます。
ただしこのままだと、マスクが画面全体に表示されてしまい指定要素のところに表示されません。これは、Magentoの標準のテーマによってローディングマスクが常に画面全体を覆うようにスタイル定義されているためです。
そこで特定領域に使用するマスクに対して親要素と子要素のpositionを調整して親要素を基準に被さるようにします。下記の例では_module.lessでスタイルの一部を変更しています。
スタイルのオーバーライド
app/code/FutureSpirits/LoadingOverlay/view/frontend/web/css/source/_module.less
#fs-loading-overlay-custom-container {
position: relative;
.loading-mask {
position: absolute;
.loader {
> img {
position: absolute;
}
}
}
}
これで特定の要素に対してマスクがされるようになりました。
ソースコードをサーバーにアップロードして適用します。
サンプルの画面はこのようになります。
ボタンを押すと指定の領域にローディングマスクが表示されます。ローディングアイコンも指定のものに置き換わっています。
Ajax送信時に表示させるには
先ほど実装したカスタムのローディングマスクをAjax送信時にも利用してみましょう。
Ajax編で説明した実装方法に従いクリックイベントを下記の様にします。ポイントはloaderContext オプションを使って先ほど初期化して用意した要素を指定することです。こうすることでカスタマイズで用意したローディングマスクを使用することが出来ます。
Javascriptソースコード
app/code/FutureSpirits/LoadingOverlay/view/frontend/web/js/loading-overlay.js
define([
'jquery',
'mage/loader'
], function ($) {
'use strict';
// ローディングマスクを表示する領域の要素を取得
var $customContainer = $('#fs-loading-overlay-custom-container');
// ローディングマスクを初期化
$customContainer.loader({
icon: require.toUrl('images/loader-1.gif')
});
$('#fs-loading-overlay-btn').on('click', function () {
$.ajax({
url: '/rest/V1/some/endpoint', // 適切なエンドポイントに置き換えてください
method: 'GET',
showLoader: true, // これを指定するだけで自動的にローディングが表示される
loaderContext: $customContainer // ローディング表示に使用する要素を指定
})
.done(function () {
// 正常時の処理
})
.fail(function () {
// エラー時の処理
});
});
});
ボタンを押すとAjax通信が行われその際にカスタマイズで用意したローディングマスクが表示されます。
ここまでで簡単なカスタマイズ表示の方法を解説しました。このほかにもオプション指定によって様々なカスタマイズが可能です、Magentoでデフォルト定義されているオプションの内容にも触れておきたいと思います。
ローディングマスクのオプションと規定値
mage/loaderは初期化する際に様々なオプションでローディング表示の内容をカスタマイズ指定することが出来ます。先ほどの例ではアイコンのみ指定しました。HTMLテンプレート自体をカスタマイズする事も可能なので多彩なローディングマスクを表現する事が出来ます。
オプション
texts:
loaderText: 表示されるメッセージテキスト ※2
imgAlt: アイコン画像のalt属性のテキスト ※3
template: ローディング時に表示されるHTMLテンプレート
※1,2,3はテンプレート内に<%- data.~ %>で差し込まれる変数です
ソースコードでは下記の様にデフォルト定義されています。
lib/web/mage/loader.js
~(略)~
$.widget('mage.loader', {
loaderStarted: 0,
options: {
icon: '',
texts: {
loaderText: $.mage.__('Please wait...'),
imgAlt: $.mage.__('Loading...')
},
template:
'<div class="loading-mask" data-role="loader">' +
'<div class="loader">' +
'<img alt="<%- data.texts.imgAlt %>" src="<%- data.icon %>">' +
'<p><%- data.texts.loaderText %></p>' +
'</div>' +
'</div>'
},
~(略)~
iconはデフォルトでは空となっていますが、Magentoでは初期化の際にlib/web/images/loader-2.gifが指定されています。(詳しくは下記)
テンプレートの基礎に当たるroot.phtmlで、Bodyの定義にのところdata-mage-initでloaderの初期化が行われておりその中でiconの値に$loaderIconを渡しています。
vendor/magento/module-theme/view/base/templates/root.phtml
x<?php
/**
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
?>
<!doctype html>
<html <?= /* @noEscape */ $htmlAttributes ?>>
<head <?= /* @noEscape */ $headAttributes ?>>
<?= /* @noEscape */ $requireJs ?>
<?= /* @noEscape */ $headContent ?>
<?= /* @noEscape */ $headAdditional ?>
</head>
<body data-container="body"
data-mage-init='{"loaderAjax": {}, "loader": { "icon": "<?= /* @noEscape */ $loaderIcon ?>"}}'
<?= /* @noEscape */ $bodyAttributes ?>>
<?= /* @noEscape */ $layoutContent ?>
</body>
</html>
$loaderIcon は、下記のソース内で指定されていてimages/loader-2.gif を指すようなっています。
vendor/magento/framework/View/Result/Page.php の function render()内
protected function render(HttpResponseInterface $response)
{
$this->pageConfig->publicBuild();
if ($this->getPageLayout()) {
$config = $this->getConfig();
$this->addDefaultBodyClasses();
$addBlock = $this->getLayout()->getBlock('head.additional'); // todo
$requireJs = $this->getLayout()->getBlock('require.js');
$this->assign([
'requireJs' => $requireJs ? $requireJs->toHtml() : null,
'headContent' => $this->pageConfigRenderer->renderHeadContent(),
'headAdditional' => $addBlock ? $addBlock->toHtml() : null,
'htmlAttributes' => $this->pageConfigRenderer->renderElementAttributes($config::ELEMENT_TYPE_HTML),
'headAttributes' => $this->pageConfigRenderer->renderElementAttributes($config::ELEMENT_TYPE_HEAD),
'bodyAttributes' => $this->pageConfigRenderer->renderElementAttributes($config::ELEMENT_TYPE_BODY),
'loaderIcon' => $this->getViewFileUrl('images/loader-2.gif'),
]);
$output = $this->getLayout()->getOutput();
$this->assign('layoutContent', $output);
$output = $this->renderPage();
$this->translateInline->processResponseBody($output);
$response->appendBody($output);
} else {
parent::render($response);
}
return $this;
}
また、テーマで一部の要素にスタイルが定義されているので、ローディングマスクのカスタマイズを行う際は必要に応じてオーバーライドで定義し直す必要があります。特にテンプレート内の<p>タグが非表示になっていたりするのでテキストメッセージを表示したい場合はこれを調整する必要があります。
vendor/magento/theme-frontend-blank/web/css/source/_loaders.less
~(略)~
.loading-mask {
.lib-loading-mask();
background: rgba(255, 255, 255, .5);
.loader {
> img {
.lib-loading-mask();
}
> p {
display: none;
}
}
}
body {
> .loading-mask {
z-index: @loader-overlay__z-index;
}
}
~(略)~
まとめ
基本編、Ajax編、カスタマイズ編と解説してきましたが、簡易なものから任意のカスタマイズまで必要に応じて自由度の高いローディングマスクに対応できるのは便利ですね。
- bodyのprocessStartをトリガーするだけでローディングマスクを表示できる - 基本編
- Ajaxでは、showLoader: true をオプション指定するだけで良い - Ajax編
- 任意に要素に初期化&バインドしてカスタマイズが可能
- 初期化した要素のprocessStartをトリガーして表示可能
- AjaxではloaderContextオプションに初期化した要素を指定する
- カスタマイズ表示ではスタイル定義に注意する
カスタマイズ表示をしたい場合は、Magentoのテーマで指定されているスタイル定義が邪魔になる場合があるので注意して実装してみてください。