初回のDOM生成のタイミングよりも遅く、後から追加されるDOM要素ってありますよね。
よく外部のCRMツールのスクリプト等が
例えばチャットボットのようなものを後付けで呼び込んでくるのですが、
そういった後から追加されるDOM要素は普通にDOM読み込みを待つJSを書いても、
最初には存在しないものなので、初回読み込みでは対象に含まれず漏れてしまい検出できません。
そんな後出しで追加された要素を検出するのってどうしたらいいの?という疑問にサンプル付きで解説します。
完成コードの前に、今回の設定
仮に、チャットボットを開くためのボタンが常に表示されて邪魔なので非表示にしたい、とします。
そのボタンは、外部ツールのscriptが呼んでくるものなので初回のDOM読み込み時には存在しないので
検出しづらい、という状況を想定しています。
ではどうするのか、ということで次の完成品をご覧ください。
完成版のコード
See the Pen Untitled by takosan (@Yukiwebcreate) on CodePen.
コードの解説
今回scriptに呼ばれて後から挿入されるのはbutton要素の「atokara-btn」くんです。
(実際にscriptに呼ばれてきてるわけではありませんがそういう想定で)
<button class="atokara-btn">チャットボットはこちら</button>
完成コード上ではすぐに削除されて見えないので、画像でご紹介。
こちらの緑のボタンが「atokara-btn」くんです。
この後から追加されたボタンを、どのようにして表示されないようにしているのか詳しく解説していきます。
まずコードの全体像としてはこんな感じ。
document.addEventListener('DOMContentLoaded', function() {
// 処理回数のカウント用
let count = 0;
// 今回のメインプログラム。setIntervalでループを回す
const destroy = setInterval(function() {
// 探す対象をtargetとして定義
const target = document.querySelector('.atokara-btn');
count = count + 1;
// もし見つかったら
if (target) {
// ループを止めて
clearInterval(destroy);
// 消す!
target.style = 'display:none!important';
}
}, 10);
// 5秒待っても対象が見つからなかったら探索を停止
setTimeout(function() {
clearInterval(destroy);
}, 5000);
})
冒頭のaddEventListenner、DOMContentLoadedは初回のDOMの読み込み終わりを待ってから動かすものです。
後から追加される要素はまだここではDOMツリー上に存在しません。
(countはconsoleでlogを確認する用なので、自分の環境で試したい時だけ使ってください)
もう少し中身にズームインしまして、
// 今回のメインプログラム。setIntervalでループを回す
const destroy = setInterval(function() {
// 探す対象をtargetとして定義
const target = document.querySelector('.atokara-btn');
count = count + 1;
// もし見つかったら
if (target) {
// ループを止めて
clearInterval(destroy);
// 消す!
target.style = 'display:none!important';
}
}, 10);
// 下に続く
この部分が今回のメインです。
表示されるボタンを瞬時に消し去りたいので、関数名をわかりやすくdestoryという物騒な名前にしました。
そしてdestroy関数はsetIntervalメソッドを使ってループします。
setIntervalは、設定した時間間隔でプログラムを繰り返し処理させるためのメソッドです。
今回は対象の要素が見つかるまで何度も探してほしいので10ミリ秒間隔で何度もトライするようにしてます。
https://developer.mozilla.org/ja/docs/Web/API/setInterval
setIntervalはclearIntervalとセットで使います。
名前からわかるように、setIntervalで指定したループを止めるメソッドです。
// もし見つかったら
if (target) {
// ループを止めて
clearInterval(destroy);
// 消す!
target.style = 'display:none!important';
}
もし対象が見つかったらif文の中でcleartIntervalでループを止めて、
display:noneとすることで対象を非表示にできます。
100%対象が見つかるならこれだけでもいいです。
が、プログラムには例外がつきもの。これで終わり、と思ってはいけません。
対象が見つからなかった時のことを考えないと、
永久に止まることなく動き続け、負荷をかけまくる悲しきモンスターとなってしまいます。
そこで、setTimeoutメソッドも活用します。
// 上の続き
// 5秒待って対象が見つからなかったら探索を停止
setTimeout(function() {
clearInterval(catchElm);
// console.log("stop");
}, 5000);
setTimeoutは指定の秒数後にプログラムを発火(走らせる)ための遅延メソッドです。
https://developer.mozilla.org/ja/docs/Web/API/setTimeout
今回のケースだと、5000ミリ秒(つまり5秒)後に、ループを中止する処理を書いています。
こうすることで、
5秒以内に見つかれば消すし、見つからなくても5秒立てばそれ以上もう探さない。
という処理が書けたことになりますね。
今回ご紹介したコードを応用すれば大体の後から追加パターンには対応できることでしょう。
async/awaitで書けるともっと正確かと思いますので、さらに知識をつけたい方はこちらもどうぞ!
パターンのひとつとして参考になれば幸いです。
ターゲットを見つけるまで巡回して、見つけ次第”消す”ってことやな。
JavaScriptオススメ書籍
フロントエンドエンドの入門には、こちらの書籍がオススメです。
1冊ですべて身につくJavaScript入門講座こちらはWebクリエイターボックスのManaさんが書かれた書籍で、ポイントは以下のような感じです。
・JavaScriptの基本から実装まで必要なことがすべて学べる
・図解が充実していて読みやすい
・章立てや構成がよくできていてスムーズに読み進められる
・アニメーションやイベントの知識と技術がつまっている
・サンプルプログラムがWeb上からダウンロードできる(自分でコードを用意しなくて良い)
タイトルどおり、一冊でまるっと学べる書籍になっているので、初学者必携の一冊といってもいいでしょう。