検索

この記事では、JS での要素の動的追加とイベントのバインディングによるプログラムの繰り返し実行に関する関連情報を、サンプル コードを通じて詳しく紹介します。この記事は、あらゆる人の学習や仕事に役立つ特定の学習価値があります。それは必要です、友達、一緒に見てみましょう。

前書き

この記事では主に、少し前に発生したバグについて説明します。このバグは、$('#point').on(' click と同様の、jquery の on メソッド バインディング インタラクティブ イベントに関するものです。 ','.read-more',function () {}) このようなコードにより、プログラムが繰り返し実行されます。これについては多くの人が記事で書いており、バインドを解除するための off メソッドの使用についても言及しています。問題の本質を指摘できても、問題の本質が実際にイベント委任によって引き起こされているということはほとんど無視されます。 $('#point').on('click','.read-more',function () {})这样的代码造成的程序重复执行,很多人在文章里写到了,也说了用off方法来解绑,但都未能点出问题的本质,几乎都忽略了问题的本质其实是事件委托造成的。

话不多说,上点天天看到的代码:

第一种:  

 $(document).on('click', function (e) {
 consol.log('jquery事件绑定')
 });

第二种:  

 document.addEventListener('click',function (e) {
 consol.log('原生事件绑定')  
 });

第三种:  

 var id = setInterval(function () {
 console.log('定时器循环事件绑定')
 },1000);

上面的代码,相信不少同盟,天天都会写到,看似简单的事件绑定,却经常能给我们带来意想不到的结果,特别是在这个SPA,应用AJAX页面局部刷新如此盛行的时代。

那什么是事件绑定,造成的程序重复执行呢?这个事情要说清除,好像不是那么简单,还是用一段测试代码来说明吧。你可以拷贝到本地,自己试试: 

<!DOCTYPE html>
<html>
<head>
 <meta charset="UTF-8">
 <title>Title</title>
</head>
<body>
<button class="add_but">点击</button>
<p id="point">fdfsdf
</p>
<script src="https://cdn.bootcss.com/jquery/1.8.3/jquery.js"></script> 
<script>
 var count=1;
 var example = {
 getData:function () {
  var data ={
  content:&#39;df&#39;+count++,
  href:&#39;&#39;
  };
  this.renderData(data);
 },
 renderData:function (data) {
  document.getElementById(&#39;point&#39;).innerHTML=&#39;<p>this is a &#39;+data.content+&#39;点此<a class="read-more" href="javasript:;" rel="external nofollow" rel="external nofollow" >查看更多</a></p>&#39;;
  $(&#39;#point&#39;).on(&#39;click&#39;,&#39;.read-more&#39;,function () {
  alert(&#39;事故发生点&#39;);
 })
/*  setInterval(function () {
  console.log(&#39;fdfdfg&#39;);
  },2000);*/
  /*用冒泡来绑定事件,类似于Jquery的on绑定事件*/
 /* document.querySelector(&#39;body&#39;).addEventListener(&#39;click&#39;,function (e) {
  if(e.target.classList.contains(&#39;read-more&#39;)){
   alert(&#39;事故发生点&#39;);
  }
  })*/

 }
 } ;
 document.querySelector(&#39;.add_but&#39;).addEventListener(&#39;click&#39;,function (e) {
 example.getData();
 e.stopImmediatePropagation();
 });
</script>
</body>
</html>

以上是我为说清这个事情写的一段测试代码,可以拷贝下来试试。当我们点击页面的按钮,触发调用example.getData()这个函数,模拟ajax获取数据成功后,就会根据局部刷新页面内元素类名为point的内容,同时会为加载这个内容中的read-more A标签绑定一个事件,就这样我们想要的效果出现啦,当元素第一次加载时,页面正常,‘事故发生点'弹出一次,当二次刷新触发后,你会发现其弹出了两次,当第三次时,你会发现,其弹三次,以此类推。。。。

OMG,这个程序到底怎么了,我明明每次事件绑定前,前面绑定的元素都删除了,为什么,被删除的尸体感觉还在动作,好吧,上面就是我第一次遇到这个情况发出的感叹。

