经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » JS/JS库/框架 » jQuery » 查看文章
jQuery 源码分析(二十一) DOM操作模块 删除元素 详解
来源:cnblogs  作者:大沙漠  时间:2019/11/8 8:48:31  对本文有异议

本节说一下DOM操作模块里的删除元素模块,该模块用于删除DOM里的某个节点,也可以理解为将该节点从DOM树中卸载掉,如果该节点有绑定事件,我们可以选择保留或删除这些事件,删除元素的接口有如下三个:

  • empty()                                   ;移除匹配元素的所有子元素。        ;先移除所有后代元素关联的数据和事件,以避免内存泄漏。然后移除子元素。  
  • remove(selector,keepData)    ;从匹配元素中移除selector元素。   ;selector是可选的选择器表达式,如果未传入则全部移除,否则只移除对应的匹配元素。keepData可选,表示是否保留匹配元素以及它的后代元素所关联的数据和事件
  • detach(selector)                     ;从文档中移除匹配元素集合             ;但会保留后代元素和匹配元素关联的数据和事件,常用于移除的元素稍后再次插入文档的场景。

说直接一点,

  • empty()会直接移除当前匹配的元素
  • remove()会将当前匹配的元素中在匹配参数1selector里的元素,如果参数2keepData为true则保存该DOM节点的事件,否则移除事件
  • detach()是调用remove()实现的,用于移除当前匹配的元素,但是会保留数据 ,它是调用remove(selector,true)来实现的

 writer by:大沙漠 QQ:22969969

举个栗子:

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>Document</title>
  6. <script src="http://libs.baidu.com/jquery/1.7.1/jquery.min.js"></script>
  7. </head>
  8. <body>
  9. <div>
  10. <h1>你好</h1>
  11. </div>
  12. <p>朋友</p>
  13. <button id="b1">测试1</button>
  14. <button id="b2">测试2</button>
  15. <button id="b3">测试3</button>
  16. <script>
  17. $('h1').click(function(){console.log('h1 click')}); //给h1元素增加一个点击事件
  18. $('p').click(function(){console.log('p click')}); //给P元素增加一个点击事件
  19.  
  20. //以下给三个按钮都会实现将h1、p元素从DOM树中移除,再插入body的子节点的前面,不同的地方是点击子节点时的输出信息不同
  21. b1.onclick=function(){$('h1,p').remove().prependTo('body')} //点击测试1按钮后 h1和p元素都移动到了body子节点的最前面,但是再点击h1和p元素都没有反应
  22. b2.onclick=function(){$('h1,p').remove('p').prependTo('body')} //点击测试1按钮后 h1和p元素都移动到了body子节点的最前面,点击h1有输出,点击p没有输出
  23. b3.onclick=function(){$('h1,p').detach().prependTo('body')} //点击测试1按钮后 h1和p元素都移动到了body子节点的最前面,点击h1和p都有输出
  24. </script>
  25. </body>
  26. </html>

渲染如下:

 对应的DOM树如下:

我们给h1和p元素分别绑定了一个事件,点击分别输出:h1 click和p click,,点击输出如下:

另外不管点击测试1、测试2还是测试3,都会将h1和p元素从DOM树中卸载并插入到body子节点的最前面,如下:

此时再点击h1和p元素就会有不同的输出了:

  • 对于测试1按钮来说   ;点击h1和p没有任何输出                 ;由于调用了remove()方法且未传递参数,所以所有匹配的元素的事件都会被删除掉
  • 对于测试2按钮来说   ;点击h1有输出,点击p没有输出      ;由于调用remove()方法时传递了p,所以把p元素的事件都删除了,而h1元素的事件并没有被删除
  • 对于测试2按钮来说   ;点击h1和p没有任何输出                ;由于调用了detach()方法,所以所有元素的数据都被保留了,detach()内部时调用remove( selector, true )来实现的,也就是remove的参数2为true

 

源码分析


讲解empty()、remove()和detach()之前先介绍一个jQuery的API,就是$.cleanData(elems),参数是DOM节点的集合(可以是document.getElementsByTagName的返回值),它用于移除一个DOM节点上绑定的jQuery事件的,我们举个栗子:

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>Document</title>
  6. <script src="http://libs.baidu.com/jquery/1.7.1/jquery.min.js"></script>
  7. </head>
  8. <body>
  9. <p>Hello World</p>
  10. <button>测试</button>
  11. <script>
  12. $('p').click(function(){console.log('p click')}); //给P元素增加一个点击事件
  13. $('button').click(function(){
  14. $.cleanData(document.getElementsByTagName('p')) //给button按钮添加一个button事件,内部调用$.cleanData去清楚p元素上绑定的事件
  15. })
  16. </script>
  17. </body>
  18. </html>

渲染如下:

