编写一个 match 函数。它接受两个参数,第一个参数是一个选择器字符串性质,第二个是一个 HTML 元素。这个元素你可以认为它一定会在一棵 DOM 树里面。通过选择器和 DOM 元素来判断,当前的元素是否能够匹配到我们的选择器。(不能使用任何内置的浏览器的函数,仅通过 DOM 的 parent 和 children 这些 API,来判断一个元素是否能够跟一个选择器相匹配。)以下是一个调用的例子。
<div id="id1" class="class1">
<div id='id2' class='class2 class3'>
<div id='id3' class='class4 class5 class6'></div>
</div>
</div>
function match(selector, element) {
let selector_arr = selector.split(' ');//获取element层级
let parent_arr = [];//用于保存父节点
let selector_re = /(\w+)|(\.\w+)|(\#\w+)/g;
for(let i = 0; i < selector_arr.length; i++){
parent_arr.push(selector_arr[i].match(selector_re));
}
let matched = true;
//从当前节点开始向上循环
for (let j = parent_arr.length-1;j>=0;j--){
if(!currentElementMatch(parent_arr[j], element)){
matched = false;
break;
}
element = element.parentNode;
}
return matched;
}
function currentElementMatch(currSelector, currElement){
let hasId = false, hasClass = false, hasTag = false;
let idMatch = false, classMatch = false, tagMatch = false;
for(let i = 0; i<currSelector.length;i++;){
if(currSelector[i].charAt(0) === '#'){
hasId = true;
if(currElement.id === currSelector[i].replace('#','')){
idMatch = true;
}
}else if(currSelector[i].charAt(0) === '.'){
hasClass = true;
classMatch = false;//因为class可能有多个,所以没判断一个class这里都要先置为false
for(let j = 0;j<currElement.classList.length; j++){
if(currElement.classList[j] === currSelector[i].replace('.','')){
classMatch = true;
break;
}
}
}else{
hasTag = true;
if(currElement.tagName.toLowerCase() === currSelector[i]){
tagMatch = true;
}
}
}
return ((hasId && idMatch) || !hasId) && ((hasClass && classMatch) || !hasClass) && ((hasTag && tagMatch) || !hasTag)
}
match("#id1.class1 div.class2.class3 div#id3.class4.class5.class6", document.getElementById("id3"));