有没有一种方法可以在不直接操作DOM的情况下使用d3轴?

我目前正在使用一个简单的Vue模板来生成SVG.

我希望避免使用d3.select来防止直接修改DOM.它运行良好,但与Vue冲突.js的范围样式.

有没有一种方法可以在不从DOM元素调用的情况下访问d3-axis?如果能够独立地访问其path生成函数,而不是通过DOM访问,这将非常有用.

下面是一个示例代码笔:https://codepen.io/thibautg/pen/BYRBXW

推荐答案

这种情况需要custom directive美元.自定义指令允许您在它们附加到的元素中操作DOM.

在本例中,我创建了一个指令,它接受一个参数,该参数的轴和一个值是您计算的比例.根据轴是x还是y,它用scale[axis]调用axisBottomaxisLeft.

别再看了.该指令将在任何更新时调用.如果你愿意的话,你可以判断一下scale是否与之前的值相比发生了变化.

new Vue({
  el: "#app",
  data() {
    return {
      width: 600,
      height: 400,
      margin: {
        top: 20,
        right: 20,
        bottom: 20,
        left: 20
      },
      items: [
        { name: "a", val: 10 },
        { name: "b", val: 8 },
        { name: "c", val: 1 },
        { name: "d", val: 5 },
        { name: "e", val: 6 },
        { name: "f", val: 3 }
      ]
    };
  },
  computed: {
    outsideWidth() {
      return this.width + this.margin.left + this.margin.right;
    },
    outsideHeight() {
      return this.height + this.margin.top + this.margin.bottom;
    },
    scale() {
      const x = d3
        .scaleBand()
        .domain(this.items.map(x => x.name))
        .rangeRound([0, this.width])
        .padding(0.15);
      const y = d3
        .scaleLinear()
        .domain([0, Math.max(...this.items.map(x => x.val))])
        .rangeRound([this.height, 0]);
      return { x, y };
    }
  },
  directives: {
    axis(el, binding) {
      const axis = binding.arg;
      const axisMethod = { x: "axisBottom", y: "axisLeft" }[axis];
      const methodArg = binding.value[axis];

      d3.select(el).call(d3[axisMethod](methodArg));
    }
  }
});
rect.bar {
  fill: steelblue;
}
<script src="//unpkg.com/vue@latest/dist/vue.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/d3/4.11.0/d3.min.js"></script>
<div id="app">
  <svg :width="outsideWidth"
       :height="outsideHeight">
    <g :transform="`translate(${margin.left},${margin.top})`">
      <g class="bars">
        <template v-for="item in items">
          <rect class="bar"
                :x="scale.x(item.name)"
                :y="scale.y(item.val)"
                :width="scale.x.bandwidth()"
                :height="height - scale.y(item.val)"
                />
        </template>
        <g v-axis:x="scale" :transform="`translate(0,${height})`"></g>
        <g v-axis:y="scale"></g>
      </g>
    </g>
  </svg>
</div>

Vue.js相关问答推荐

正在try 访问vutify中v-select(ItemProps)的嵌套json值

在VITE-VUE APP-DEV模式上重定向HTTP请求

如何在与父集合相同的读取中取回子集合(或重构数据?)

Vuetify快速失败不会阻止发送表单

如何在vue js模板中添加foreach和for循环

在 Vue.js 2.6 的 Javascript 中访问 的内容

为什么普通对象在 Vue3 中自动变成响应式的?

如果在 VueJS/VuetifyJS 中切换switch,则调用函数

两个div元素之间的vue2过渡

有没有办法初始化一个保留初始 HTML 的 Vue 对象

如何为使用 Vuex store的 Vue 表单组件编写 Jest 单元测试?

根据 URL 有条件地隐藏视图组件

为什么 CSS 关键帧动画在具有范围样式的 Vue 组件中被 destruct ?

如何使用 vuex 删除项目?

如何在 Node.js 服务器上部署 Vue.js 应用程序

如何使用 vue.js 获取所选选项的索引

触发子函数

执行调度程序刷新期间未处理的错误,这可能是一个 Vue 内部错误

使用 axios 和 vue.js 取消先前的请求

使用 Vee-validate 禁用按钮,直到正确填写表单