Home  >  Article  >  Web Front-end  >  How to add elements dynamically in JS

How to add elements dynamically in JS

亚连
亚连Original
2018-06-22 13:55:292347browse

This article mainly introduces to you the relevant information about the repeated execution of programs caused by dynamically adding elements and binding events in JS. The article introduces it in detail through sample code, which has certain reference value for everyone's study or work. Friends who need it can come and take a look below.

Preface

This article mainly shares with you the bug encountered some time ago. This bug is about jquery’s on method binding interactive events. Code similar to $('#point').on('click','.read-more',function () {}) causes repeated execution of the program. Many people wrote in the article When we arrived, we also talked about using the off method to unbind, but they failed to point out the essence of the problem. They almost ignored that the essence of the problem was actually caused by event delegation.

Without further ado, here are the codes I see every day:

##The first type:

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

Second type:

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

Third type:

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

I believe many allies write the code above every day Well, seemingly simple event binding can often bring us unexpected results, especially in this era where SPA and AJAX page partial refresh are so popular.

So what is event binding, and what causes repeated execution of programs? It seems that this matter is not that simple to clear, so let’s use a test code to illustrate it. You can copy it locally and try it yourself:

<!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>

The above is a test code I wrote to clarify this matter. You can copy it and try it. When we click the button on the page, the function

example.getData() is triggered. After simulating ajax to obtain the data successfully, the content of the element class named point in the page will be refreshed locally, and at the same time, this function will be loaded. The read-more A tag in the content is bound to an event, and the effect we want appears. When the element is loaded for the first time, the page is normal, and the 'accident point' pops up once. When the second refresh is triggered, you You will find that it pops up twice, and the third time, you will find that it pops up three times, and so on. . . .

OMG, what’s wrong with this program? I clearly know that before each event is bound, the previously bound elements are deleted. Why, the deleted corpse feels like it is still moving. Well, the above is my first An exclamation made when encountering this situation.

Finally, I asked the master around me, and I suddenly realized that the binding was always there, and this binding was saved in a place called the event queue. He was not in the main thread of loop execution, and drew a A picture that requires tacit understanding to be understood, so I reluctantly took a look at it.

Event queue

Restore the truth

In fact, the above code is for The code specially written for testing, except for the timer, the other two click events are written in a normal way. Repeated execution will not occur. The normal code:

 // 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;);
 })

Do you see the difference? In fact That is, there is no need to bubble up event delegation, but directly bind events to the added elements. So

Dom events make sense. For dynamically added elements, events are dynamically bound to this element. After the element is deleted, the corresponding event bound to it will actually be deleted from the event binding queue , rather than the above test code, which gives the impression that after the element is removed, its bound events are still in the memory. But please remember, this is a misunderstanding. The code tested above gives this illusion because we do not bind events to dynamically added elements, but only use the form of event delegation. , in fact, the event is bound to the #point element, which always exists. Event bubbling is used to let the program know that we clicked on the dynamically added link element. In the test, native js was specially used to reproduce the event delegation. The principle of jquery's on binding event is basically the same.

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

Those methods to eliminate bugs

Timer

This is the most common mistake The error is of course the easiest to solve, because when setting the timer, it will return a value. This value should be a number in the timer in the event queue, similar to 9527; the step is to set a global variable to Keep this return value id, and every time you set the timer, first clear the timer that has been set by id

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

Dom event

In fact, we above As mentioned before, the most direct way is not to use event delegation, but to use direct binding; if you really want to use event delegation to bind events, then unbind. The unbind function is provided in jquery to unbind events. However, after jquery version 1.8, this method is no longer recommended, and the off method is recommended. For example, in the on event delegation method above, to unbind, you can use the statement

$('#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中有关组件通信有哪些方法?

The above is the detailed content of How to add elements dynamically in JS. For more information, please follow other related articles on the PHP Chinese website!

Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn