D3 仅在 Vue 3 组件的第一个实例中正常工作

Posted

技术标签:

【中文标题】D3 仅在 Vue 3 组件的第一个实例中正常工作【英文标题】:D3 working properly only in first instance of Vue 3 component 【发布时间】:2021-10-31 04:37:00 【问题描述】:

我正在开发 Vue 3 应用程序,我想在其中使用一个组件的多个实例。每个组件都应该有它的 D3 实例来显示各种 SVG 图像。在我的情况下,D3 仅在 Vue 组件的第一个实例上按预期工作。

点是由 D3 随机生成的。在检查元素时,我可以看到在组件的第二个实例中没有附加任何点。问题截图可以找到here.

我的 D3 组件如下所示:

<template>
  <div class="fill-100">
    <svg ref="svgRef"  height=667>
      <g></g>
    </svg>
  </div>
</template>

<script>

import ref, onMounted from "@vue/runtime-core";
import select, zoom from "d3";

export default 
  name: "SldSvgD3",
  props: ["id"],
  setup() 
    const svgRef = ref(null);

    onMounted(() =>
      const svg = select(svgRef.value);
      svg.append("svg")


      let data = [], width = 400, height = 667, numPoints = 100;

      let zoom3 = zoom()
        .on('zoom', handleZoom);

      function handleZoom(e) 
          select('svg g')
          .attr('transform', e.transform);
      

      function initZoom() 
        select('svg')
          .call(zoom3);
      

      function updateData() 
        data = [];
        for(let i=0; i<numPoints; i++) 
          data.push(
            id: i,
            x: Math.random() * width,
            y: Math.random() * height
          );
        
      

      function update() 
        select('svg g')
          .selectAll('circle')
          .data(data)
          .join('circle')
          .attr('cx', function(d)  return d.x; )
          .attr('cy', function(d)  return d.y; )
          .attr('r', 3);
      

      initZoom();
      updateData();
      update();

    );

    return svgRef
  


</script>


<style lang="scss">
  .fill-100
    width: 100%;
    height: 100%;
  
</style>

D3 缩放和平移的实现取自this site

【问题讨论】:

【参考方案1】:

我不知道d3.select() 调用的范围对于整个应用程序来说是全局的。在我的情况下,解决方案只是为根 div 创建唯一的 id 并在任何操作之前选择此 div

This question 对我很有帮助。

完整代码:

<template>
  <div class="fill-100" :id="'sld_div'+this.id">
  </div>
</template>

<script>

import ref, onMounted from "@vue/runtime-core";
import * as d3 from "d3";

export default 
  name: "SldSvgD3",
  props: ["id"],
  setup(props) 
    const svgRef = ref(null);
    const svg_width = 400;
    const svg_height = 667;

    onMounted(() =>

        const svg = d3
          .select("#sld_div"+props.id)
        svg.append("svg")
          .attr("id","sld_root"+props.id)
          .attr("width", svg_width)
          .attr("height", svg_height)
        .append("g")
          .attr("id","sld_root_g"+props.id)

      let data = [], width = 600, height = 400, numPoints = 100;

      let zoom = d3.zoom()
        .on('zoom', handleZoom);

      function handleZoom(e) 
        d3.select("#sld_div"+props.id)
          .select('svg g')
          .attr('transform', e.transform);
      

      function initZoom() 
        d3.select("#sld_div"+props.id)
          .select('svg')
          .call(zoom);
      

      function updateData() 
        data = [];
        for(let i=0; i<numPoints; i++) 
          data.push(
            id: i,
            x: Math.random() * width,
            y: Math.random() * height
          );
        
      

      function update() 
        d3.select("#sld_div"+props.id)
          .select('svg g')
          .selectAll('circle')
          .data(data)
          .join('circle')
          .attr('cx', function(d)  return d.x; )
          .attr('cy', function(d)  return d.y; )
          .attr('r', 3);
      

      initZoom();
      updateData();
      update();

    );

    return svgRef
  


</script>


<style lang="scss">
  .fill-100
    width: 100%;
    height: 100%;
  
</style>

【讨论】:

以上是关于D3 仅在 Vue 3 组件的第一个实例中正常工作的主要内容,如果未能解决你的问题,请参考以下文章

仅在添加到刀片页面时导入 Vue 组件

另一个实例视图中的实例视图

仅在加载元素时运行 vue 组件

Vue 什么是组件

Vue中重新渲染组件的方法总结

在vue中使用基于d3为基础的dagre-d3.js搞定一个流程图组件