上QQ阅读APP看书,第一时间看更新
6.4 选择器引擎涉及的通用函数
6.4.1 isXML
最强大的前几名选择器引擎都能操作 XML 文档,但 XML 与 HTML 存在很大的差异,没有className,getElementById,并且nodeName是区分大小写,在旧版本IE中还不能直接给XML元素添加自定义属性。因此这区分非常有必要。我们看一下各大引擎的实现吧。
Sizzle的实现如下。
var isXML = Sizzle.isXML = function( elem ) { var documentElement = elem && (elem.ownerDocument || elem).documentElement; return documentElement ? documentElement.nodeName !== "HTML" : false; };
但这样不严谨,因为XML的根节点可能是HTML标签,比如这样创建一个XML文档:
try { var doc = document.implementation.createDocument(null, 'HTML', null); alert(doc.documentElement) alert(isXML(doc)) } catch (e) { alert("不支持creatDocument方法") }
我们来看mootools的slick的实现。
var isXML = function(document) { return ( !! document.xmlVersion) || ( !! document.xml) || (toString.call(document) == '[object XMLDocument]') || (document.nodeType == 9 && document.documentElement.nodeName != 'HTML'); };
mootools用到了大量属性来进行判定,从mootools1.2到现在还没什么改动,说明还是很可靠的。我们再精简一下。在标准浏览器中,暴露了一个创建HTML文档的构造器HTMLDocument,而IE下的XML元素又拥有selectNodes。
var isXML = window.HTMLDocument ? function(doc) { return !(doc instanceof HTMLDocument) } : function(doc) { return "selectNodes" in doc }
不过这些方法都只是规范,JavaScript 对象可以随意添加,属性法很容易被攻破,最好是使用功能法。无论 XML 或HTML 文档都支持 createElement方法,我们判定创建了元素的nodeName是否区分大小写。
var isXML = function(doc) { return doc.createElement("p").nodeName !== doc.createElement("P").nodeName; };
这是我当前能给出的最严谨的函数了。