[JavaScript] 外部フォーム(formrunなど)の読み込み中表示をしたい
- formrunなどのフォーム作成ツールを使用したとき、フォームの読み込みが気になることがあります
- サイトを設置しているサーバーの状況、接続しているユーザーのネット環境、外部フォームのサービス状況と三つの要因が絡むため、毎回スムーズに読み込み&表示ができるとは限りません
- フォームの読み込みに時間がかかると、最悪ページの不備だと誤解されて直帰してしまうユーザーがいるかもしれません
- 外部フォームの読み込みが完了するまでの間、「読み込み中」の案内を表示する方法を検討してみました
動作イメージ
- 外部フォームを読み込んでいる間、読み込み中である案内を表示
- 読み込みが完了したら案内を消す
サンプルコード
html
<div class="wait_loading">
<div class="wait_loading_message">
<div class="loading">
<span></span>
<span></span>
<span></span>
</div>
<p>フォームの準備中です。しばらくお待ちください。</p>
</div>
<script src="https://sdk.form.run/js/v2/embed.js"></script>
<div
class="formrun-embed"
data-formrun-form="@xxx--0123456789"
data-formrun-redirect="true">
</div>
</div>
CSS
.wait_loading_message {
text-align: center;
}
.wait_loading.js_active .wait_loading_message {
display: none;
}
.loading {
display: flex;
justify-content: center;
}
.loading + p {
margin: 1em 0px 0px;
}
.loading > span {
margin: 0px 10px;
width: 20px;
height: 20px;
border-radius: 50%;
background-color: #888;
animation: loading_anime 1s linear 0s infinite normal both running;
}
.loading > span:nth-of-type(2) {
animation-delay: 0.2s;
}
.loading > span:nth-of-type(3) {
animation-delay: 0.4s;
}
@keyframes loading_anime {
0% {
transform: scale(0);
}
25% {
transform: scale(1);
}
50% {
transform: scale(1);
}
75% {
transform: scale(1);
}
100% {
transform: scale(0);
}
}
Javascript
document.addEventListener('DOMContentLoaded', function() {
const targets = document.getElementsByClassName('wait_loading');
for(let i = 0; i < targets.length; i++) {
const observer = new MutationObserver(mutations => {
for(let j = 0; j < mutations.length; j++) {
const oldValue = mutations[j].oldValue;
if(oldValue != null) {
if(oldValue.indexOf('height: ') !== -1) {
targets[i].classList.add('js_active');
observer.disconnect();
}
}
}
});
observer.observe(targets[i], {
childList: false,
subtree: true,
characterData: false,
attributes: true,
attributeOldValue: true,
attributeFilter: ['style']
});
}
}, false);
サンプルコード解説
- 今回、外部フォームの読み込みが完了したかどうかの判定を「MutationObserver」という仕組みを使って実現しています
- 「MutationObserver」は、DOMの変化(スタイルの変化、要素の増減など)を監視し、変化があったときにコールバック関数を実行してくれるAPIです
- このAPIを使って、要素の高さ(height)を監視し、フォームの読み込みが完了して高さが増えたタイミングで読み込み中表示を消すという処理を行います
読み込み中表示
<div class="wait_loading_message">
<div class="loading">
<span></span>
<span></span>
<span></span>
</div>
<p>フォームの準備中です。しばらくお待ちください。</p>
</div>
- フォームの読み込み中表示をする要素です
- 読み込みが完了したときに「wait_loading_message」クラスを非表示にします
- 「loading」クラスで読み込み中のアニメーション表示をしています。このアニメーションの作りについてはこちらの記事で解説しています
- 「loading」クラスをimgタグに置き換えてアニメーションGIF画像を使ってもOKです
外部フォームの設置
<div class="wait_loading">
〜
<script src="https://sdk.form.run/js/v2/embed.js"></script>
<div
class="formrun-embed"
data-formrun-form="@xxx--0123456789"
data-formrun-redirect="true">
</div>
</div>
- 外部フォームのソースコードは「wait_loading」クラスの中に配置します
- サンプルコードではformrunを使ったフォームの設置例になっています
要素の高さが変わったときの処理
const observer = new MutationObserver(mutations => {
for(let j = 0; j < mutations.length; j++) {
const oldValue = mutations[j].oldValue;
if(oldValue != null) {
if(oldValue.indexOf('height: ') !== -1) {
targets[i].classList.add('js_active');
observer.disconnect();
}
}
}
});
- 「MutationObserver」の生成処理です
- 生成処理の引数として、状態変化が発生したときに実行するコールバック関数を設定します
- コールバック関数では、どの要素がどう状態変化したか設定されている配列「mutations」の内容をチェックします
- 「mutations」は以下のような内容になっています。色々な情報がありますが、今回は変化前の属性情報が保持されている「oldValue」を使用します
- 「oldValue」は「スタイル名: 値; スタイル名: 値;」といった形式で変化のあったスタイルが列挙されています
if(oldValue.indexOf('height: ') !== -1) {
targets[i].classList.add('js_active');
observer.disconnect();
}
- 「oldValue」の中に要素の高さである「height」があるかをチェックします
- 「height」があれば、要素の高さが変化した=フォームの読み込みが完了したものとして、「wait_loading」クラスに「js_active」クラスを付与します
- 最後に「observer.disconnect();」で状態変化の監視を終了します
observerに監視する情報を設定する
observer.observe(targets[i], {
childList: false,
subtree: true,
characterData: false,
attributes: true,
attributeOldValue: true,
attributeFilter: ['style']
});
- 生成した「MutationObserver」の監視を開始する処理です
- 第一引数に、監視対象となる要素(ここでは「wait_loading」クラスが設定されたdiv要素)を指定します
- 第二引数に、監視対象とするものを指定した配列を設定します。今回はstyle属性だけを監視すればよいので、以下のように設定しています
- childList
-
- 要素(ノード)の追加や削除を監視するかどうか設定する値
- 今回は不要なので「false」にします
- subtree
-
- 監視対象として設定した要素の子孫要素まで監視対象に含めるかどうかを設定する値
- 今回、フォームの読み込みによる要素の高さの変化を監視する場合、実際に「height」が変化するのは「wait_loading」の中にある「iframe」タグとなります(formrunの場合)
- 「iframe」タグの高さが変わることで、結果的に「wait_loading」の高さも変わりますが、それは「wait_loading」の状態変化としては扱われず、通知が飛びません
- よって、この設定値が「false」では高さの状態変化が監視できないため。「true」にしておく必要があります
- characterData
-
- 要素のデータ(内容)の変化を監視するかどうか設定する値
- 今回は不要なので「false」にします
- attributes
-
- 要素の属性の変化を監視するかどうか設定する値
- 今回監視したい情報なので「true」にします
- attributeOldValue
-
- 状態変化時の通知情報に変化前の属性情報を含めるかどうか設定する値
- この値が「true」になっていないと、コールバック関数で渡される配列に「oldValue」が含まれなくなってしまいます
- 「height」が変化したかどうかを特定するために必要となるため「true」にしておく必要があります
- attributeFilter
-
- 状態変化を通知する属性情報の絞り込みをする値
- 今回は「style」属性の監視だけでよいため「style」と設定しています
ご質問など受け付けています
記事の中でわかりにくかったところ、もっと知りたかったこと、間違っていることなど、何でもお気軽にご連絡ください。
ご連絡は下記フォームを利用いただくか、ツイッターアカウント@flat8migi宛てでもOKです。