d3.js 直接子级的d3选择器

qlzsbp2j  于 2022-11-12  发布在  其他
关注(0)|答案(8)|浏览(229)

我显然可以这样做:

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,并从源头上解决了这个问题,没有任何问题!(为了方便起见,我会把它复制在这里,但人们可能不会向下滚动,为他的英雄壮举投下当之无愧的赞成票。)

vwkv1x7d

vwkv1x7d1#

我不希望这样做,但看起来D3将子选择任何作为选择 * 的子元素并且 * 与选择器匹配的元素-所以这样做是可行的:

d3.select(this).selectAll('div > ul');

请参阅http://jsfiddle.net/g3aay/2/

snz8szmq

snz8szmq2#

如果有人仍然感兴趣,d3.select(this.childNodes)正在帮助我解决选择所有直接子对象的问题。

selection.select(function(){
  return this.childNodes;
})
cnjp1d6j

cnjp1d6j3#

d3 selection v2.0现在应该内置了新的selection.selectChildren()/selection.selectChild()方法-请参见https://github.com/d3/d3-selection/issues/243

9ceoxa92

9ceoxa924#

@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();
});
tv6aics1

tv6aics15#

selectAll方法依赖于querySelectorAll本机方法(至少在v4中)。
这意味着您可以使用:scope伪选择器:

var uls = div.selectAll(':scope > ul')

:scope伪选择器目前是一个草案规范,并不是所有的浏览器都支持它。有关:scope伪选择器的更多信息,请访问MDN

fafcakar

fafcakar6#

基于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(afaik)引用的全局名称。
包含此文件后,您可以执行以下操作:

d3.select('#some_id').MYPREFIX_selectChildren('ul')
thtygnil

thtygnil7#

看起来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)));
}

如果您使用的是typescript,则可以在同一个文件中包含以下函数声明:

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/

gtlvzcf8

gtlvzcf88#

无论四年后它的价值如何,都可以使用​d3.selectAll('#id > *'),例如,在​d3.selectAll('#id > *').remove()中,删除id= id的元素的所有子元素

相关问题