news 2026/9/7 6:58:56

D3 本地变量详解:d3.local 与 DOM 作用域状态的读写、继承与移除

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
D3 本地变量详解:d3.local 与 DOM 作用域状态的读写、继承与移除

D3 本地变量详解:d3.local 与 DOM 作用域状态的读写、继承与移除

【免费下载链接】d3Bring data to life with SVG, Canvas and HTML. :bar_chart::chart_with_upwards_trend::tada:项目地址: https://gitcode.com/GitHub_Trending/d3/d3

D3 locals(本地变量)是 d3-selection 提供的一种把状态挂载到 DOM 元素上的机制,它让状态的定义完全独立于数据绑定,并支持沿祖先链自动继承。本文基于仓库中 locals 文档 的完整 API 内容展开,并结合 package.json、src/index.js 与 api.md 等仓库证据,说明local()local.setlocal.getlocal.removelocal.toString五个 API 的用法、行为边界以及与其他状态存储方式的取舍。

什么是 D3 locals,适合什么场景

D3 locals 允许定义独立于数据(data)的本地状态。典型场景是渲染时间序列数据的 small multiples(小倍图):你可能希望所有小图共享同一个 x 轴比例尺,但每张图拥有各自独立的 y 轴比例尺,以便对比各指标的相对表现。

locals 的作用域规则以 DOM 元素为单位:

  • set 时:值被存储在指定的元素上;
  • get 时:值从指定元素读取;若该元素未定义此 local,则沿祖先链向上查找,返回最近的定义了该 local 的祖先上的值;若没有任何祖先定义,则返回undefined

原文档给出了一条明确的官方提示,值得原样保留:

CAUTION:Locals 很少被使用;你往往会发现把需要的状态存储在 selection 的 data 中更简单。

也就是说,locals 的定位是“锦上添花”的细粒度控制手段,而不是日常首选。

local():声明一个新的本地变量

const foo = d3.local();

local()用于声明一个新的本地变量。可以把它理解为 JS 的var的 DOM 化版本:

  • var相同:每个 local 都是一个独立的符号引用;
  • var不同:每个 local 的取值还按 DOM 作用域划分,即同名 local 在不同元素上可以有不同取值。

