ミギムキ

[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);

サンプルコード解説

読み込み中表示

<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です。