Skip to content完全替换(
选择性替换(
延迟更新(
setOption 的合并策略
概述
setOption 是 ECharts 实例上用于更新配置项的主要方法。它的默认行为是深度合并(deep merge)传入的配置与实例内部已有的配置,而非整体替换。这种设计在多数增量编辑场景中比较便利,但在意图切换数据源或移除某个组件时容易产生与预期不符的结果——例如旧配置的字段没有被清除,series 数组中多余的元素仍被保留。
基本概念
ECharts 实例在内部持有完整的配置对象(通常称为 _option),该对象保存了当前图谱的全部描述信息,包括标题、图例、坐标系、系列等。每次调用 setOption(option) 时,如果未显式要求替换,框架会将传入的 option 与内部的 _option 进行递归合并:
- 对顶层键(
title、tooltip、legend、series等),逐键处理。 - 对普通对象,递归合并其属性。
- 对数组类型(如
series、color),按索引位置将新元素与旧元素合并。如果新数组长度小于旧数组,多余元素不会自动移除。
因此局部更新(例如仅修改标题文本)非常轻量,但试图用较小的 option 覆盖或删除旧配置时,往往不能达到目的。
工作原理
框架内部通过 OptionManager.setOption 完成合并,简化的处理逻辑如下:
text
setOption(option, opts)
→ OptionManager.setOption(option, opts)
→ 当 opts.notMerge !== true 时:
→ 深度合并 option 与内部 _option
→ 递归处理每个顶层键
→ series 数组按索引合并(index 对应)
→ 当 opts.notMerge === true 时:
→ 以 option 直接替换内部 _option默认合并(notMerge 为 false)对于编辑场景很高效——开发者只需要传入变化的部分,无需维护完整配置。但在需要彻底切换数据形态时,索引合并策略就会留下残余。
以下示例展示了从双系列图表切换到单系列饼图时,合并引发的问题:
js
// 当前内部状态:option.series = [lineSeries, barSeries](2 个元素)
// 传入仅包含一个新系列的 option
chart.setOption({ series: [pieSeries] });
// 实际合并结果:
// option.series = [
// merge(pieSeries, lineSeries), // 第一个位置混合了两个系列的字段
// barSeries // 第二个位置原样保留
// ]merge(pieSeries, lineSeries) 会将饼图的配置与折线图配置进行深度合并,产生字段被污染的异常系列。同时第二个柱状图系列并未移除,图表会出现非预期的表现。
基本用法
增量更新(默认合并)
js
// 只修改标题文本,其余配置保持不变
chart.setOption({
title: {
text: '新标题'
}
});传入的对象与内部配置合并,仅覆盖 title.text,其余属性(如 title.subtext、tooltip 等)不受影响。
完全替换(notMerge: true)
js
chart.setOption(fullOption, { notMerge: true });传入的 option 会直接成为实例的新内部配置,旧配置被完全丢弃。适合图表类型整体切换、需要严格保证配置独立性的场合。此时 option 必须是完整的有效配置,否则缺失的部分会导致对应组件表现异常。
选择性替换(replaceMerge)
js
chart.setOption(newOption, { replaceMerge: ['series'] });仅对指定的顶层键采用替换策略,其他键仍然走默认合并。上例中 series 数组会整体替换,而 tooltip、legend 等沿用合并行为。
延迟更新(lazyUpdate)
js
chart.setOption(option, { lazyUpdate: true });传入的配置变更不会立即反映到 Model 层的全局更新中,而是推迟到下一个 requestAnimationFrame 再执行。在动画进行中需要调整配置时可以借此避免打断动画,但后续立即读取系列状态可能拿到旧值。
API
chart.setOption(option, opts?)
参数
option: EChartsOption
新的配置项。当使用notMerge: true或replaceMerge时,需确保相关部分完整;当使用默认合并时,可以只提供需要修改的片段。opts?: SetOptionOption
可选的控制参数对象,包含以下字段:notMerge?: boolean
默认false。设置为true时,以传入的option整体替换内部配置,不做合并。replaceMerge?: string | string[]
指定哪些顶层组件(键)采用替换模式,其余组件仍走合并。可传入单个键名字符串或键名数组。可用的键包括 ECharts 配置对象的所有顶层属性,例如'title'、'tooltip'、'legend'、'grid'、'xAxis'、'yAxis'、'series'、'color'等。replaceMerge只能指定顶层键,无法递归到组件内部的子属性。当notMerge为true时,replaceMerge配置将被忽略。lazyUpdate?: boolean
默认false。设为true时,Model 的更新推迟到下一个动画帧执行。如果同时指定notMerge: true或replaceMerge,替换行为本身发生在延迟更新开始前,但最终对组件和系列的合并与布局会推迟。silent?: boolean
默认false。设为true时不触发update事件,适合不希望驱动外部监听的静默更新。
示例
保留交互配置,仅替换系列数据
当图表类型改变,但布局、图例、提示框等仍希望沿用原有配置时,可用 replaceMerge 只替换 series:
js
const baseOption = {
tooltip: {},
legend: { data: ['销量'] },
xAxis: { data: ['A', 'B', 'C'] },
yAxis: {},
series: [{ type: 'bar', data: [5, 20, 36] }]
};
chart.setOption(baseOption);
// 切换为折线图,仅替换 series,其余组件保持不变
chart.setOption(
{
series: [{ type: 'line', data: [10, 15, 30] }]
},
{ replaceMerge: ['series'] }
);如果不使用 replaceMerge,上述调用会导致 series[0] 与旧的柱状图系列合并,类型字段冲突,且 legend.data 不会自动更新。
全量切换到另一张图表
从一个图表完全切换到另一个配置不同的图表时,使用 notMerge 可以避免残留:
js
chart.setOption(newFullOption, { notMerge: true });这会丢弃所有旧配置,包括标题、坐标轴、图例等,需要确保 newFullOption 是一个完整且有效的 ECharts 配置对象。
动画期间调整配置
使用 lazyUpdate 可以在不打断当前过渡动画的情况下更新数据:
js
chart.setOption(
{
series: [{ data: newData }]
},
{ lazyUpdate: true }
);更新会在下一帧执行,当前帧的动画不受影响。如果紧接着调用 getOption() 或依赖即时状态的逻辑,得到的是上一个配置的状态。
注意点
- 不能通过传入
null或空对象删除已有组件。例如要移除tooltip,不能写{ tooltip: null },因为默认合并会忽略null值,旧配置仍然存在。可行的做法是显式设置tooltip: { show: false }隐藏该组件,或者通过notMerge/replaceMerge整体替换不含tooltip的新配置(代价是必须提供完整的其他组件)。 series数组合并按索引对齐,新数组短于旧数组时多余项不会清除。切换图表类型时,如果新旧系列数量不同,应优先考虑replaceMerge: ['series']或notMerge: true。- 对象合并是递归的,但数组不会递归合并每个元素,而是基于索引合并每个对象成员。比如
color数组、series数组都是按位置合并,而非拼接或替换整个数组。 - 内嵌对象字段会与旧值合并。如果某次调用仅传入
tooltip: { trigger: 'item' },则tooltip对象中未传入的其他字段(如formatter)将被保留。这也是默认合并的设计意图,但在意图重置组件时容易造成字段污染。 replaceMerge只对顶层键有效,不能写类似'series[0].data'这样的路径。如果需要对系列内部的数组或对象做更精细的控制,通常需要手动构建该系列对应的完整描述并依赖replaceMerge: ['series']整体替换对应索引的系列。
限制
notMerge与replaceMerge互斥。当notMerge: true时,replaceMerge配置会被忽略,所有组件均直接替换。lazyUpdate延迟的是 Model 更新和后续的视觉映射、布局计算,但notMerge/replaceMerge引起的内部配置替换本身不会延迟。因此在同一帧内连续多次调用并期望后续调用看到前一次更新的状态时,需要谨慎处理时序。- ECharts 没有提供部分属性删除的原子操作。默认合并机制本质上是“只增不改删”的合并,这要求开发者在合并模式下要么接受旧字段残留、通过显式开关控制可见性,要么在需要削减配置时切换到替换模式。
- 三维或 GL 组件的合并行为与普通 2D 组件基本一致,但部分组件(如
globe)在内部处理上可能有差异,建议参照具体组件的文档确认。
应用
setOption 的调用可以归纳为两类路径。
增量编辑路径
适用于高频交互(如拖拽滑块调整样式、动态修改标题或提示格式)。这些场景每次变更字段少,改动范围明确,利用默认合并可以避免反复构建完整配置对象,降低计算开销。
全量或半全量替换路径
适用于低频但整体性强的变更(如数据源切换、图表类型切换、页面级状态重置)。这类场景需要保证 series 数组干净、组件配置不残留,应使用 notMerge: true 或 replaceMerge。在调用之前,业务代码需要有能力构造当前所需的完整片段。
混用两类策略容易在合并时残留旧字段或导致数组索引错位,将不同频率、不同完整性的更新统一到单一合并模式中往往会带来额外的状态清理成本。如果在中频操作(如每秒一次刷新)中需要平衡便利性与安全性,replaceMerge 配合明确指定的替换键是一种可取的折中。
参考链接
- ECharts 官方 API:
setOption
https://echarts.apache.org/zh/api.html#echartsInstance.setOption - ECharts 配置项总览
https://echarts.apache.org/zh/option.html