最后是问身边的大神,才突然领悟,原来绑定一直都在,而这个绑定被保存在一个叫做事件队列的地方,他不在循环执行的主线程中,画了一张需要默契才能看懂的图,勉强看一看。

事件队列

还原真相

其实上面那一段代码是为了测试而特意写的代码,除了定时器外,其他两个点击事件换个正常的写法,重复执行的情况是不会出现的,正常的代码:  

 // jquery 事件直接绑定的写法;
 $(&#39;#point .read-more&#39;).on(&#39;click&#39;,function () {
  alert(&#39;事故发生点&#39;);
 })
 // 原生JS 事件直接绑定的写法;
 document.querySelector(&#39;.read-more&#39;).addEventListener(&#39;click&#39;,function (e) {
  alert(&#39;事故发生点&#39;);
 })

看出差别了吗?其实就是不用冒泡来事件委托,而是直接给添加的元素绑定事件。所以Dom事件是讲道理的,动态添加的元素,再动态为此绑定事件,待元素被删除后,与其绑定的相应事件其实是会从事件绑定队列中删除的,而非如上面测试代码,给人的感觉是元素移除后,但其绑定的事件还在内存中。但请记住,这是个误会,上面测试的代码之所以给人这种错觉,是因为我们并没有为动态添加的元素绑定事件,而仅仅是用了事件委托的形式,实际上事件是绑定在#point元素上的,其一直存在,利用事件冒泡来让程序知道我们点击了动态添加的链接元素。测试中特意用原生js去重现了这次事件委托,jquery的on绑定事件其实原理基本相同。  

