ある要素が表示されるまで待つJSライブラリを書いた(MutationObserver)
wait-for-element.js
wait-for-element.js という関数一個だけのライブラリを書きました。
以下のような感じで、セレクタにマッチする要素が出現するまで待つというシンプルな関数です。
var waitForElement = require("wait-for-element");
waitForElement("#js-element").then(function (element) {
alert("Found #js-element");
}).catch(console.error.bind(console));
インストール
npm からインストールできます。
npm install wait-for-element.js
使い方
waitForElement(selector, [timeout])
という感じで使います。
waitForElement()
はPromiseを返すので、見つかったthen
で登録したコールバックが呼ばれて、見つからなかったらcatch
が呼ばれるという感じです。
Promiseについて詳しくはJavaScript Promiseの本を見てください
/**
* Wait until an element that is matched the selector is visible.
* @param {string} selector the css selector
* @param {number} timeout the timeout is millisecond. default:2000ms
* @returns {Promise}
*/
var waitForElement = require("wait-for-element");
waitForElement("#js-element").then(function (element) {
alert("Found #js-element");
}).catch(console.error.bind(console));
Example of wait-for-element.js か以下にブラウザで動かせるサンプルがあるので試してみるとわかりやすいです。
依存
- Promise API
Promiseがある前提のライブラリになってるので、Promiseない環境では先にES6-Promiseなどを入れるといいと思います。
実際にテストコードではPhantomJSなどでも動かしてるのでpolyfillを入れています。
- MutationObserver or SetTimeout polling
wait-for-element.jsはMutationObserverとsetTimeoutによるポーリングの2つの実装を持っています。
feature detectionをして、MutationObserverが使えるならこっちを使うようになってます。
- Element.matches
ある要素があるセレクタにマッチするかはElement.matches()を使っています。
古いブラウザだと名前が違ったりするのでaliasを貼るかpolyfillを使う必要があるかもしれません。
if (Element && !Element.prototype.matches) {
var proto = Element.prototype;
proto.matches = proto.matchesSelector ||
proto.mozMatchesSelector || proto.msMatchesSelector ||
proto.oMatchesSelector || proto.webkitMatchesSelector;
}
何か色々新しめのAPIを使ってる感じがしますが、実際のwait-for-element.jsの使いドコロとしてはGreasemonkeyやブラウザ拡張などだと思うので、基本的にpolyfillなくても良い場合が多そうな気がします。
テスト
テストは以下のように実行できますが、Test Runnerにはtestemを使っています。(最近メンテナが増えたのでリリースが増えた)
npm test
testem.jsonを見てみるとわかりますが、power-assertとBrowserifyとMochaを組み合わせて使っていますが、設定はそこまで複雑じゃないと思います。
以前紹介したgulp+testemの方法も、ちょっと変更があってBowerなしでも可能になったので以下の記事は更新してあります。
今回やったのは上記の記事Karmaでやってた部分をTestemに変えただけで、Browserifyでテストコード(power-assertを使ってる)をビルドしたファイルを作って、それをTestemに読み込ませて、Mochaでブラウザ上でテストするという感じです。
Travis CIでは簡単に動かせるFirefoxとPhantomJSだけのテストになってます。 (Chromeはsandboxの都合で何か面倒)
sudo: false
language: node_js
node_js:
- '0.12'
before_script:
- export DISPLAY=:99.0
- sh -e /etc/init.d/xvfb start
- sleep 5
script: npm test -- -l phantomjs,firefox
zuulを使おうとしたけど、MochaがPromiseテスト対応していないバージョンだったり面倒になったので諦めました。(SauceLabsでIEのテストしたかった…)
テストはNode.jsだけで動くようにするととてもシンプルになるのでできるだけそうした方が楽ですが、今回みたいに結構DOM API使ってるとブラウザで動かしたほうがいいかなーという感じがします。けど、もっと簡単に(設定ファイルなしで)ブラウザでもテストができるといいなーという感じがしました。
お知らせ欄
JavaScript Primerの書籍版がAmazonで購入できます。
JavaScriptに関する最新情報は週一でJSer.infoを更新しています。
GitHub Sponsorsでの支援を募集しています。