一般来说,直接导入整个d3,我们会这么写:
import * as d3 from 'd3';
这样,我们就可以像在js里一样,使用熟悉的d3.select
了。
但是因为不想一次性导入整个d3给项目增加大小,所以我就对d3进行了按模块导入:
import * as d3 from 'd3-selection';
这个其实也不影响select,但是因为我想给一个div增加transition的效果,就写了这么一段代码:
div.transition()
.duration(500)
.style('opacity', 0.9);
这个看起来是没啥问题的,但是使用的时候控制台就会报错div.transition() is not a function
。上网查了一下,有很多人说升级d3的版本,但是我用的是最新的5.x,而且transition方法是在d3-selection这个模块里的:
declare module 'd3-selection' {
interface Selection<GElement extends BaseType, Datum, PElement extends BaseType, PDatum> {
transition(name?: string): Transition<GElement, Datum, PElement, PDatum>;
}
}
找了很长时间,后来发现,事实上transition方法是通过d3-transition这个模块挂载到selection上的,并不属于d3-selection这个模块本身。我们可以看看d3的源码(省略了无关的部分):
// node_modules/d3-transition/src/selection/index.js
import {selection} from "d3-selection";
import selection_transition from "./transition.js";
selection.prototype.transition = selection_transition;
所以,如果直接导入d3-selection,是肯定找不到这个方法的。解决方案很简单,就是添加一个依赖,导入这个包:
import * as d3 from 'd3-selection';
import 'd3-transition';
但是,为什么会有这种误导呢,是d3写错了吗?再仔细看看package.json:
"devDependencies": {
"@types/d3": "^5.7.2"
}
原因就在这里了。因为导入的是整个d3的类型声明,他默认我已经导入了全部的依赖,所以才会把transition方法放到Selection接口里。如果我们看一下d3-selection模块的类型声明(node_modules/@types/d3-selection/index.d.ts
),就会发现,里面并没有transition方法。
所以,不仅仅在导入依赖的时候要正确导入,而且在node_modules里的依赖也要正确。