document.querySelector(&#39;body&#39;).addEventListener(&#39;click&#39;,function (e) {
 if(e.target.classList.contains(&#39;read-more&#39;)){
  alert(&#39;事故发生点&#39;);
 }
})

解除bug的那些方法

定时器

这个是最易犯的错误,当然也是最易解的错误,因为设定定时器时,其会返回一个数值,这个数值应该是事件队列此定时器中的一个编号吧,类似于9527;步骤就是设定一个全局变量来保持这个返回值id,在每次设定定时器时,先通过id清除已经设定过的定时器    

 clearInterval(intervalId); //粗暴的写法
 intervalId&&clearInterval(intervalId); //严谨的写法
 intervalId=setInterval(function () {
  console.log(&#39;fdfdfg&#39;);
  },2000);

Dom事件

其实上面我们已经说过,最直接的办法就是不采用事件委托,而是采用直接绑定;如果确实要用事件委托来绑定事件,那就是解绑。在jquery中提供了unbind函数来解绑事件,不过在jquery 1.8版本以后,这个方法已经不推荐了,而是推荐off方法。比如上面的on事件委托的方式,要解绑,可采用语句$('#point').off('click','.read-more')

🎜🎜 早速、私が毎日目にするコードを以下に示します。 🎜🎜🎜🎜🎜 1 つ目: 🎜🎜
 var flag = false;
 var example = {
 getData: function () {
  var data = {
  content: &#39;df&#39; + count++,
  href: &#39;&#39;
  };
  this.renderData(data);
 },
 renderData: function (data) {
  document.getElementById(&#39;point&#39;).innerHTML = &#39;<p>this is a &#39; + data.content + &#39;点此<a class="read-more" href="javasript:;" rel="external nofollow" rel="external nofollow" >查看更多</a></p>&#39;;
  !flag && $(&#39;#point&#39;).on(&#39;click&#39;, &#39;.read-more&#39;, function () {
  alert(&#39;事故发生点&#39;+data.content);
  });
  flag = true;
 }
 };
🎜🎜 2 つ目: 🎜🎜rrreee🎜🎜 3 つ目: 🎜🎜rrreee🎜上記のコードについては、多くのアライアンスが毎日このことについて書いていると思います。特に SPA と AJAX ページの部分更新が非常に普及しているこの時代では、一見単純なイベント バインディングが予期せぬ結果をもたらすことがよくあります。 🎜🎜では、イベント バインディングとは何ですか?また、何がプログラムの繰り返し実行を引き起こすのでしょうか?この問題をクリアするのはそれほど簡単ではないようなので、テストコードを使用して説明してみましょう。ローカルにコピーして自分で試すことができます: 🎜rrreee🎜 上記は、この問題を明確にするために私が書いたテストコードです。コピーして試してください。ページ上のボタンをクリックすると、関数 example.getData() が呼び出され、Ajax をシミュレートしてデータを正常に取得した後、ページ内の point という名前の要素クラスのコンテンツが呼び出されます。このコンテンツの A タグはイベントにバインドされており、要素が初めて読み込まれるときに、必要な効果が表示されます。ページは正常で、2 回目の更新がトリガーされると「事故ポイント」が 1 回ポップアップし、3 回目では 3 回ポップアップすることがわかります。 。 。 。 🎜🎜このプログラムの何が問題なのでしょうか? 各イベントがバインドされる前に、以前にバインドされた要素が削除されることはわかっています。なぜなら、削除された死体がまだ動いているように見えるのです。この状況からの感嘆の声。 🎜🎜最後に、周りのマスターに尋ねたところ、バインディングは常に存在しており、このバインディングはイベントキューと呼ばれる場所に保存されており、絵を描くために必要なメインスレッドには存在しませんでした。暗黙の了解で絵を見てやっと理解できる。 🎜

🎜

イベント キュー🎜🎜🎜🎜真実を復元します🎜🎜🎜🎜実際、上記のコードはタイマーに加えて、他の 2 つのクリック イベントもテスト用に特別に書かれています。通常の記述では、繰り返し実行は発生しません。 通常のコード: 🎜rrreee🎜 実際、イベント デリゲートをバブルアップする必要はなく、追加された要素にイベントを直接バインドする必要があります。したがって、動的に追加された要素の場合、イベントはこの要素に動的にバインドされ、その要素にバインドされた対応するイベントは、上記のテスト コードのようにではなく、実際にイベント バインディング キューから削除されます。要素が削除された後も、バインドされたイベントがまだメモリ内にあるような印象を与えます。 🎜ただし、覚えておいてください🎜、これは誤解です。上記でテストしたコードがこのような錯覚を引き起こす理由は、イベントを動的に追加された要素にバインドせず、実際にはイベント委任の形式のみを使用しているためです。 #point 要素は常に存在し、イベント バブリングを使用して、動的に追加されたリンク要素をクリックしたことをプログラムに知らせます。テストでは、イベント委任を再現するためにネイティブ js が意図的に使用されました。jquery のバインディング イベントの原理は基本的に同じです。 🎜rrreee🎜🎜🎜バグを排除するためのメソッド🎜🎜🎜🎜🎜タイマー🎜🎜🎜これは最もよくある間違いであり、もちろん、解決するのが最も簡単です。なぜなら、タイマーが設定されると、この値が返されるからです。 9527 と同様に、イベント キューのタイマー内の数値である必要があります。このステップでは、タイマーが設定されるたびに、最初にタイマー 🎜rrreee を通じて設定値をクリアします。 🎜🎜Dom イベント🎜🎜🎜 実際、上で述べたように、最も直接的な方法は、イベント委任を使用するのではなく、直接バインディングを使用することです。イベント委任を使用してイベントをバインドしたい場合は、 unbind を使用します。 jquery ではイベントをバインド解除するための unbind 関数が提供されていますが、jquery バージョン 1.8 以降では、この方法は推奨されなくなり、代わりに off 方法が推奨されます。たとえば、上記のイベント委任メソッドでバインドを解除するには、ステートメント $('#point').off('click','.read-more') を使用できます。 🎜

有缺陷的解决方案,添加flag

很好理解,第一次绑定后,flag置位,下一次在执行这个绑定时,程序就知道在这个节点上已经有了绑定,无需再添加,具体操作就是:  

 var flag = false;
 var example = {
 getData: function () {
  var data = {
  content: &#39;df&#39; + count++,
  href: &#39;&#39;
  };
  this.renderData(data);
 },
 renderData: function (data) {
  document.getElementById(&#39;point&#39;).innerHTML = &#39;<p>this is a &#39; + data.content + &#39;点此<a class="read-more" href="javasript:;" rel="external nofollow" rel="external nofollow" >查看更多</a></p>&#39;;
  !flag && $(&#39;#point&#39;).on(&#39;click&#39;, &#39;.read-more&#39;, function () {
  alert(&#39;事故发生点&#39;+data.content);
  });
  flag = true;
 }
 };

从逻辑上,看起来没有问题,但仔细观察,发现这是有问题的。当我们第二次,第三次刷新时,弹出框的内容还是和第一次模拟刷新后点击后弹出的内容一致,还是'事故发生点df1',而非和内容一样递增,为什么呢,感觉事件队列里面的回调函数被单独保存起来了,data被深拷贝了,而不再是一个引用。确实有点难理解,我也不知道到底是为什么,如果哪位能说清楚,还请一定告知。

结个尾写在最后,其实平常写一些程序时,事件绑定,造成程序重复执行这些情况很少发生,其通常会出现在我们写插件的时候,插件需要适应多种调用环境,所以在插件内部做到防止事件重复绑定的情况非常重要。

上面是我整理给大家的,希望今后会对大家有帮助。

相关文章:

使用node.js如何创建子进程(详细教程)

使用ES6如何实现单例模式

如何把Angular项目部署到nginx上

在vue中使用v-model如何实现父子组件通信

在react中有关组件通信有哪些方法?

以上がJSで要素を動的に追加する方法の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
JavaScriptとWeb:コア機能とユースケースJavaScriptとWeb:コア機能とユースケースApr 18, 2025 am 12:19 AM

Web開発におけるJavaScriptの主な用途には、クライアントの相互作用、フォーム検証、非同期通信が含まれます。 1)DOM操作による動的なコンテンツの更新とユーザーインタラクション。 2)ユーザーエクスペリエンスを改善するためにデータを提出する前に、クライアントの検証が実行されます。 3)サーバーとのリフレッシュレス通信は、AJAXテクノロジーを通じて達成されます。

JavaScriptエンジンの理解:実装の詳細JavaScriptエンジンの理解:実装の詳細Apr 17, 2025 am 12:05 AM

JavaScriptエンジンが内部的にどのように機能するかを理解することは、開発者にとってより効率的なコードの作成とパフォーマンスのボトルネックと最適化戦略の理解に役立つためです。 1)エンジンのワークフローには、3つの段階が含まれます。解析、コンパイル、実行。 2)実行プロセス中、エンジンはインラインキャッシュや非表示クラスなどの動的最適化を実行します。 3)ベストプラクティスには、グローバル変数の避け、ループの最適化、constとletsの使用、閉鎖の過度の使用の回避が含まれます。

