我显然可以做到这一点:
d3.selectAll('div#some-div>ul')
但是如果我使用 DOM 节点或现有的 D3 选择怎么办:
d3.select(this).selectAll('ul')
将为我提供所有后代 UL。所以,如果
var div = d3.select('div')
给我这个节点:
<div>
<ul>
<li>foo
<ul><li>bar</li></ul>
</li>
<ul>
</div>
然后
var uls = div.selectAll('ul')
会给我两个 UL。我想我可以区分出顶级的:
uls.filter(function() { return this.parentNode === div.node() }
所以,我已经回答了我自己的问题。也许这对某人有用。或者也许有人可以推荐一个不那么丑陋的解决方案。
更好的是,Alain Dumesny,他的下面的答案后来被选为正确的,将其作为问题发布到 D3 并从源头解决了问题,没有拼凑!(为了方便起见,我将其复制到此处,但是那么人们可能不会向下滚动并为他的英雄壮举投下应有的赞成票。)
我没想到这会起作用,但看起来 D3 会子选择作为选择的子元素的任何元素 并且 与选择器匹配 - 所以这有效:
d3.select(this).selectAll('div > ul');
如果有人仍然感兴趣,
d3.select(this.childNodes)
正在帮助我解决挑选所有直系孩子的问题。或者,您可以使用
selection.select(function(){
return this.childNodes;
})
d3 Selection v2.0 现在应该使用新的
selection.selectChildren()
/ selection.selectChild()
方法内置此功能 - 请参阅 https://github.com/d3/d3-selection/issues/243
@nrabinowitz 的解决方案并不总是有效。
就我而言,我正在尝试做
d3.select(this).selectAll(".childNode > *")
。
所以我试图获取 .childNode 的所有直接子节点。问题是这是一个嵌套堆栈,因此 .childNode 也可能出现在子级中,这会导致问题。
我发现的最好方法是:
var child = d3.select(this).select(".childNode");
var sel = d3.select(this).selectAll(".childNode > *").filter(function() {
return this.parentNode == child.node();
});
基于 Sigfrid 的解决方案,以下是我在我从事的项目中添加到原型中的内容。
/**
* Helper that allows to select direct children.
* See https://stackoverflow.com/questions/20569670/d3-selector-for-immediate-children
*
* @param {string} selector
* @returns {Selection}
*/
d3.selectAll('__nonexisting__').__proto__.MYPREFIX_selectChildren = function (selector) {
var expectedParent = this.node();
return this.selectAll(selector).filter(
function() {
return this.parentNode === expectedParent;
}
);
};
我获取原型对象的方式看起来有点笨拙。也许有更好的方法。
“MYPREFIX_”旨在防止名称冲突。
jsdoc
@returns {Selection}
不明确,不幸的是,这种类型是在闭包中声明的,并且没有 jsdoc 可引用的全局名称(据我所知)。
包含此文件后,您可以执行以下操作:
d3.select('#some_id').MYPREFIX_selectChildren('ul')
看起来 d3 曾经构建了一些函数来解决这个确切的问题 - 但由于某种原因它们被删除了。 通过将此代码粘贴到您的程序中,您可以再次将它们添加回来:
function childMatcher(selector) {
return function(node) {
return node.matches(selector);
};
}
function children() {
return this.children;
}
function childrenFilter(match) {
return function() {
return Array.prototype.filter.call(this.children, match);
};
}
/**
* Runs the css selector only on the immediate children.
* See: https://stackoverflow.com/questions/20569670/d3-selector-for-immediate-children
* Use: https://github.com/d3/d3-selection/commit/04e9e758c80161ed6b7b951081a5d5785229a8e6
*
* Example Input: selectChildren("form")
*/
d3.selection.prototype.selectChildren = function(match) {
return this.selectAll(match == null ? children
: childrenFilter(typeof match === "function" ? match : childMatcher(match)));
}
function childFind(match) {
return function() {
return Array.prototype.find.call(this.children, match);
};
}
function childFirst() {
return this.firstElementChild;
}
/**
* Runs the css selector only on the immediate children and returns only the first match.
* See: https://stackoverflow.com/questions/20569670/d3-selector-for-immediate-children
* Use: https://github.com/d3/d3-selection/commit/04e9e758c80161ed6b7b951081a5d5785229a8e6
*
* Example Input: selectChild("form")
*/
d3.selection.prototype.selectChild = function(match) {
return this.select(match == null ? childFirst
: childFind(typeof match === "function" ? match : childMatcher(match)));
}
如果您使用的是打字稿,那么这里是您可以包含在同一文件中的函数声明:
declare module "d3" {
interface Selection<GElement extends d3.BaseType, Datum, PElement extends d3.BaseType, PDatum> {
selectChild(match: string | null | Function): Selection<GElement, Datum, PElement, PDatum>;
selectChildren(match: string | null | Function): Selection<GElement, Datum, PElement, PDatum>;
}
}
这是实现此功能的小提琴:https://jsfiddle.net/Kade333/drw3k49j/12/
无论四年后它的价值如何,都可以使用
d3.selectAll('#id > *')
,例如在 d3.selectAll('#id > *').remove()
中删除 id=id
的元素的所有子元素