我正在尝试实现getByClassnameHierarchy,但是实现方面存在问题。 我应该使用BFS而不是DFS遍历节点吗?
有人可以向我解释使用这些方法的方法以及Pro和Con的方法吗?
// Helper function to make output easier to read
const getIds = (elements=[]) => Array.from(elements).map(x => x.id);
/**
* Return all DOM elements who are _leaf_nodes_ that satisfy the hierarchy.
* Hierarchy is a string of class names separated by `>`, akin to
* CSS CHILD SELECTORS.
*
* ex. getByClassnameHierarchy(#root, 'a>b>c') -> [<div class="c" id="c-1"></div>,<div class="c" id="c-2"></div> ]
* "give me all the elements with class name 'c', who have a strict parent with
* class name 'b', who have a strict parent with class name 'a'"
*
* @param root DOMElement: start the search from this DOM element
* @param hierarchy string: `>`-delimited string of classnames
* @return Array<DOMElement>: all DOM elements that satisfy the target hierarchy
*/
function getByClassnameHierarchy(root, hierarchy) {
// parentNode
const res = [];
const level = hierarchy.split('>');
helper(root, level, 0);
return res;
function helper(root, level, cur) {
if(!root) return
if(root.classList && root.classList.contains(level[cur-1])){ // b
if(root.parentNode.classList.contains(level[cur-2])) { // a
if(root.classList.contains(level[cur-1])) {
res.push(root);
}
}
} //c
root.childNodes.forEach(child => {
helper(child, level, cur + 1);
});
}
}
const root2 = document.getElementById('root2');
// // basic case:
console.log('actual: ', getIds(getByClassnameHierarchy(root2, 'a>b>c')));
console.log(`a>b>c expected:` , `['c-1', 'c-2']`, '\n');
<div id="root2">
<div class="a" id="a-1">
<div class="b" id="b-1">
<div class="c" id="c-1"></div>
<div class="c" id="c-2"></div>
</div>
</div>
</div>
问题:
预期返回:[ 'b-1', 'c-1', 'c-2' ]
而不是['c-1', 'c-2']
不确定我要去哪里。
答案 0 :(得分:1)
您可以执行以下操作(查看评论以获取详细信息):
const getIds = (elements = []) => Array.from(elements).map(x => x.id);
function getByClassnameHierarchy(root, hierarchy, level = 0) {
let result = [];
// Grab the class names
const classNames = hierarchy.split('>');
// Retrieve the current (first) one
const currentClassName = classNames[0];
// For each child
root.childNodes.forEach(child => {
// If it contains the given class
if (child.classList && child.classList.contains(currentClassName)) {
// Append the result of the following selector on this child,
// or the child itself if we're at the last part of the selector
result = result.concat(classNames.length > 1
? getByClassnameHierarchy(child, classNames.slice(1).join('>'), level + 1)
: child);
}
// Otherwise, if we're still on the first part of the selector,
// append the result of the same selector on this child
else if (level === 0) {
result = result.concat(getByClassnameHierarchy(child, hierarchy, level));
}
});
return result;
}
// Test
const root2 = document.getElementById('root2');
console.log('a>b>c actual:', getIds(getByClassnameHierarchy(root2, 'a>b>c')));
console.log('a>b>c expected:', ['c-1', 'c-2']);
console.log('b>c actual: ', getIds(getByClassnameHierarchy(root2, 'b>c')));
console.log('b>c expected:', ['c-1', 'c-2', 'c-3', 'c-4']);
console.log('b actual: ', getIds(getByClassnameHierarchy(root2, 'b')));
console.log('b expected:', ['b-1', 'b-2']);
console.log('a>c actual: ', getIds(getByClassnameHierarchy(root2, 'a>c')));
console.log('a>c expected:', []);
<div id="root2">
<div class="a" id="a-1">
<div class="b" id="b-1">
<div class="c" id="c-1"></div>
<div class="c" id="c-2"></div>
</div>
</div>
<div class="b" id="b-2">
<div class="c" id="c-3"></div>
<div class="c" id="c-4"></div>
</div>
</div>