Python vs. JavaScript:学習曲線と使いやすさPython vs. JavaScript:学習曲線と使いやすさApr 16, 2025 am 12:12 AM

Pythonは、スムーズな学習曲線と簡潔な構文を備えた初心者により適しています。 JavaScriptは、急な学習曲線と柔軟な構文を備えたフロントエンド開発に適しています。 1。Python構文は直感的で、データサイエンスやバックエンド開発に適しています。 2。JavaScriptは柔軟で、フロントエンドおよびサーバー側のプログラミングで広く使用されています。

Python vs. JavaScript:コミュニティ、ライブラリ、リソースPython vs. JavaScript:コミュニティ、ライブラリ、リソースApr 15, 2025 am 12:16 AM

PythonとJavaScriptには、コミュニティ、ライブラリ、リソースの観点から、独自の利点と短所があります。 1)Pythonコミュニティはフレンドリーで初心者に適していますが、フロントエンドの開発リソースはJavaScriptほど豊富ではありません。 2)Pythonはデータサイエンスおよび機械学習ライブラリで強力ですが、JavaScriptはフロントエンド開発ライブラリとフレームワークで優れています。 3)どちらも豊富な学習リソースを持っていますが、Pythonは公式文書から始めるのに適していますが、JavaScriptはMDNWebDocsにより優れています。選択は、プロジェクトのニーズと個人的な関心に基づいている必要があります。

