JSで要素を動的に追加し、イベントをバインドし、プログラムを繰り返し実行させる


奇妙なバグ


2週間休んで何も書いていないので、最近少し知識が慌てているような気がします.新しい知識はありません.この間出会ったバグの難題を共有してください.このバグはjqueryのon方法についてインタラクティブなイベントを縛っています.$('#point')に似ています.on('click','.read-more',function(){})のようなコードはプログラムを繰り返し実行させ、多くの人がoff法で縛りを解くと書いたが、問題の本質を指摘することはめったになく、問題の本質を無視したのはイベント依頼によるものだ.あまり話さないで、上の点で毎日見ているコード:1つ目:
    $(document).on('click', function (e) {
        consol.log('jquery    ')
    });

2つ目:
   document.addEventListener('click',function (e) {
        consol.log('      ')            
   });

3つ目:
   var id = setInterval(function () {
        console.log('         ')
   },1000);

上のコードは、多くの同盟を信じて、毎日书くことができて、简単な事件のバインドのように见えて、いつも私达に予想外の结果をもたらすことができて、特にこのSPAで、AJAXページの局部を応用してこのように盛んな时代を更新します.では、イベントバインドとは何でしょうか.プログラムが繰り返し実行されますか.このことはクリアといえば、そんなに簡単ではないようですが、テストコードで説明しましょう.ローカルにコピーして、自分で試してみてください.



    
    Title



fdfsdf
var count=1; var example = { getData:function () { var data ={ content:'df'+count++, href:'' }; this.renderData(data); }, renderData:function (data) { document.getElementById('point').innerHTML='<div>this is a '+data.content+' <a class="read-more" href="javasript:;"> </a></div>'; $('#point').on('click','.read-more',function () { alert(' '); }) /* setInterval(function () { console.log('fdfdfg'); },2000);*/ /* , Jquery on */ /* document.querySelector('body').addEventListener('click',function (e) { if(e.target.classList.contains('read-more')){ alert(' '); } })*/ } } ; document.querySelector('.add_but').addEventListener('click',function (e) { example.getData(); e.stopImmediatePropagation(); });

以上は私がこのことをはっきり言うために書いたテストコードです.コピーしてみてください.ページのボタンをクリックするとexampleの呼び出しがトリガーされます.getData()という関数は、ajaxをシミュレートしてデータを取得することに成功すると、ページ内の要素クラス名pointの内容をローカルにリフレッシュするとともに、このコンテンツをロードするread-more Aラベルにイベントをバインドし、目的の効果が現れます.メタエレメントが1回目にロードされると、ページは正常になり、「事故発生点」が1回ポップアップされ、2回目のリフレッシュがトリガーされると、2回ポップアップされ、3回目になると、3回弾いて、このように押すことに気づきます...OMG、このプログラムはいったいどうしたのか、私は毎回イベントがバインドされる前に、前のバインドされた要素が削除されたのに、どうして、削除された死体はまだ動作しているような気がします.いいでしょう.上は私が初めてこの状況に遭遇した感嘆です.最后に身の回りの大神に闻いて、やっと突然悟って、もとは缚り付けてずっとあって、この缚り付けは1つの非同期の事件の列という地方に保存されて、1枚の暗黙の了解がやっと理解することができる図を描いて、无理に见てみます.

真実を復元する.


実は上のコードはテストのためにわざわざ書いたコードで、タイマーのほかに、他の2つのクリックイベントは正常な書き方に変えて、繰り返し実行する場合は現れません.正常なコード:
        // jquery          ;
        $('#point .read-more').on('click',function () {
            alert('     ');
        })
        //   JS          ;
        document.querySelector('.read-more').addEventListener('click',function (e) {
            alert('     ');
        })

違いは見えますか?実は泡を立ててイベントを依頼するのではなく、追加した要素に直接イベントをバインドします.だからDomイベントは道理を説いて、動的に追加した要素、更に動的にこのバインドイベントに対して、要素が削除されると、そのバインドされた対応するイベントは実際にはイベントバインドキューから削除され、上のテストコードのように、要素が削除されたと感じられますが、そのバインドされたイベントはまだメモリの中にあります.しかし、これは誤解であることを覚えておいてください.上でテストしたコードがこのような錯覚を与えたのは、動的に追加された要素にイベントをバインドしていないからです.イベント依頼の形式を使っているだけで、実際にはイベントは#point要素にバインドされています.それはずっと存在しています.イベントバブルを利用して、動的に追加されたリンク要素をクリックしたことをプログラムに知らせます.テストではわざわざ原生jsで今回のイベント依頼を再現したが,jqueryのonバインドイベントは原理がほぼ同じである.
document.querySelector('body').addEventListener('click',function (e) {
     if(e.target.classList.contains('read-more')){
          alert('     ');
      }
})

バグを解除する方法


タイマ


これは最も犯しやすいエラーで、もちろん最も解きやすいエラーでもあります.タイマを設定すると、イベントキューというタイマの番号が返されるからです.9527に似ています.ステップは、グローバル変数を設定してこの戻り値idを保持し、タイマを設定するたびに、設定したタイマをidでクリアする
     clearInterval(intervalId); //     
     intervalId&&clearInterval(intervalId); //     
     intervalId=setInterval(function () {
                console.log('fdfdfg');
            },2000);  
            

Domイベント


実は上で私たちはすでに言ったように、最も直接的な方法は事件の依頼ではなく、直接バインドを採用することです.このような方法以外に、実は他の方法があります.バインドされた反意語は、縛りを解くことです.jqueryではunbind関数を提供してイベントをバインドしますが、jquery 1.8バージョン以降では、この方法はもう推奨されず、offメソッドが推奨されます.例えば、上記のonイベント依頼の方式では、縛りを解くには、文$('#point')を採用することができる.off('click','.read-more').

欠陥のあるソリューション、flagの追加


よく理解して、1回目のバインド後、flagは位置を置いて、次はこのバインドを実行する時、プログラムはこのノードの上ですでにバインドがあることを知っていて、これ以上追加する必要はありません.具体的な操作は:
     var flag = false;
     var example = {
        getData: function () {
            var data = {
                content: 'df' + count++,
                href: ''
            };
            this.renderData(data);
        },
        renderData: function (data) {
            document.getElementById('point').innerHTML = '
this is a ' + data.content + '
'; !flag && $('#point').on('click', '.read-more', function () { alert(' '+data.content); }); flag = true; } };

論理的には問題ないように見えますが、よく見ると問題があることがわかります.2回目、3回目のリフレッシュでは、ポップアップボックスの内容は、1回目のシミュレーションリフレッシュ後にクリックするとポップアップされた内容と一致するか、「事故発生点df 1」であり、内容と同じように増加するのではなく、なぜか、イベントキュー内のコールバック関数が単独で保存されているのか、data.contentは参照ではなく深くコピーされました.确かにちょっとわかりにくいですが、私もなぜか分かりません.どなたかはっきり言えたら、ぜひ教えてください.

最後を結ぶ


最後に、実際には通常いくつかのプログラムを書くとき、これらの状況はめったに発生しません.イベントバインドによって、プログラムが繰り返し実行されます.このような状況は通常、私たちがプラグインを書くときに発生します.プラグインは多くの呼び出し環境に適応する必要があります.そのため、プラグイン内部でイベントの繰り返しバインドを防止することが重要です.本文は同時に:closertb.site著作権所有、原文リンクを保留して転載することを歓迎します:)