Maison >interface Web >js tutoriel >Comment ajouter des éléments dynamiquement dans JS
Cet article vous présente principalement les informations pertinentes sur l'exécution répétée de programmes provoquée par l'ajout dynamique d'éléments et d'événements de liaison dans JS. L'article les présente de manière très détaillée à travers un exemple de code, qui a une certaine valeur de référence pour l'étude ou le travail de chacun. Les amis qui en ont besoin peuvent venir jeter un oeil ci-dessous.
Avant-propos
Cet article partage principalement avec vous le bug rencontré il y a quelque temps. Ce bug concerne les événements interactifs de liaison de méthodes de jquery. des gens ont écrit sur l'exécution répétée de programmes provoqués par un code comme $('#point').on('click','.read-more',function () {})
, et ont également mentionné l'utilisation de la méthode off pour dissocier, mais ils n'ont pas réussi à souligner l'essence du problème, et presque tous ont ignoré la nature réelle du problème. Il est causé par la délégation d’événements.
Sans plus attendre, voici les codes que je vois chaque jour :
Le premier type :
$(document).on('click', function (e) { consol.log('jquery事件绑定') });
Le deuxième type :
document.addEventListener('click',function (e) { consol.log('原生事件绑定') });
Le troisième type :
var id = setInterval(function () { console.log('定时器循环事件绑定') },1000);
Le code ci-dessus, je crois Que ce soit ou non, Shao Tonglian écrit chaque jour que la liaison d'événements apparemment simple peut souvent nous apporter des résultats inattendus, en particulier à cette époque où l'actualisation partielle des pages SPA et AJAX est si populaire.
Alors, qu'est-ce que la liaison d'événements et qu'est-ce qui provoque l'exécution répétée des programmes ? Pour résoudre ce problème, cela ne semble pas si simple. Utilisons un morceau de code de test pour l'illustrer. Vous pouvez le copier localement et l'essayer vous-même :
<!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:'df'+count++, href:'' }; this.renderData(data); }, renderData:function (data) { document.getElementById('point').innerHTML='<p>this is a '+data.content+'点此<a class="read-more" href="javasript:;" rel="external nofollow" rel="external nofollow" >查看更多</a></p>'; $('#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(); }); </script> </body> </html>
Ce qui précède est un code de test que j'ai écrit pour clarifier ce problème. Vous pouvez le copier et l'essayer. Lorsque nous cliquons sur le bouton sur la page, la fonction example.getData()
est appelée, et une fois l'acquisition ajax réussie, le contenu de la classe d'élément nommée point dans la page sera actualisé localement, et la balise read-more A dans cette le contenu sera chargé. Lier un événement et l'effet souhaité apparaît. Lorsque l'élément est chargé pour la première fois, la page est normale et le « point d'accident » apparaît une fois. Lorsque la deuxième actualisation est déclenchée, vous le ferez. constatez qu'il apparaît deux fois. La troisième fois, vous constaterez qu'il rebondit trois fois, et ainsi de suite. . . .
OMG, qu'est-ce qui ne va pas avec ce programme ? Je sais clairement qu'avant que chaque événement ne soit lié, les éléments précédemment liés sont supprimés. Pourquoi, le cadavre supprimé a l'impression qu'il bouge toujours. Une exclamation faite face à cette situation.
Finalement, j'ai interrogé le maître autour de moi, et j'ai soudain réalisé que la liaison était toujours là, et cette liaison était enregistrée dans un endroit appelé la file d'attente des événements. Il n'était pas dans le thread principal de l'exécution de la boucle. , et a dessiné une image A qui nécessite une compréhension tacite pour être comprise, alors j'y ai jeté un coup d'œil à contrecœur.
File d'attente des événements
Rétablir la vérité
En fait, le code ci-dessus est pour Le code spécialement écrit pour les tests, à l'exception du timer, les deux autres événements de clic sont écrits de manière normale. Une exécution répétée ne se produira pas :
// jquery 事件直接绑定的写法; $('#point .read-more').on('click',function () { alert('事故发生点'); }) // 原生JS 事件直接绑定的写法; document.querySelector('.read-more').addEventListener('click',function (e) { alert('事故发生点'); })
Voyez-vous la différence. ? En fait, il n'est pas nécessaire de faire remonter la délégation de l'événement, mais de lier directement l'événement à l'élément ajouté. Ainsi, les événements Dom ont du sens. Pour les éléments ajoutés dynamiquement, les événements sont liés dynamiquement à cet élément. Une fois l'élément supprimé, l'événement correspondant qui lui est lié sera en fait supprimé de la file d'attente de liaison d'événements , plutôt que du. code de test ci-dessus, qui donne l'impression qu'une fois l'élément supprimé, ses événements liés sont toujours dans la mémoire. Mais rappelez-vous, c'est un malentendu. Le code testé ci-dessus donne cette illusion car nous ne lions pas les événements aux éléments ajoutés dynamiquement, mais utilisons uniquement la délégation d'événements, en fait, l'événement est lié au #. L'élément point, qui existe toujours, est utilisé pour faire savoir au programme que nous avons cliqué sur l'élément de lien ajouté dynamiquement. Dans le test, js natif a été délibérément utilisé pour reproduire la délégation d'événement. Le principe de jquery sur la liaison d'événement est fondamentalement le même.
document.querySelector('body').addEventListener('click',function (e) { if(e.target.classList.contains('read-more')){ alert('事故发生点'); } })
Ces méthodes pour éliminer les bugs
Minuterie
C'est la plus simple L'erreur commise est bien sûr la plus simple à résoudre, car lors du réglage du minuteur, elle renverra une valeur. Cette valeur doit être un nombre dans le minuteur dans la file d'attente des événements, similaire à 9527. L'étape consiste à définir une variable globale à conserver. cette valeur de retour id. Chaque fois que la minuterie est définie, effacez d'abord la minuterie qui a été définie par id
clearInterval(intervalId); //粗暴的写法 intervalId&&clearInterval(intervalId); //严谨的写法 intervalId=setInterval(function () { console.log('fdfdfg'); },2000);
Événement Dom
En fait, nous. J'ai dit ci-dessus que le moyen le plus direct n'est pas d'utiliser la délégation d'événements, mais d'utiliser la liaison directe si vous souhaitez vraiment utiliser la délégation d'événements pour lier des événements, puis dissocier. La fonction de dissociation est fournie dans jquery pour dissocier les événements, mais après jquery 1.8, cette méthode n'est plus recommandée et la méthode off est recommandée. Par exemple, dans la méthode de délégation sur événement ci-dessus, pour dissocier, vous pouvez utiliser l'instruction $('#point').off('click','.read-more')
.
有缺陷的解决方案,添加flag
很好理解,第一次绑定后,flag置位,下一次在执行这个绑定时,程序就知道在这个节点上已经有了绑定,无需再添加,具体操作就是:
var flag = false; var example = { getData: function () { var data = { content: 'df' + count++, href: '' }; this.renderData(data); }, renderData: function (data) { document.getElementById('point').innerHTML = '<p>this is a ' + data.content + '点此<a class="read-more" href="javasript:;" rel="external nofollow" rel="external nofollow" >查看更多</a></p>'; !flag && $('#point').on('click', '.read-more', function () { alert('事故发生点'+data.content); }); flag = true; } };
从逻辑上,看起来没有问题,但仔细观察,发现这是有问题的。当我们第二次,第三次刷新时,弹出框的内容还是和第一次模拟刷新后点击后弹出的内容一致,还是'事故发生点df1',而非和内容一样递增,为什么呢,感觉事件队列里面的回调函数被单独保存起来了,data被深拷贝了,而不再是一个引用。确实有点难理解,我也不知道到底是为什么,如果哪位能说清楚,还请一定告知。
结个尾写在最后,其实平常写一些程序时,事件绑定,造成程序重复执行这些情况很少发生,其通常会出现在我们写插件的时候,插件需要适应多种调用环境,所以在插件内部做到防止事件重复绑定的情况非常重要。
上面是我整理给大家的,希望今后会对大家有帮助。
相关文章:
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!