C/CからJavaScriptへ:すべてがどのように機能するかC/CからJavaScriptへ:すべてがどのように機能するかApr 14, 2025 am 12:05 AM

C/CからJavaScriptへのシフトには、動的なタイピング、ゴミ収集、非同期プログラミングへの適応が必要です。 1)C/Cは、手動メモリ管理を必要とする静的に型付けられた言語であり、JavaScriptは動的に型付けされ、ごみ収集が自動的に処理されます。 2)C/Cはマシンコードにコンパイルする必要がありますが、JavaScriptは解釈言語です。 3)JavaScriptは、閉鎖、プロトタイプチェーン、約束などの概念を導入します。これにより、柔軟性と非同期プログラミング機能が向上します。

JavaScriptエンジン:実装の比較JavaScriptエンジン:実装の比較Apr 13, 2025 am 12:05 AM

さまざまなJavaScriptエンジンは、各エンジンの実装原則と最適化戦略が異なるため、JavaScriptコードを解析および実行するときに異なる効果をもたらします。 1。語彙分析:ソースコードを語彙ユニットに変換します。 2。文法分析:抽象的な構文ツリーを生成します。 3。最適化とコンパイル:JITコンパイラを介してマシンコードを生成します。 4。実行:マシンコードを実行します。 V8エンジンはインスタントコンピレーションと非表示クラスを通じて最適化され、Spidermonkeyはタイプ推論システムを使用して、同じコードで異なるパフォーマンスパフォーマンスをもたらします。

ブラウザを超えて:現実世界のJavaScriptブラウザを超えて:現実世界のJavaScriptApr 12, 2025 am 12:06 AM

現実世界におけるJavaScriptのアプリケーションには、サーバー側のプログラミング、モバイルアプリケーション開発、モノのインターネット制御が含まれます。 2。モバイルアプリケーションの開発は、ReactNativeを通じて実行され、クロスプラットフォームの展開をサポートします。 3.ハードウェアの相互作用に適したJohnny-Fiveライブラリを介したIoTデバイス制御に使用されます。

next.jsを使用してマルチテナントSaaSアプリケーションを構築する(バックエンド統合)next.jsを使用してマルチテナントSaaSアプリケーションを構築する(バックエンド統合)Apr 11, 2025 am 08:23 AM

私はあなたの日常的な技術ツールを使用して機能的なマルチテナントSaaSアプリケーション(EDTECHアプリ)を作成しましたが、あなたは同じことをすることができます。 まず、マルチテナントSaaSアプリケーションとは何ですか? マルチテナントSaaSアプリケーションを使用すると、Singの複数の顧客にサービスを提供できます

See all articles

ホットAIツール

Undresser.AI Undress

Undresser.AI Undress

リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover

AI Clothes Remover

写真から衣服を削除するオンライン AI ツール。

Undress AI Tool

Undress AI Tool

脱衣画像を無料で

Clothoff.io

Clothoff.io

AI衣類リムーバー

AI Hentai Generator

AI Hentai Generator

AIヘンタイを無料で生成します。

ホットツール

AtomエディタMac版ダウンロード

AtomエディタMac版ダウンロード

最も人気のあるオープンソースエディター

MantisBT

MantisBT

Mantis は、製品の欠陥追跡を支援するために設計された、導入が簡単な Web ベースの欠陥追跡ツールです。 PHP、MySQL、Web サーバーが必要です。デモおよびホスティング サービスをチェックしてください。

SublimeText3 Mac版

SublimeText3 Mac版

神レベルのコード編集ソフト(SublimeText3)

メモ帳++7.3.1

メモ帳++7.3.1

使いやすく無料のコードエディター

SublimeText3 中国語版

SublimeText3 中国語版

中国語版、とても使いやすい