初始化时我们点击Hello World控制台会输出信息,如果点击按钮后再点击Hello World就不会输出了,因为$.cleanData把该DOM元素的事件给卸载了,$.cleanData实现如下:

  1. jQuery.extend({
  2. cleanData: function( elems ) { //移除多个DOM元素的全部数据和事件, elems是待移除数据和事件的DOM元素数组。
  3. var data, id,
  4. cache = jQuery.cache,
  5. special = jQuery.event.special,
  6. deleteExpando = jQuery.support.deleteExpando;
  7. for ( var i = 0, elem; (elem = elems[i]) != null; i++ ) { //遍历每个匹配元素
  8. if ( elem.nodeName && jQuery.noData[elem.nodeName.toLowerCase()] ) { //如果不支持设置属性,则跳过本次循环。 jQuery.noData是一个数组,保存了不支持扩展属性的节点名称。
  9. continue;
  10. }
  11. id = elem[ jQuery.expando ]; //属性名,注1
  12.  
  13. if ( id ) { //如果该DOM对象有jQuery.expando属性,则表示设置过数据。
  14. data = cache[ id ];
  15. if ( data && data.events ) { //如果DOM的关联数据缓存对象存在且含有events属性,说明在该DOM上绑定过事件,则移除
  16. for ( var type in data.events ) { //data.events是DOM元素的事件缓存对象,存储了DOM元素的所有事件
  17. if ( special[ type ] ) {
  18. jQuery.event.remove( elem, type );
  19. // This is a shortcut to avoid jQuery.event.remove's overhead
  20. } else {
  21. jQuery.removeEvent( elem, type, data.handle );
  22. }
  23. }
  24. // Null the DOM reference to avoid IE6/7/8 leak (#7054)
  25. if ( data.handle ) {
  26. data.handle.elem = null;
  27. }
  28. }
  29. if ( deleteExpando ) { //如果jQuery.support.deleteExpando;返回ture,即浏览器支持删除DOM元素上的扩展属性
  30. delete elem[ jQuery.expando ]; //删除DOM元素的jQuery.expando属性
  31. } else if ( elem.removeAttribute ) { //如果浏览器不支持删除DOM元素上的扩展属性,则调用removeAttribute删除属性
  32. elem.removeAttribute( jQuery.expando );
  33. }
  34. delete cache[ id ]; //删除DOM元素的数据缓存对象cache[id]
  35. }
  36. }
  37. }
  38. /**/
  39. })

注1:jQuery绑定的事件对应的信息都存在$.cache里,键名是对应DOM对象的jQuery.expando,也就是这里的elem[ jQuery.expando ],有疑问可以看看之前事件的讲解:https://www.cnblogs.com/greatdesert/p/11679334.html

cleanData就是删除参数elems里所有DOM元素的事件,本节的empty()和remove()都是基于cleanData实现的,empty()实现如下:

  1. jQuery.fn.extend({
  2. empty: function() { //从文档中移除匹配元素的所有子元素。
  3. for ( var i = 0, elem; (elem = this[i]) != null; i++ ) { //遍历当前匹配的每个元素
  4. // Remove element nodes and prevent memory leaks
  5. if ( elem.nodeType === 1 ) {
  6. jQuery.cleanData( elem.getElementsByTagName("*") ); ////先移除所有后代元素关联的数据和事件,以避免内存泄漏
  7. }
  8. // Remove any remaining nodes
  9. while ( elem.firstChild ) { //然后移除子元素。
  10. elem.removeChild( elem.firstChild );
  11. }
  12. }
  13. return this;
  14. },
  15. })

empty()内首先调用cleanData()移除所有子孙节点的数据和事件,然后通过一个while()循环卸载掉每个DOM节点,比较好理解哈,对于remove()来说,实现如下:

  1. jQuery.fn.extend({
  2. remove: function( selector, keepData ) { //从匹配元素中移除selector元素,该方法会遍历匹配元素集合,先删除后代元素和匹配元素的数据和事件,以避免内存泄漏,然后移除匹配元素。
  3. for ( var i = 0, elem; (elem = this[i]) != null; i++ ) { //遍历当前匹配元素
  4. if ( !selector || jQuery.filter( selector, [ elem ] ).length ) { //如果没有传入selector参数,或者传入了selector参数,并且当前元素与之匹配
  5. if ( !keepData && elem.nodeType === 1 ) { //如果没有传入keepData参数且elem是元素节点
  6. jQuery.cleanData( elem.getElementsByTagName("*") ); //移除后代元素的全部数据和事件
  7. jQuery.cleanData( [ elem ] ); //移除元素节点。
  8. }
  9. if ( elem.parentNode ) { //调用原生方法removeChild()移除节点。
  10. elem.parentNode.removeChild( elem );
  11. }
  12. }
  13. }
  14. return this;
  15. },
  16. detach: function( selector ) {
  17. return this.remove( selector, true ); //调用remove()来实现的,参数2传入了true
  18. },
  19. })

remove()方法会根据selector来选择匹配元素,并将该匹配元素从DOM树中卸载,如果有传入keepData则保存数据,否则将数据删除,对于detach来说,就是调用remove()来实现的

原文链接:http://www.cnblogs.com/greatdesert/p/11813539.html

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号