レットイットスノー


原著on my blog

Go to https://vixalien.ga/post/let-it-snow#snow to view the results


🌨⛄ あなたは雪が好きですか.それはあなたの地域で雪ですか?まだ12月ですか.
私たちは冷たい雪を使って仮想雪を作りますWeb Animations API .

雪片!
まず第一に、雪片を作成しましょう!私たちのスノーフレークは.svg 美しいファイルIonicons .

雪片積載
ローカルファイルとして保存し、SVGとして読み込むか、Iniiconのライブラリから使用しますが、文字列として保存します.
let svg_str = `<!-- snowflake svg text here -->`;

文字列をDOM要素に解析する
それでは使用しますDOMParser 文字列を実際のDOM要素にパースする.
let snow = new DOMParser().parseFromString(svg_str, "text/xml").children[0];

Note: Because parseFromString returns a #document, we used .children[0] to get the <svg> element instead. (<svg> is equivalent to <html>.)



スノーフレークをフロートに設定する
私たちの雪片は固定されています(それは他の要素のようにスクロールしない)と最初は、画面のすぐ上に配置されます.
snow.style.position = "fixed";
snow.style.top = "-24px";

新しい雪片を作成する
我々のページが多くの雪があるので、我々はちょうど我々が作成した雪片をクローンします.
let newSnow = () => {
    let clonedSnow = snow.cloneNode(true);
    // we pass true to clone the node deeply (that is, with all it's children).
};

Note: from now on, our code will be in the newSnow function.


次に、その雪片のランダム左の位置を生成します
let left = Math.floor(document.body.offsetWidth * Math.random());
// we use Math.floor to ensure left is an integer
clonedSnow.style.left = left + "px";
それから、我々はちょうどそれをDOMに加えます
document.body.append(clonedSnow);

雪片のアニメーション
ここでちょうど使用しますWeb Animations API 要素をアニメーション化する.APIを使用するにはelement.animate(keyframes, options) . を読むことができますMDN Page .
本当の雪の効果を作るために、我々はまた、ランダムな速度(アニメーションの期間を考える)を生成します
let time = Math.max(10 * Math.random(), 5) * 1000;
// Math.max choose the largest argument it was given. By using it here, we restrict time to be larger than 5.
雪をアニメーション化して変えるtop CSSプロパティ.最後に、要素はビューポートのすぐ下に配置されます.
let anim = clonedSnow.animate(
    {
        top: window.innerHeight + 24 + "px",
    },
    { duration: time, fill: "forwards" }
);
最後に、ゴミ収集をします.アニメーションが終了すると、それはもはや便利ではない雪片を削除します.
// garbage collection
anim.onfinish = el => el.target.effect.target.remove()
今すぐあなたのコンソールで実行してくださいnewSnow() . あなたは雪片をゆっくりと落ちるでしょう.

雪が降る!
これまでのところ、我々はランニングによって需要に応じて雪を作り出すしかないnewSnow() 毎回、我々はそれを必要とします.私たちは、できるだけ多くの雪片を作成するループを作成するについてはどうですか?

ネイティブJSループの問題
あなたが使うならばfor ループまたはwhile または何でも、それは動作しません.なぜ?それは一度に多くの雪を作成します.あなたのブラウザーは雪で満たされます、そして、あなたがスーパーコンピュータにいない限り、あなたのブラウザーはひどく壊れます.これはカスタムループの必要性を作成します!

非同期にループする

async iterate
asyncループの実装です.
let asyncIterate = async (start, iterations, fn) => {
    // initialize the iterator
    let i = start;
    let call = res => fn(res)
        // waits for the function to resolves before calling the next iteration
        .then(async result => {
            if (i >= iterations) return result;
            i++
            return await call(i)
        });
    return await call(i);
}
これは3パラメータを受け入れます.start イテレータが初期化されたものです.iterations かなり自明です.関数が実行される回数です.then fn が実行する関数です.
これが非同期ループであることを覚えておくことが重要です.つまり、関数を実行し、それが解決するのを待ちます.次に、次の反復処理を実行します.

待ち
次はwait 関数.これはラッパですsetTimeout . それはいくつかの時間(ミリ秒単位)を待ち、関数を実行します.( NPMレジストリで利用可能ですasync-wait-then ).
wait = time => new Promise(res => setTimeout(res, time))
以下に簡単な例を示しますwait .
wait(1000)
    .then(() => console.log('This will be logged after one second!'));

使用wait and asyncIterate 積む
組み合わせることでwait and asyncIterate , 私たちは、約束APIを使用する強力な機能セットを得ます.
だから、雪の要素を作成する前に、現実的な雪を作成する
asyncIterate(0, 10, async () => {
    await wait(1000)
    newSnow()
})
これは、それぞれの雪片の間に1秒間の間隔で、それは10雪を降らせるようになる
それはより現実的に見えるように(いくつかのサスペンスを追加)、我々は静的1秒の代わりに時間のランダムな量を待つことになります.
asyncIterate(0, 10, async () => {
    await wait(Math.max(3 * Math.random(), 1) * 300)
    newSnow()
})
しかし、これは10雪を作成します.永遠に雨にしましょう.
asyncIterate(0, Infinity, async () => {
    await wait(Math.max(3 * Math.random(), 1) * 300)
    newSnow()
})
完全なコードは、いくつかの最適化と完全に投稿されますGithub Gist