无法让 D3.js 在 Svelte 组件内工作(使用 Rollup)
Cannot get D3.js to work inside Svelte component (with Rollup)
我一直在尝试将最基本的 D3 示例放入 Svelte 应用程序中,但无法使其正常工作。起初我尝试将 D3 安装为节点模块:npm install d3
但这会产生与从 index.html
内的 CDN 作为外部脚本导入 D3 相同的结果(缺少结果):<script src="https://d3js.org/d3.v5.min.js"></script>
.无论使用哪种方法,我都会在应用程序启动时收到一堆循环依赖警告:
(!) Circular dependency: node_modules\d3-selection\src\selection\index.js -> node_modules\d3-selection\src\selection\select.js -> node_modules\d3-selection\src\selection\index.js
但是app启动没有报错,也没有出现D3动态格式化,也没有在Chrome里面的DevTools控制台弹出任何报错。
Svelte 组件如下所示:
<script>
import * as d3 from 'd3';
var data = [30, 86, 168, 281, 303, 365];
d3.select(".chart")
.selectAll("div")
.data(data)
.enter()
.append("div")
.style("width", function(d) {
return d + "px";
})
.text(function(d) {
return d;
});
</script>
<style>
.chart div {
font: 10px sans-serif;
background-color: steelblue;
text-align: right;
padding: 3px;
margin: 1px;
color: white;
}
</style>
<div class="chart"></div>
将上面的代码放入静态 HTML 文件会按预期生成条形图。但是当 运行 作为 Svelte 组件时,什么都不显示。
我的rollup.config.js是:
import svelte from 'rollup-plugin-svelte';
import resolve from 'rollup-plugin-node-resolve';
import commonjs from 'rollup-plugin-commonjs';
import livereload from 'rollup-plugin-livereload';
import { terser } from 'rollup-plugin-terser';
const production = !process.env.ROLLUP_WATCH;
export default {
input: 'src/main.js',
output: {
sourcemap: true,
format: 'iife',
name: 'app',
file: 'public/bundle.js',
globals: { 'd3': 'd3' },
external: [ 'd3' ]
},
plugins: [
svelte({
dev: !production,
css: css => { css.write('public/bundle.css'); }
}),
resolve({ browser: true }),
commonjs(),
!production && livereload('public'),
production && terser()
],
watch: {
clearScreen: false
}
};
...index.html 是:
<!doctype html>
<html>
<head>
<meta charset='utf8'>
<meta name='viewport' content='width=device-width'>
<title>Svelte app</title>
<link rel='icon' type='image/png' href='favicon.png'>
<link rel='stylesheet' href='global.css'>
<link rel='stylesheet' href='bundle.css'>
</head>
<body>
<script src="https://d3js.org/d3.v5.min.js"></script>
<script src='bundle.js'></script>
</body>
</html>
我怀疑 Rollup 没有正确捆绑 D3 模块,但作为 <body>
中的外部脚本,它在理论上应该可以工作,但事实并非如此。请给我指出正确的方向,我花了太多时间试图让它工作,作为一个 JS 菜鸟,我别无选择。谢谢!
当您的代码首先 运行s 时 <div class="chart"></div>
元素不存在 — <script>
运行 的内容当组件被实例化时。如果你需要访问组件内部的 DOM 个元素,它会首先在 onMount:
内部可用
<script>
import { onMount } from 'svelte';
// other code...
onMount(() => {
d3.select('.chart')
// ...
});
</script>
使用 select 或类似 .chart
是危险的,因为如果页面上有多个组件 D3 会 select 错误。最好用 bind:this 代替:
<script>
import { onMount } from 'svelte';
// other code...
let el;
onMount(() => {
d3.select(el) // no danger of selecting the wrong element
// ...
});
</script>
<div class="chart" bind:this={el}></div>
现在您需要更改的是 CSS — 因为 Svelte 会丢弃它认为未使用的 select 或,并且因为它不知道 D3 将要做什么,所以它将删除 .chart div {...}
。相反,使用 :global(...) modifier 定位 top-level 元素内的 div:
<style>
.chart :global(div) {
/* styles */
}
</style>
通过这些更改,它可以完美运行:
https://svelte.dev/repl/8722c32f4e1a44a98e3a3fc8a095b2d7?version=3.5.3
但在这种情况下,D3 并没有真正为聚会带来任何东西。您可以更简单地获得相同的结果:
<script>
var data = [30, 86, 168, 281, 303, 365];
</script>
<style>
.chart div {
font: 10px sans-serif;
background-color: steelblue;
text-align: right;
padding: 3px;
margin: 1px;
color: white;
}
</style>
<div class="chart">
{#each data as d}
<div style="width: {d}px">
{d}
</div>
{/each}
</div>
除了供您编写的代码更少之外,您的应用现在包含的内容也少了很多 JavaScript。此处演示:https://svelte.dev/repl/be5cac1695554b8e9ee6d0bc14b9dff1?version=3.5.3
我一直在尝试将最基本的 D3 示例放入 Svelte 应用程序中,但无法使其正常工作。起初我尝试将 D3 安装为节点模块:npm install d3
但这会产生与从 index.html
内的 CDN 作为外部脚本导入 D3 相同的结果(缺少结果):<script src="https://d3js.org/d3.v5.min.js"></script>
.无论使用哪种方法,我都会在应用程序启动时收到一堆循环依赖警告:
(!) Circular dependency: node_modules\d3-selection\src\selection\index.js -> node_modules\d3-selection\src\selection\select.js -> node_modules\d3-selection\src\selection\index.js
但是app启动没有报错,也没有出现D3动态格式化,也没有在Chrome里面的DevTools控制台弹出任何报错。
Svelte 组件如下所示:
<script>
import * as d3 from 'd3';
var data = [30, 86, 168, 281, 303, 365];
d3.select(".chart")
.selectAll("div")
.data(data)
.enter()
.append("div")
.style("width", function(d) {
return d + "px";
})
.text(function(d) {
return d;
});
</script>
<style>
.chart div {
font: 10px sans-serif;
background-color: steelblue;
text-align: right;
padding: 3px;
margin: 1px;
color: white;
}
</style>
<div class="chart"></div>
将上面的代码放入静态 HTML 文件会按预期生成条形图。但是当 运行 作为 Svelte 组件时,什么都不显示。
我的rollup.config.js是:
import svelte from 'rollup-plugin-svelte';
import resolve from 'rollup-plugin-node-resolve';
import commonjs from 'rollup-plugin-commonjs';
import livereload from 'rollup-plugin-livereload';
import { terser } from 'rollup-plugin-terser';
const production = !process.env.ROLLUP_WATCH;
export default {
input: 'src/main.js',
output: {
sourcemap: true,
format: 'iife',
name: 'app',
file: 'public/bundle.js',
globals: { 'd3': 'd3' },
external: [ 'd3' ]
},
plugins: [
svelte({
dev: !production,
css: css => { css.write('public/bundle.css'); }
}),
resolve({ browser: true }),
commonjs(),
!production && livereload('public'),
production && terser()
],
watch: {
clearScreen: false
}
};
...index.html 是:
<!doctype html>
<html>
<head>
<meta charset='utf8'>
<meta name='viewport' content='width=device-width'>
<title>Svelte app</title>
<link rel='icon' type='image/png' href='favicon.png'>
<link rel='stylesheet' href='global.css'>
<link rel='stylesheet' href='bundle.css'>
</head>
<body>
<script src="https://d3js.org/d3.v5.min.js"></script>
<script src='bundle.js'></script>
</body>
</html>
我怀疑 Rollup 没有正确捆绑 D3 模块,但作为 <body>
中的外部脚本,它在理论上应该可以工作,但事实并非如此。请给我指出正确的方向,我花了太多时间试图让它工作,作为一个 JS 菜鸟,我别无选择。谢谢!
当您的代码首先 运行s 时 <div class="chart"></div>
元素不存在 — <script>
运行 的内容当组件被实例化时。如果你需要访问组件内部的 DOM 个元素,它会首先在 onMount:
<script>
import { onMount } from 'svelte';
// other code...
onMount(() => {
d3.select('.chart')
// ...
});
</script>
使用 select 或类似 .chart
是危险的,因为如果页面上有多个组件 D3 会 select 错误。最好用 bind:this 代替:
<script>
import { onMount } from 'svelte';
// other code...
let el;
onMount(() => {
d3.select(el) // no danger of selecting the wrong element
// ...
});
</script>
<div class="chart" bind:this={el}></div>
现在您需要更改的是 CSS — 因为 Svelte 会丢弃它认为未使用的 select 或,并且因为它不知道 D3 将要做什么,所以它将删除 .chart div {...}
。相反,使用 :global(...) modifier 定位 top-level 元素内的 div:
<style>
.chart :global(div) {
/* styles */
}
</style>
通过这些更改,它可以完美运行:
https://svelte.dev/repl/8722c32f4e1a44a98e3a3fc8a095b2d7?version=3.5.3
但在这种情况下,D3 并没有真正为聚会带来任何东西。您可以更简单地获得相同的结果:
<script>
var data = [30, 86, 168, 281, 303, 365];
</script>
<style>
.chart div {
font: 10px sans-serif;
background-color: steelblue;
text-align: right;
padding: 3px;
margin: 1px;
color: white;
}
</style>
<div class="chart">
{#each data as d}
<div style="width: {d}px">
{d}
</div>
{/each}
</div>
除了供您编写的代码更少之外,您的应用现在包含的内容也少了很多 JavaScript。此处演示:https://svelte.dev/repl/be5cac1695554b8e9ee6d0bc14b9dff1?version=3.5.3