这篇依然是跟 dom
相关的方法,侧重点是跟集合元素查找相关的方法。
读Zepto源码系列文章已经放到了github上,欢迎star: reading-zepto
源码版本
本文阅读的源码为 zepto1.2.0
内部方法
之前有一章《读Zepto源码之内部方法》是专门解读 zepto
中没有提供给外部使用的内部方法的,但是有几个涉及到 dom
的方法没有解读,这里先将本章用到的方法解读一下。
matches
zepto.matches = function(element, selector) {
if (!selector || !element || element.nodeType !== 1) return false
var matchesSelector = element.matches || element.webkitMatchesSelector ||
element.mozMatchesSelector || element.oMatchesSelector ||
element.matchesSelector
if (matchesSelector) return matchesSelector.call(element, selector)
// fall back to performing a selector:
var match, parent = element.parentNode,
temp = !parent
if (temp)(parent = tempParent).appendChild(element)
match = ~zepto.qsa(parent, selector).indexOf(element)
temp && tempParent.removeChild(element)
return match
}
matches
方法用于检测元素( element
)是否匹配特定的选择器( selector
)。
浏览器也有原生的 matches
方法,但是要到IE9之后才支持。具体见文档:Element.matches()
if (!selector || !element || element.nodeType !== 1) return false
这段是确保 selector
和 element
两个参数都有传递,并且 element
参数的 nodeType
为 ELEMENT_NODE
,如何条件不符合,返回 false
var matchesSelector = element.matches || element.webkitMatchesSelector ||
element.mozMatchesSelector || element.oMatchesSelector ||
element.matchesSelector
if (matchesSelector) return matchesSelector.call(element, selector)
这段是检测浏览器是否原生支持 matches
方法,或者支持带私有前缀的 matches
方法,如果支持,调用原生的 matches
,并将结果返回。
var match, parent = element.parentNode,
temp = !parent
if (temp)(parent = tempParent).appendChild(element)
match = ~zepto.qsa(parent, selector).indexOf(element)
temp && tempParent.removeChild(element)
return match
如果原生的方法不支持,则回退到用选择器的方法来检测。
这里定义了三个变量,其中 parent
用来存放 element
的父节点, temp
用来判断 element
是否有父元素。值为 temp = !parent
,如果 element
存在父元素,则 temp
的值为 false
。
首先判断是否存在父元素,如果父元素不存在,则 parent = tempParent
,tempParent
已经由一个全局变量来定义,为 tempParent = document.createElement('div')
,其实就是一个 div
空节点。然后将 element
插入到空节点中。
然后,查找 parent
中所有符合选择器 selector
的元素集合,再找出当前元素 element
在集合中的索引。
zepto.qsa(parent, selector).indexOf(element)
再对索引进行取反操作,这样索引值为 0
的值就变成了 -1
,是 -1
的返回的是 0
,这样就确保了跟 matches
的表现一致。
其实我有点不太懂的是,为什么不跟原生一样,返回 boolean
类型的值呢?明明通过 zepto.qsa(parent, selector).indexOf(element) > -1
就可以做到了,接口表现一致不是更好吗?
最后还有一步清理操作:
temp && tempParent.removeChild(element)
将空接点的子元素清理点,避免污染。
children
function children(element) {
return 'children' in element ?
slice.call(element.children) :
$.map(element.childNodes, function(node) { if (node.nodeType == 1) return node })
}
children
方法返回的是 element
的子元素集合。
浏览器也有原生支持元素 children
属性,也要到IE9以上才支持,见文档ParentNode.children
如果检测到浏览器不支持,则降级用 $.map
方法,获取 element
的 childNodes
中 nodeType
为 ELEMENT_NODE
的节点。因为 children
返回的只是元素节点,但是 childNodes
返回的除元素节点外,还包含文本节点、属性等。
这里用到的 $.map
跟数组的原生方法 map
表现有区别,关于 $.map
的具体实现,已经在《读zepto源码之工具函数》解读过了。
filtered
function filtered(nodes, selector) {
return selector == null ? $(nodes) : $(nodes).filter(selector)
}
将匹配指定选择器的元素从集合中过滤出来。
如果没有指定 selector
,则将集合包裹成 zepto
对象全部返回,否则调用 filter
方法,过滤出符合条件的元素返回。filter
方法下面马上讲到。
元素方法
这里的方法都是 $.fn
中提供的方法。
.filter()
filter: function(selector) {
if (isFunction(selector)) return this.not(this.not(selector))
return $(filter.call(this, function(element) {
return zepto.matches(element, selector)
}))
}
filter
是查找符合条件的元素集合。
参数 selector
可以为 Function
或者选择器,