遍历 DOM 注意点

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

内容简介:版权声明:本文为博主原创文章,未经博主允许不得转载。 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;
            }
        }
    }

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

查看所有标签

猜你喜欢:

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

Learning PHP 5

Learning PHP 5

David Sklar / O'Reilly / July, 2004 / $29.95

Learning PHP 5 is the ideal tutorial for graphic designers, bloggers, and other web crafters who want a thorough but non-intimidating way to understand the code that makes web sites dynamic. The book ......一起来看看 《Learning PHP 5》 这本书的介绍吧!

JSON 在线解析
JSON 在线解析

在线 JSON 格式化工具

RGB CMYK 转换工具
RGB CMYK 转换工具

RGB CMYK 互转工具

HSV CMYK 转换工具
HSV CMYK 转换工具

HSV CMYK互换工具