前沿
这是之前淘宝的一道面试题,题目借用了 jQuery 选择器的语法。大概的意思是,从 #id
元素内选出所有不是 .c
后代的 a
元素,即父元素 #id 内的所有后代元素中,选出不是 .c 后代元素里的所有a元素。题目主要考察的是 DOM 操作的知识,来筛选DOM元素,并且不能使用jQuery等框架。
思路
先选出所有 a
元素。对每个 a
元素,从其所在位置沿着 DOM 树往上搜索,每走一步对比当前节点类名,含有 c 类
立刻中止,否则继续上行直至根节点或父元素(#id
)处,结束搜索并将 a
元素加入结果集里。对全部 a
元素执行完该操作后,返回结果集。
查找过程的流程图如下:
js核心代码:
// 参数依次为根元素、给出的类名、目标元素(即一一对应题目中的$("#id .c a")) var domSelector = function(rootId, filterClass, targetTag) { var root = document.getElementById(rootId), nodes = root.getElementsByTagName(targetTag), resultArr = [], i, len; // 沿着DOM树查找 var ascend = function(start, end, current) { if(current === end) { // 查找成功 resultArr.push(start); // 没查找到则继续沿着DOM树往上搜索(递归调用) } else if((" " + current.className.toLowerCase() + " ").indexOf(" " + filterClass + " ") == -1) { ascend(start, end, current.parentNode); } }; for (i = 0, len = nodes.length; i < len; i++) { ascend(nodes[i], root, nodes[i].parentNode); // 循环便利 } return resultArr; };
测试:
HTML结构:
调用函数:
// 测试 window.onload = function() { // 调用函数 var res = domSelector("id", "c", "a"); console.log(res); // 返回一个数组:[a.A1, a.A3] };
结语
由于过多的DOM遍历会导致性能问题,所以递归调用的方法可能会存在效率上的问题。所以各自权衡吧~