遍历 DOM 注意点

栏目: JavaScript · 发布时间: 5年前

内容简介:版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/zhangxin09/article/details/86693618

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/zhangxin09/article/details/86693618

在实现一个清理 HTML 冗余标签(word 粘贴过来的)功能,最简单的,莫过于:

// MSWordHtmlCleaners.js https://gist.github.com/ronanguilloux/2915995
	cleanPaste : function(html) {
	    // Remove additional MS Word content
	    html = html.replace(/<(\/)*(\\?xml:|meta|link|span|font|del|ins|st1:|[ovwxp]:)((.|\s)*?)>/gi, ''); // Unwanted
																											// tags
	    html = html.replace(/(class|style|type|start)=("(.*?)"|(\w*))/gi, ''); // Unwanted
																				// sttributes
	    html = html.replace(/<style(.*?)style>/gi, '');   // Style tags
	    html = html.replace(/<script(.*?)script>/gi, ''); // Script tags
	    html = html.replace(/<!--(.*?)-->/gi, '');        // HTML comments
	    
	    return html;
	},

因为某些正则功能的缺失,网页的 JS 正则是不能完全匹配对应标签的。故所以这种通过正则过滤的办法是有潜在问题的。于是考虑另外一种方法,如老外写的这个 http://booden.net/ContentCleaner.aspx,它是通过 DOM 方法删除标签的,——我觉得可行,就拿来改造。遇到的问题不少,记录如下。

首先,他依赖 jQuery,我希望是原生的,开始我以为修改下问题不大,但后来发现没那么容易,首当其冲的是 DOM 遍历。写一个遍历并递归 DOM 的代码不困难,麻烦在于,当你使用 for 遍历,集合的总数是固定的(length),而当你删除了一个元素,等于破坏了这个数组,数组下标也乱了。于是改为 while(firstChild) 循环的方法,有点链表那样的写法,总是会出现死循环的现象,可能是指针有误。

苦于没有办法快放弃的情况下,忽然想起老外那个代码有段函数 removeComments(),想想那正是原生的遍历方法,它是删除注释节点后而继续迭代的。于是拿来改造用,并得到成功!

后来想想,可能这就是迭代器与 for 的区别,因为集合里面的元素允许动态变化,用 for 遍历肯定有问题,这时就适宜用迭代器,诸如 hasNext()、getNextItem() 的 API,尽管会啰嗦点。

在删除 DOM 元素属性时,也遇到这种问题。例如下面代码,每次只能删除一个属性,而不是全部!

var attrs = el.attributes;
for (var i = 0; i < attrs.length; i++) {
    console.log(attrs[i]);
    el.removeAttribute(attrs[i].name);
}

解决方法是如 MDN 所说的,

for(var i = attrs.length - 1; i >= 0; i--) {
	var name = attrs[i].name;
	if (attributesAllowed[tag] == null || attributesAllowed[tag].indexOf("|" + name.toLowerCase() + "|") == -1){
		node.removeAttribute(name);
	}
}

最后,完整的清理 HTML 代码如下

// 清理冗余 HTML
	cleanHTML(){
	    // 类似于 白名单
	    var tagsAllowed = "|h1|h2|h3|p|div|a|b|strong|br|ol|ul|li|pre|img|br|hr|font|";

	    var attributesAllowed = {};
	    attributesAllowed["div"] = "|id|class|";
	    attributesAllowed["a"] = "|id|class|href|name|";
	    attributesAllowed["img"] = "|src|";

	    this.everyNode(this.iframeBody, node => {
	    	var isDelete = false;
	    	
	    	if (node.nodeType === 1) {
	    		var tag = node.tagName.toLowerCase();
	    		if (tagsAllowed.indexOf("|" + tag + "|") === -1)
	    			isDelete = true;
	    		
	    		if (!isDelete) { // 删除属性
	    			var attrs = node.attributes;

	    			for(var i = attrs.length - 1; i >= 0; i--) {
	    				var name = attrs[i].name;
	    				if (attributesAllowed[tag] == null || attributesAllowed[tag].indexOf("|" + name.toLowerCase() + "|") == -1){
	    					node.removeAttribute(name);
	    				}
	    			}
	    		}
	    	} else if (node.nodeType === 8) {// 删除注释
	    		isDelete = true;
	    	}
	    	
	    	return isDelete;
	    });

	},
	
    everyNode (el, fn) {
        var objChildNode = el.firstChild;
        while (objChildNode) {
            if (fn(objChildNode)) { // 返回 true 则删除
                var next = objChildNode.nextSibling;
                el.removeChild(objChildNode);
                objChildNode = next;
            } else {
                if (objChildNode.nodeType === 1) 
                    this.everyNode(objChildNode, fn);

                objChildNode = objChildNode.nextSibling;
            }
        }
    }

以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

设计模式之禅

设计模式之禅

秦小波 / 机械工业出版社 / 2010年3月 / 69.00元

如果说“四人帮”的《设计模式》是设计模式领域的“圣经”,那么之后出版的各种关于设计模式的书都可称之为“圣经”的“注释版”或“圣经的故事”。本书是得道者对“圣经”的“禅悟”,它既不像“圣经”那样因为惜字如金、字字珠玑而深奥、晦涩和难懂,又比“圣经”的“注释版”更深刻和全面、更通俗和生动、更接近开发者遇到的实践场景,更具指导性。本书兼收并蓄、博采众长,也许是设计模式领域里的下一个里程碑之作。 全......一起来看看 《设计模式之禅》 这本书的介绍吧!

Base64 编码/解码
Base64 编码/解码

Base64 编码/解码

MD5 加密
MD5 加密

MD5 加密工具

正则表达式在线测试
正则表达式在线测试

正则表达式在线测试