d3 错误:DOMException:无法在“Node”上执行“insertBefore”:新的子元素包含父元素

问题描述 投票:0回答:1

我在使用以下代码时遇到错误。

const div = d3.select('div');

const t = d3.timer((e) => {
  const outerOneData = d3.range(0,5);
  const outerTwoData = d3.range(0,3);
  
  const outerOne = div.selectAll('div');

  
  outerOne.exit().remove();
  
  outerOne.data(outerOneData)
    .join('xhtml:div')
    .attr('id',(_,i)=>`outer${i}`);
    
 const outerTwo = outerOne.selectAll('div');  
  
   outerTwo.exit().remove();
  
  outerTwo.data(outerTwoData)
    .join('xhtml:div')
    .attr('id',(_,i)=>`outerTwo${i}`);
  
  
  if (e > 200) t.stop();
}, 150);
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<script type="text/javascript" src="https://d3js.org/d3.v7.min.js"></script>
<body>   
    <div id="viz"></div>
</body>
<script>
</script>
</html>

但不适用于以下内容(当我只做一个级别时)。

const div = d3.select('div');

const t = d3.timer((e) => {
  const outerOneData = d3.range(0,5);
  const outerTwoData = d3.range(0,3);
  
  const outerOne = div.selectAll('div');

  
  outerOne.exit().remove();
  
  outerOne.data(outerOneData)
    .join('xhtml:div')
    .attr('id',(_,i)=>`outer${i}`);
    
 /*const outerTwo = outerOne.selectAll('div');  
  
   outerTwo.exit().remove();
  
  outerTwo.data(outerTwoData)
    .join('xhtml:div')
    .attr('id',(_,i)=>`outerTwo${i}`);*/
  
  
  if (e > 200) t.stop();
}, 150);
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<script type="text/javascript" src="https://d3js.org/d3.v7.min.js"></script>
<body>   
    <div id="viz"></div>
</body>
<script>
</script>
</html>

我打算 d3 给我以下 DOM 中的数据绑定结构

└── doc
    ├── <div id='viz'>
    │   └── <div id='outer0'>
    │       ├── <div id='inner0'>
    │       ├── <div id='inner1'>
    │       └── <div id='inner2'>
javascript d3.js
1个回答
0
投票

问题在于您在 D3 中使用的层次结构和选择机制。

在第一个示例中,将数据绑定到outerOne并创建div元素后,您立即尝试选择其中的div元素并将数据绑定到outerTwo。由于 D3 的工作原理,此操作本质上是有缺陷的:

  1. 您选择了 div 内的所有 div。
  2. 您为outerOne 绑定数据并附加子div。
  3. 然后,您立即尝试选择outerOne内的所有div(这将有效地重新选择outerOne div)并绑定另一组数据,这与之前的数据绑定冲突。

这会导致 D3 尝试将子 div (outerTwo) 附加到其自身或其直接父级 (outerOne),从而导致 DOMException 错误。

修复第一个示例:

  1. 在主 div (outerOne) 和子 div (outerTwo) 之间建立明确的区别。
  2. 避免使用可能在层次结构中重叠的通用选择器。相反,使用类名称或其他属性来将选择范围缩小到预期元素。

这是更正后的版本

const div = d3.select('#viz');

const t = d3.timer((e) => {
    const outerOneData = d3.range(0, 5);
    const outerTwoData = d3.range(0, 3);

    // Bind outerOneData to top-level divs
    const outerOne = div.selectAll('.outerOne').data(outerOneData);

    // Create/Update/Remove top-level divs
    outerOne
        .join('div')
        .classed('outerOne', true)  // Assign a class to distinguish them
        .attr('id', (_, i) => `outer${i}`)
        .selectAll('.outerTwo')    // Now select child divs inside each outerOne div
        .data(() => outerTwoData)  // Bind outerTwoData to child divs
        .join('div')
        .classed('outerTwo', true) // Assign a class to distinguish them
        .attr('id', (_, i) => `outerTwo${i}`);

    // Remove divs no longer in the data
    outerOne.exit().remove();

    if (e > 200) t.stop();
}, 150);
© www.soinside.com 2019 - 2024. All rights reserved.