首页 > 代码库 > matchesSelector及低版本IE中对该方法的实现

matchesSelector及低版本IE中对该方法的实现

matchesSelector用来匹配dom元素是否匹配某css selector。它为一些高级方法的实现提供了基础支持,比如事件代理,parent, closest等。

W3C在2006年就提出了该方法草案,Firefox和Safari相继实现,比如

?
1
2
3
4
5
6
<div id="wraper" class="item"></div>
<script>
    wraper.mozMatchesSelector(‘div‘) // true 标签选择器
    wraper.mozMatchesSelector(‘#wraper‘) // true id选择器
    wraper.mozMatchesSelector(‘.item‘) // true 类选择器
</script>

  

目前除IE6-IE8,Firefox/Chrome/Safari/Opera/IE 的最新版本均已实现,但方法都带上了各自的前缀

Chrome/Safari

 

Firefox

 

IE9+

 

可以用特性监测来获取一个统一接口API。如下

?
1
2
3
4
var matchesSelector = function() {
    var body = document.body
    return body.webkitMatchesSelector || body.msMatchesSelector || body.mozMatchesSelector || body.oMatchesSelector
}()

有两个细节

1.  优先使用body.webkitMatchesSelector webkit内核占有率最高,尤其国内国产浏览器的高速引擎是webkit

2.  这里没有优选获取body.matchesSelector,是因为该方法迄今尚未标准化

3.  2013年2月Opera放弃Presto转向Webkit,因此把body.oMatchesSelector放在了最后以兼容老版本的Opera

 

对于低版本的IE,如何实现该方法吗? 首先需要实现一个基本的CSS选择器,这里提供了一个常用选择器(id,class,tagName,attribute)的实现。

 

两种情况

1. 对于已经存在于页面里的DOM元素

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
function matches(el, selector) {
    var parent = el.parentNode
    var match = query(selector, parent)
    var len = match.length
    if (len) {
        while (len--) {
            if (match[len] == el) {
                return true
            }
        }
        return false
    } else {
        return false
    }
}

存在于页面的DOM元素,必定有parentNode,紧接着在父节点里查找指定的selector,如果不存在返回false,如果存在还有过滤下,如果匹配的元素和传入的el是同一个元素则返回true。

 

2. 对于动态创建的元素,尚未添加到页面中

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
function matches(el, selector) {
    var tempParent = document.createElement(‘div‘)
    tempParent.appendChild(el)
    match = query(selector, tempParent)
    tempParent.removeChild(el)
    return !!match.length
}
 
var pp = document.createElement(‘p‘)
pp.id = ‘pp‘
pp.className = ‘pp1‘
pp.setAttribute(‘data-info‘, ‘Jack‘)
pp.innerHTML = ‘test‘
 
matches(pp, ‘p‘) // true
matches(pp, ‘#pp‘) // true
matches(pp, ‘.pp1‘) // true
matches(pp, ‘[data-info=jack]‘) // true

此时该元素师没有父元素的,这里创建了一个临时的父元素,添加子元素后再把它删掉。剩余思路同上。

 

两种情况合并一起就完成了对IE9-版本浏览器的支持

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
function matches(el, selector) {
    var parent = el.parentNode
    var match = query(selector, parent)
    var len = match.length
 
    if (parent) {
        if (len) {
            while (len--) {
                if (match[len] == el) {
                    return true
                }
            }
            return false
        } else {
            return false
        }
    } else {
        var parent = document.createElement(‘div‘)
        parent.appendChild(el)
        match = query(selector, parent)
        parent.removeChild(el)
        return !!match.length  
    }
}

 

最后是一个完成版本

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
var matchesSelector = function() {
    var body = document.body
    var w3cMatches = body.webkitMatchesSelector || body.msMatchesSelector || body.mozMatchesSelector || body.oMatchesSelector
     
    function matches(el, selector) {
        return w3cMatches.call(el, selector)
    }
 
    function lowIEMatches(el, selector) {
        var parent = el.parentNode
        var match = query(selector, parent)
        var len = match.length
 
        if (parent) {
            if (len) {
                while (len--) {
                    if (match[len] == el) {
                        return true
                    }
                }
                return false
            } else {
                return false
            }
        } else {
            var parent = document.createElement(‘div‘)
            parent.appendChild(el)
            match = query(selector, parent)
            parent.removeChild(el)
            return !!match.length  
        }
    }
 
    return w3cMatches ? matches : lowIEMatches
}()

  

 

相关:

http://dev.w3.org/2006/webapi/selectors-api2/#matchtesting

https://developer.mozilla.org/zh-CN/docs/Web/API/Element.matches

http://msdn.microsoft.com/en-us/library/ie/ff975201(v=vs.85).aspx