在完整打包的 d3 中,local与整个 d3-selection 模块一起导出。从 src/index.js 可以看到,umbrella 包通过export * from "d3-selection"(src/index.js#L24)一次性暴露了d3.local在内的全部 selection API;而 package.json 声明的依赖版本为d3-selection: ^3.0.0(package.json#L61),当前 umbrella 包版本为7.9.0。这意味着d3.local在 d3 v7 及 d3-selection v3 及以上版本中均可直接使用。

local.set(node, value):向元素写入值

selection.each(function(d) { foo.set(this, d.value); });

local.set(node, value)把指定node上该 local 的值设置为value,并返回被设置的value(这一返回值使得 set 可以内嵌在表达式中使用)。由于 set/get 的入参是具体的 DOM 节点而非 selection,惯用写法是借助 selection.each 遍历选区,在回调里用this引用当前元素。

如果只是想给元素存储一个变量,原文档建议直接考虑更简单的 selection.property:

selection.property(foo, (d) => d.value);

这里foo作为 local 变量对象传入,会被用作属性名的字符串标识,等价于以foo.toString()的标识为属性名调用 property。这一写法能成立的原因正是下一个小节要讲的 toString 机制。

local.get(node):按祖先链回退的读取

selection.each(function() { const value = foo.get(this); });

local.get(node)返回指定node上该 local 的值,其查找规则是整个 locals 机制中最有特色的部分:

  1. node自身定义了该 local,直接返回自身上的值;
  2. node未定义,则返回最近的定义了该 local 的祖先的值;
  3. 若整条祖先链上都没有定义,返回undefined

这种“就近继承”语义使得 small multiples 场景中的分工变得自然:把共享的 x 比例尺 set 在图表容器的公共外层节点上,把各自的 y 比例尺 set 在每个小图节点上;小图内部的所有子元素(坐标轴、网格线、文字等)调用get(this)时,x 比例尺从外层继承,y 比例尺则命中所在小图自身的定义。祖先继承也意味着:修改某个内层元素上的 local 不影响外层,而删除内层定义后读取会回退到外层值(见下文 remove)。

local.remove(node):删除元素上的定义

selection.each(function() { foo.remove(this); });

local.remove(node)删除指定node上该 local 的值,其返回值为布尔型:

  • 若删除前node自身定义了该 local,返回true
  • 否则返回false

需要注意继承语义在删除后依然生效:若祖先上也定义了该 local,这些祖先定义不受影响,因此 local.get 仍然会返回继承自祖先的值。换言之,remove只清除“本节点自己的定义”,让查找自然回退到祖先链,而不是把值置空。

local.toString():取回本地属性标识符

local.toString()返回该 local 自动生成的标识符。这个标识符的实质意义是:

它正是用来在元素上存储该 local 值的属性名

因此,除了 set/get/remove 之外,你还可以通过原生属性访问读写同一个值:

  • element[local]—— 用 local 对象作为计算属性名,直接读写底层属性(local.toString()会在计算属性名时被自动调用);
  • selection.property —— 例如selection.property(foo, (d) => d.value),即把foo.toString()的结果当作属性名。

这一点把 locals 与 d3-selection 的其余修改类 API 打通了:同一个 local 既可以用 locals API 管理,也可以作为property的属性名使用,两条路径读写的是元素上同一个位置的值。

在 d3 项目中的位置与证据

从仓库结构可以确认 locals 在 d3 生态中的归属与地位:

  • API 索引:api.md 的 d3-selection 章节将 “Local variables” 列为 selection 的六大主题之一(与 Selecting、Modifying、Joining、Events、Control flow 并列),并逐条索引了d3.locallocal.setlocal.getlocal.removelocal.toString五个条目(api.md#L1096-L1102),与本文覆盖范围一致。
  • 模块归属:locals 属于 d3-selection 子模块,umbrella 包通过 src/index.js 的 re-export 汇总暴露;各 API 的实现源码位于 d3-selection 子仓库的src/local.js(官方文档在每条 API 条目下均标注了对应的 Source 链接,实现细节以该子模块为准)。
  • 历史沿革:CHANGES.md 记录了d3.local的引入动机(CHANGES.md#L1208):“提供定义本地变量的机制:状态绑定到 DOM 元素,并可供任何后代元素使用,是使用 selection.each 或把状态存进 data 的便捷替代。” 这与本文开头描述的用途一致。

locals 与 data、property 的取舍

locals 是 d3 中三种“把值挂到元素上”的方式之一,选择时可以从以下维度对照:

方式存储位置作用域/继承适用情形
selection 的 data(data join)与元素的 datum 绑定无祖先继承,按数据索引取用状态与数据一一对应时的默认选择
selection.property元素上的原生属性无祖先继承表单控件的value/checked等特殊属性,或单变量存储
d3.local元素上以自动生成标识符为名的属性有祖先继承(get 沿祖先链回退)状态需要跨层级共享、且不想混入数据绑定时的细粒度场景

官方对 locals 的定位是克制而明确的:它“很少被使用”。日常开发中,优先把状态放进 selection 的 data 或用property存储;只有当状态天然是“挂在 DOM 树某一层级、供整棵子树读取”的形态(如 small multiples 中的共享比例尺、子组件间传递的渲染上下文)时,locals 的祖先继承语义才会体现出独特价值。

小结

  • d3.local()声明一个按 DOM 元素划分的本地变量,是var的 DOM 作用域版本;
  • local.set(node, value)将值写入指定元素并返回该值,通常配合selection.each使用;单变量场景可退化为selection.property(foo, fn)
  • local.get(node)读取值时沿祖先链回退,未命中任何定义则返回undefined,这是 locals 支持“公共配置挂外层、私有配置挂内层”模式的关键;
  • local.remove(node)仅删除本节点的定义并返回布尔值,祖先定义不受影响,删除后 get 会回退到继承值;
  • local.toString()暴露底层存储所用的属性名,使element[local]selection.property成为与 locals API 等价的读写路径。

【免费下载链接】d3Bring data to life with SVG, Canvas and HTML. :bar_chart::chart_with_upwards_trend::tada:项目地址: https://gitcode.com/GitHub_Trending/d3/d3

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/7 6:58:50

网页里的视频和音频怎么一次抓全:猫抓资源嗅探实战

网页里的视频和音频怎么一次抓全:猫抓资源嗅探实战 【免费下载链接】cat-catch 猫抓 浏览器资源嗅探扩展 / cat-catch Browser Resource Sniffing Extension 项目地址: https://gitcode.com/GitHub_Trending/ca/cat-catch 视频页面转了三圈圈,右键…

作者头像 李华
网站建设 2026/9/7 6:58:19

线性规划实战指南:从建模到Python求解排产优化

简介:线性规划单纯形算法的C实现资料包,面向运筹学课程学习者、算法爱好者及需要求解线性规划问题的开发者,演示如何将标准线性规划模型转化为单纯形表并迭代求最优解。压缩包共17个文件、大小623KB,包含两个C源文件及头文件、Vis…

作者头像 李华
网站建设 2026/9/7 6:58:13

C# WinForm无人机地面站开发实战:架构设计与避坑指南

简介:一套基于 C# WinForm 的无人机地面站源码工程,面向刚接触桌面应用与无人机通信的初学者,能快速理解 GDI 图形绘制、串口收发与自定义通信协议的完整落地实现。功能上包含无人机实时状态显示、在线地图、航线航迹绘制、飞行参数曲线和航线…

作者头像 李华
网站建设 2026/9/7 6:57:47

Buzz:离线语音转文字,隐私不出门的免费方案

Buzz:离线语音转文字,隐私不出门的免费方案 【免费下载链接】buzz Buzz transcribes and translates audio offline on your personal computer. Powered by OpenAIs Whisper. 项目地址: https://gitcode.com/GitHub_Trending/buz/buzz 你有没有遇…

作者头像 李华
网站建设 2026/9/7 6:55:54

基于Claude API构建生产级AI智能体:工具调用与工程实践

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/7 6:55:48

灰色狼群优化GWO的MATLAB完整实现与源码详解

简介:面向机器学习与智能优化方向的开发者,这份资源提供灰色狼群优化(GWO)算法的MATLAB源码及详细中文注解,可用于支持向量机(SVM)与支持向量回归(SVR)参数寻优&#xff…

作者头像 李华