
简介一份基于3Dmol.js的前端项目资源包面向Web前端开发者、化学信息学学习者及科研教学人员。3Dmol.js是开源三维分子可视化库无需额外插件即可在支持WebGL的浏览器中展示PDB、MOL、SDF等多种分子格式。资源为zip压缩包大小136.09MB已有341人学习/下载。项目围绕分子数据解析、3D模型构建、用户交互和渲染优化展开涉及WebGL底层原理、坐标空间转换、原子与化学键的可视化呈现、旋转缩放等交互操作以及分子动画与动态更新机制。通过研读和实践该前端项目可以掌握将化学结构数据转换为交互式三维场景的完整思路熟悉3Dmol.js常用API与性能优化手段并学会将可视化组件集成到现有Web应用中为开发分子可视化教学工具或科研展示平台打下基础。1. 一个能直接跑的分子可视化前端项目3Dmol 有多大本事第一次解压这个压缩包时我原以为又是一个套模板的管理后台前端项目打开才发现目录里躺着 sample.pdb 和一堆 3Dmol 渲染源码——这是一个专门做分子三维可视化的前端项目。它做的事很具体把 PDB、SDF 这类结构文件丢进浏览器立刻渲染出可旋转、可缩放、可切换样式的三维分子模型不用装 PyMOL。这个项目适合三类人想把分子结构嵌入页面的开发者、对 WebGL 感兴趣但不想从零写渲染器的前端工程师、拿分子可视化做课程设计的学生。体量不大但覆盖了 3Dmol.js 的完整链路——解析、样式、选择器、交互每个关键步骤都有能直接抄的代码。2. 项目定位与技术选型为什么用 3Dmol.js 而不是自研 WebGL2.1 这个前端项目到底在解决什么问题先把这个项目放在它应该在的位置。分子结构可视化在生物信息学、药物设计、结构生物学里是刚需但传统方案几乎都绑在桌面软件上。桌面端常见的分子可视化工具渲染效果确实是公认的好可它们是本地程序想嵌进网页基本不可能早年浏览器里能跑的是 Java Applet 方案现在已经被主流浏览器彻底封死。想在 Web 端展示分子结构实际可选的路只有两条用 Three.js 或原生 WebGL 自己写一套分子渲染器或者直接使用 3Dmol.js 这类专门的分子可视化库。自己写渲染器是什么概念你至少要处理蛋白质骨架的几何建模、球棍模型的图元生成、着色器里对原子半径和键长的统一缩放、大分子的 LOD 降级。这些工作量按周甚至按月计算而且最终效果大概率不如一个深耕分子渲染多年的库。3Dmol.js 把这些全封装好了——内置 PDB/SDF/XYZ/MOL2 解析器、多种样式、基于 spec 的选择器还有对 WebGL 上下文的托管。这个压缩包的定位就很清楚了它不是 3Dmol.js 的源码而是一个基于 3Dmol.js 的上层应用脚手架把库的 API 串成一条完整的业务链路。这个项目我最看重的一点是它的「闭环感」。很多开源 Demo 只给你一个渲染出来的效果代码往往是孤零零的几个 API 调用。而这个项目里怎么初始化 viewer、怎么从本地文件读取分子数据、怎么用 spec 选择器选中某条链、怎么在点击原子时弹出属性信息——每一步都是串起来的。对于想在自己项目里集成分子展示的人来说这份代码的价值在于不用啃整套文档直接把初始化逻辑和样式配置搬过去就能跑通。2.2 技术栈全景与目录结构打开项目先看 package.json。构建工具用的是 Vite核心依赖只有 3dmol 这一个包UI 层没有引入 React 或 Vue是原生 HTML 加原生 JavaScript。这个选择我比较认同3Dmol.js 本身不依赖框架用原生 JS 写能把库的调用逻辑暴露得最清楚不会出现「框架生命周期没处理好导致 viewer 销毁了」这种干扰问题。对想迁移到 React 或 Vue 的开发者这份代码反而是好事——核心调用代码可以一行不改地搬进去只要换个容器元素的挂载方式。解压后典型的目录结构如下不同版本的压缩包命名可能略有差异但职责划分基本一致路径职责index.html页面骨架viewer 容器和工具栏按钮package.json依赖管理与 npm 脚本vite.config.js开发服务器配置主要是端口和静态资源路径src/main.js入口文件初始化并串联各模块src/viewer/initViewer.js创建 3Dmol viewer 实例及全局参数src/viewer/loadFile.js本地文件读取和目标格式识别src/viewer/styleManager.js渲染样式管理与切换src/data/sample.pdb项目自带的示例分子文件src/utils/fileReader.js文件内容的预处理工具这种按职责分文件的方式是这个体量项目里最常规的写法。initViewer 只管创建实例loadFile 只管把文件内容变成 modelstyleManager 只管样式切换main.js 负责把三者串起来。好处非常直接你想调背景色不用去翻文件读取的代码改一个 initViewer 的参数就行想换默认样式不用碰加载逻辑只动 styleManager 里的配置对象。模块之间的数据传递也只有一条单向链路file → model → style → render理解成本很低。2.3 渲染方案对比3Dmol.js vs Three.js vs 桌面软件很多人看到三维渲染第一反应是 Three.js我也走过这条路。Three.js 是一套通用三维引擎几何体、材质、相机、光照它都管但分子渲染需要的是专业能力读取 PDB 这种文本格式的分子坐标、把氨基酸残基映射成 cartoon 样式的平滑条带、按原子半径和颜色规则生成球体。这些东西 Three.js 一个都不内置全要自己算。我见过一个团队用 Three.js 做了一两个月最后只完成了原子球和键的线框渲染蛋白质的 cartoon 样式还没影。3Dmol.js 的对比优势在于它的定位垂直。它内部实现了分子文件解析器能理解 PDB 的 ATOM 记录、CONECT 连接记录它内置了 cartoon、sphere、stick、line、cross 多种样式每种样式都针对分子场景调过参数它的 spec 选择器可以直接用 resi残基号、chain链标识、atom原子名这种生物学语义来选中目标。这些能力用 Three.js 复刻的成本极高而且很容易在二次开发时遇到边缘情况——比如某个 PDB 文件里有异常残基名自研解析器直接崩了。那为什么不直接用桌面软件桌面软件脚本系统确实强大但部署和分发的成本摆在那里终端用户得安装本地环境得处理授权得接受一个本地窗口而不是网页链接。在如今 Web 应用普及的背景下一个能直接嵌入网页、打开链接就能看分子结构的方案对于课题组内部协作、论文补充材料展示、在线课程教学这些场景都有明显的分发优势。这个前端项目选 3Dmol.js本质上是在「效果可接受」和「开发成本可控」之间选了一个最稳的折中点。3. 本地运行五步走从解压到在浏览器里旋转蛋白结构3.1 环境准备与依赖安装跑这个项目对环境的要求很低Node.js 版本建议 16 以上因为 Vite 对 Node 版本有最低要求版本太老会直接启动失败。先确认环境再进入解压后的项目目录执行安装node -v npm -v cd 3dmol-frontend # 以你解压后的实际目录名为准 npm installnpm install 会安装 package.json 里声明的全部依赖。这个项目的依赖树很浅核心就是 3dmol 库本身加上 Vite 及其周边的编译工具正常情况下几十秒就能装完。如果你在 install 过程中遇到网络超时常见做法是切换 npm 镜像源再重试这个操作只影响包的下载地址不会改动项目的任何代码逻辑装完之后可以再切回去。装完之后可以顺手看一眼 node_modules 里 3dmol 的目录结构找到 dist 目录下的压缩版入口文件。知道这个文件位置对后面排查问题很有帮助——比如你怀疑库没加载成功直接在浏览器 Network 面板里搜 3dmol 就能确认。我一般还会做一件事打开 package.json 里的 dependencies 段确认 3dmol 的版本号因为 3Dmol.js 的 API 在不同大版本之间有过调整版本号决定了后面代码里那些写法是否被支持。3.2 启动开发服务器并验证页面依赖装完就可以起服务了这是整个流程里最没玄学的一步npm run dev正常情况下终端会输出本地访问地址Vite 默认是 http://localhost:5173。在浏览器里打开这个地址你看到的页面应该是一个占据大半屏的三维场景背景是白色或浅灰色中间已经渲染好了 sample.pdb 的分子结构。页面上通常有几个按钮或下拉框用来切换 cartoon、sphere、stick 样式以及一个用于加载本地 PDB 文件的文件选择控件。验证项目是否正常可以从三个层面检查。第一页面有没有报错——打开浏览器开发者工具的 Console 面板如果看到红色报错优先看是不是 3dmol 相关资源加载失败第二能不能拖拽旋转——在分子上按住鼠标左键拖动分子应该绕着场景中心旋转这说明 viewer 的交互事件已经绑定成功第三切换样式是否生效——点击 sphere 按钮整个分子的渲染方式应该从 cartoon 的丝带图变成原子球。这三步都通过说明项目本体没有坏可以开始折腾自己的数据了。这里有一个新手容易忽略的点如果你把静态文件直接双击用 file:// 协议打开 index.html大概率会白屏或者样式错乱因为 Vite 项目默认的模块加载路径是基于开发服务器根目录的。所以请记住这个项目必须在 dev server 环境下跑而不是直接双击 HTML 文件。这也是为什么 package.json 里要配 dev 脚本而不是只给一个静态打包目录。3.3 加载自己的分子文件三种常用方式项目把 sample.pdb 跑通之后你大概率想换成自己的分子。换数据有三种方式按方便程度排序。第一种是项目内置的文件选择控件。页面上一般会有一个文件选择输入框点击选择本地 PDB 或 SDF 文件主线程会通过 FileReader 读取文件内容调用 viewer.addModel 把新模型加进场景。这种方式适合临时查看单个文件不需要改任何代码也是我在日常中使用频率最高的一种。第二种是直接替换 src/data/sample.pdb。把项目自带的示例文件换名备份把你自己的 PDB 文件改名成 sample.pdb 放回原路径刷新页面就能生效。这样做的好处是不动代码但缺点也明显如果你换了文件格式比如想加载 XYZ 格式就必须改 loadFile.js 里的格式识别逻辑因为代码是按扩展名猜格式的。而且改完记得把备份文件删掉或移走否则加载逻辑可能会按错误的顺序读到旧的示例文件。第三种是改成从远程 URL 加载。把 loadFile 里读取本地文件的逻辑替换成 fetch 请求指向一个存放分子文件的静态资源服务器// src/viewer/loadFile.js 中的远程加载分支 export function loadMoleculeFromUrl(viewer, url) { fetch(url) .then(res { if (!res.ok) throw new Error(HTTP ${res.status}); return res.text(); }) .then(data { viewer.addModel(data, inferFormat(url)); viewer.zoomTo(); viewer.render(); }) .catch(err console.error(分子文件加载失败:, err)); }这里要注意的是 CORS 问题fetch 请求的目标服务器必须返回正确的跨域头否则文件内容拿到了也进不了 addModel 这一步。我习惯的做法是开发环境里在 Vite 配置一个代理把 /api/pdb 这样的路径转发到真正的文件服务器这样浏览器里看到的是同源请求从根上绕开 CORS。生产环境则把分子文件放在和前端同域的对象存储里。跑通了这三个小节的操作你已经能把这个项目当成一个可用的分子查看器了。但只看效果不看原理遇到问题还是会抓瞎。接下来最关键的问题变成这套流程内部到底是怎么工作的我们进入核心模块拆解。4. 核心模块拆解一个 PDB 文件从解析到上屏的完整链路4.1 初始化 viewer容器、参数与 WebGL 上下文整个项目的起点在 initViewer.js。这个模块做一件事拿到一个 DOM 容器在里面创建 3Dmol 的 viewer 实例。3Dmol 的 viewer 本质上是 WebGL 渲染器加上一套分子数据管理接口的封装它会自动在容器里创建 canvas 元素并获取 WebGL 上下文。初始化的核心代码如下// src/viewer/initViewer.js import * as $3Dmol from 3dmol; export function initViewer(containerId, options {}) { const element document.getElementById(containerId); if (!element) { throw new Error(容器元素 ${containerId} 不存在); } const viewer $3Dmol.createViewer(element, { backgroundColor: options.backgroundColor || 0xffffff, antialias: true, // 开启抗锯齿分子边缘更平滑 disableContextMenu: true, // 屏蔽右键菜单避免旋转时误触 fog: false // 关闭雾效小分子场景用不上 }); return viewer; }这里有个关键点值得展开createViewer 的第二个参数是配置对象backgroundColor 用 16 进制字符串写法且必须带引号写成 0xffffff 而不是 #ffffff这是 3Dmol 延续自 Jmol 的配色习惯。如果你在配置里写错了颜色格式viewer 不会报错但背景色会保持默认的黑色黑底上看浅色分子会感觉对比度奇怪——我在这里翻过一次车排查了半天以为是样式问题最后发现是配置项写成了 CSS 的井号格式。另一个值得注意的参数是 antialias。分子渲染里大量使用圆弧边缘的原子球锯齿会非常明显尤其在高分屏上。开启之后边缘会平滑很多代价是 WebGL 渲染压力略有增加。对这个项目的分子体量来说完全不用担心性能问题反而是 disableContextMenu 这个参数在实操中更重要——3Dmol 的默认交互绑定了右键拖拽平移视角如果不禁用浏览器菜单每次右键拖动都会弹出菜单体验非常割裂。4.2 文件解析链路FileReader、格式识别与 addModel把文件变成屏幕上模型的关键链路在 loadFile.js。用户选择文件后代码先通过 FileReader 把文件内容读成文本再根据扩展名判断格式最后调用 viewer.addModel 把文本数据交给 3Dmol 内部解析器。核心代码如下// src/viewer/loadFile.js import { inferFormat } from ../utils/fileReader.js; export function loadMoleculeFromFile(viewer, file, options {}) { const reader new FileReader(); reader.onload (event) { const content event.target.result; const format inferFormat(file.name); // addModel 第二个参数是格式名可以是 pdb/sdf/mol2/xyz const model viewer.addModel(content, format); // 默认样式cartoon 适合蛋白小分子建议用 stick const defaultStyle options.style || { cartoon: { color: spectrum } }; viewer.setStyle({}, defaultStyle); // 缩放视野到模型整体等价于自动调整相机距离 viewer.zoomTo(); viewer.render(); }; reader.readAsText(file); }addModel 是这条链路的核心动作。它接收两个参数文件内容字符串和格式标识。3Dmol 内置的解析器会在内部把 PDB 文本解析成原子坐标、元素类型、残基信息、连接关系组织成一个 model 对象。这里有一个容易踩的细节如果格式标识传错了比如把一个 SDF 文件标成 pdb解析器不会报错但原子的键连关系会残缺渲染出来就是一堆松散的原子球漂浮着没有化学键连接。所以 inferFormat 这个工具函数值得看一眼// src/utils/fileReader.js export function inferFormat(filename) { const ext filename.split(.).pop().toLowerCase(); const formatMap { pdb: pdb, ent: pdb, // PDB 的另一种扩展名 sdf: sdf, mol: sdf, mol2: mol2, xyz: xyz }; return formatMap[ext] || pdb; }格式识别失败的时候函数会默认兜底到 pdb。这种兜底策略在 Demo 项目里很常见但对生产环境我建议改成显式报错——格式认不出来比渲染出错更值得让用户知道至少提示里能说明是扩展名不支持还是文件损坏。我在二次开发时就把这段兜底逻辑改成抛出可读的错误信息了后续维护时省了不少猜谜时间。提示addModel 之后必须调用 render 才会真正绘制。很多新手在控制台看到 viewer 对象有数据但画布是空的就是因为少了这一步。4.3 样式系统与 spec 选择器为什么 setStyle 的威力在 spec样式切换是 3Dmol 体验最好的部分。setStyle 接受两个参数第一个是选择器 spec第二个是样式对象。空对象 {} 表示全选这是最常见的用法但真正体现这个库设计功力的是 spec 的精细度。来看 styleManager 里的实现// src/viewer/styleManager.js const STYLE_MAP { cartoon: { cartoon: { color: spectrum, thickness: 3 } }, sphere: { sphere: { scale: 1.0, color: element } }, stick: { stick: { radius: 0.15, bond: { radius: 0.08 } } } }; export function applyStyle(viewer, styleName, spec {}) { if (!STYLE_MAP[styleName]) { console.warn(未知样式 ${styleName}可用样式: ${Object.keys(STYLE_MAP)}); return; } viewer.setStyle(spec, STYLE_MAP[styleName]); viewer.render(); }spec 选择器支持用生物学语义选目标比如选中某条链上的特定残基区间// 只给 A 链的 100-120 号残基上球棍样式 viewer.setStyle( { chain: A, resi: [100, 120] }, { stick: { radius: 0.15 } } ); // 只给某种原子着色高亮 viewer.setStyle( { atom: CA }, { sphere: { color: yellow } } );这里有个容易让新手困惑的点setStyle 不是累加生效而是整体覆盖。每次调用 setStyle之前设置的样式会被替换而不是叠加。如果你先给全分子设置 cartoon再给某条链设置 sphere最后的渲染结果是只有那条链是球状其他部分变成默认的线框样式。正确的做法是在同一次调用里用 spec 区分不同区域的样式或者在设置新样式之前先统一 setStyle({}, {}) 重置。另一个经验styleManager 这种把样式定义集中管理的方式在二次开发时非常有用。后续新增一个「隐藏水分子」的按钮只需在 STYLE_MAP 里加一个条目把选中水分子的 spec 传给 setStyle 就行不需要改动渲染逻辑。项目把样式定义和数据加载分离的做法虽然代码量上多了一个文件但维护性提升明显。4.4 交互事件点击原子、悬浮提示与相机控制最后一块核心是交互层。3Dmol 的 viewer 支持点击回调点击分子上的原子时会触发 setClickCallback 注册的函数回调能拿到被点击原子的坐标和属性信息。这个项目里把它用来做原子信息展示// src/main.js 中注册点击回调 viewer.setClickCallback(function (atom, viewer, event) { const infoEl document.getElementById(atom-info); if (!atom) { infoEl.textContent 点击空白区域; return; } infoEl.textContent 原子: ${atom.atom} | 残基: ${atom.resi} | 链: ${atom.chain} | 坐标: (${atom.x.toFixed(2)}, ${atom.y.toFixed(2)}, ${atom.z.toFixed(2)}); });回调的第二个参数是 viewer 本身意味着你可以在点击事件里继续做复杂的联动比如点中某个残基时把周围 5 埃范围内的原子高亮。第三个参数是原始鼠标事件可以用来做右键菜单的定制。atom 对象上常用的字段包括 atom原子名如 CA 表示 Cα、resi残基序号、chain链标识、resn残基名、x/y/z坐标这些字段在二次开发里会频繁用到。相机控制这块3Dmol 的默认交互是经过调校的左键拖拽旋转、右键拖拽平移、滚轮缩放。项目在初始化时把 disableContextMenu 设为 true就是为了避免右键拖拽平移时频繁弹出浏览器菜单。如果你在二次开发时要关闭旋转、只留缩放可以通过 viewer 的交互配置去调整这是我在做演示模式时常用的一个接口。除此之外zoomTo 是一个值得单独说的接口。它做的事情是计算当前模型的外包围盒中心把相机移到合适距离让整个分子居中显示。每次加载新文件之后调用一次比手动设置相机位置靠谱得多。如果你的页面在初始化时有一个 loading 状态可以先把 viewer 创建出来但先不加载模型等文件就绪后再 addModel zoomTo render这样交互上会感觉更顺滑也不会出现黑屏闪一下的情况。5. 避坑指南3Dmol 前端项目最常见的 5 个翻车现场5.1 页面白屏但控制台没有任何报错现象启动 dev server 后页面一片空白Console 干净得像是没加载过任何脚本Network 面板里所有资源也都正常返回了 200。原因这是 3Dmol 项目里最容易翻车的坑——容器元素没有高度。createViewer 会在容器里创建 canvas但 WebGL canvas 的默认高度取决于容器的高度如果容器 div 的高度为 0 或未设置canvas 就是一条看不见的线页面看起来就是白屏。这个坑之所以隐蔽是因为代码逻辑完全正确控制台无任何异常你甚至能在调试面板里看到 canvas 元素存在只是它的尺寸是 300x0。解决检查 index.html 里 viewer 容器的 CSS给它设置明确的尺寸。我一般这样写#viewer-container { width: 100%; height: 80vh; /* 或者固定 600px */ position: relative; }改完刷新页面分子就会出现。从那以后我每次初始化 viewer 之前都会先确认容器高度不再想当然。5.2 本地文件加载失败CORS 与 file 协议陷阱现象点击文件选择按钮选择了 PDB 文件后页面没有任何反应Console 里有跨域相关的报错提示 CORS policy或者文件选完模型没有出现在画布上。原因如果你把 index.html 直接双击打开file:// 协议FileReader 读取本地文件本身没问题但如果项目里额外用 fetch 去请求 resources 目录下的辅助文件就会触发浏览器的同源限制。更常见的情况是改造成 URL 加载之后目标服务器没有返回 Access-Control-Allow-Origin 响应头导致 fetch 拿到的响应被浏览器拦截。解决开发阶段不要用 file:// 协议始终通过 npm run dev 启动的开发服务器访问。远程加载的场景优先在 vite.config.js 里配置代理把请求转发到后端的文件服务接口上。生产环境把分子文件和前端页面部署到同一个域名下CORS 问题从根源消失。5.3 切换样式后分子直接消失现象点了一个样式切换按钮之后画布上只剩背景色分子不见了。刷新页面又重新出现再点一次按钮又消失。原因setStyle 是整体覆盖式的。如果你先对全分子调用了 setStyle({}, {sphere})紧接着又对某个 spec 调用 setStyle({chain:A}, {stick})3Dmol 会把 chain 等于 A 的部分应用 stick其余部分不应用任何样式——而没有样式的原子默认不渲染。所以「看起来分子消失」其实是没被选中的原子被移出了渲染集合。解决每次做整体切换时先重置再设置把渲染逻辑改成「全选 覆盖」的模式。比如在 styleManager 里这样处理export function switchStyle(viewer, styleName) { viewer.setStyle({}, STYLE_MAP[styleName]); // 直接对全分子覆盖新样式 viewer.render(); }重置之后再针对特定选区追加样式而不是反过来。这个顺序问题是用一次血泪教训换来的——当时线上用户的反馈是「分子看得到但颜色不对」排查到最后发现就是样式覆盖顺序的锅某个区域被后设置的 spec 覆盖成了默认样式。5.4 大分子旋转卡顿渲染性能优化现象加载一个原子数超过两万的蛋白复合体之后拖拽旋转明显掉帧GPU 风扇开始狂转页面滚动都跟着卡。原因默认样式下3Dmol 为每个原子生成独立的几何体原子数多时顶点数成倍增长再加上样式切换时频繁触发重绘帧率自然撑不住。三种样式里 sphere 的顶点数最高stick 其次cartoon 最省这也是为什么大蛋白默认用 cartoon 展示。解决分两步优化。第一步减少几何体复杂度把 sphere 的 scale 调小、stick 的 radius 调小视觉效果变化不大但顶点数明显下降第二步按需重绘长按旋转结束之后再 render而不是每次鼠标移动都触发完整渲染。3Dmol 还支持通过 viewer.setQuality 调整渲染档位低画质模式下 WebGL 会降低采样率换取流畅度适合大分子演示场景。如果这些都做了还是卡就该考虑对分子做裁剪只显示配体结合口袋附近的残基。5.5 窗口缩放后分子变形canvas 尺寸同步问题现象拖动浏览器窗口大小后分子被拉伸或者只能看到左上角一块刷新页面才恢复正常但只要再动一下窗口又变形。原因viewer 创建时 WebGL 画布尺寸是固定的窗口 resize 之后 canvas 没有跟随容器尺寸变化导致画面比例错位。这是 WebGL 项目里非常经典的一个坑——渲染器的 viewport 不会自动感知外部布局变化。解决监听窗口的 resize 事件调用 viewer.resize() 让画布重新适配容器。正确写法如下window.addEventListener(resize, () { viewer.resize(); });注意 resize 方法会从容器元素读取最新尺寸所以容器本身不能是固定像素的需要使用相对单位或 flex 布局让它响应窗口变化。这个问题在做嵌入页面时特别常见——外层布局撑开之后viewer 如果不跟着变分子就会以奇怪的透视渲染出来。如果你用的是 React记得在组件卸载时移除这个监听否则会内存泄漏。6. 二次开发思路把查看器改造成分子分析小平台6.1 三个值得动手的扩展方向跑通之后这个项目的改造空间很大。我建议从三个方向入手按性价比排序。第一个是交互增强加上残基高亮、配体结合位点展示这只需要丰富 spec 选择器的用法改动集中在 main.js 的事件回调里。第二个是数据对接把硬编码的 sample.pdb 换成后端接口批量下发分子文件前端需要增加请求管理、加载态和错误提示。第三个是可视化能力扩展把 2D 的序列信息与 3D 结构联动点击序列某个残基3D 视图自动高亮对应位置。6.2 一个 20 行的改造自定义原子距离测量具体做一个小的。很多课题组需要测两个原子之间的距离项目默认没有这个功能改造思路是记录两次点击的原子通过 model.selectedAtoms 拿到坐标计算欧氏距离并显示在页面上。// 在 main.js 里扩展点击回调 let firstAtom null; viewer.setClickCallback(function (atom) { if (!atom) return; if (!firstAtom) { firstAtom atom; return; } const model viewer.getModel(); const a model.selectedAtoms({ atom: firstAtom.atom, resi: firstAtom.resi, chain: firstAtom.chain })[0]; const b model.selectedAtoms({ atom: atom.atom, resi: atom.resi, chain: atom.chain })[0]; const dist Math.sqrt( (a.x - b.x) ** 2 (a.y - b.y) ** 2 (a.z - b.z) ** 2 ); document.getElementById(measure-result).textContent ${firstAtom.atom}(${firstAtom.resi}) - ${atom.atom}(${atom.resi}) ${dist.toFixed(2)} Å; firstAtom null; });逻辑说明selectedAtoms 返回指定 spec 下的原子数组这里用原子名、残基号、链号三个字段定位原子确保选中的是同一个具体原子而不是同名原子。距离单位是埃ÅPDB 文件里的坐标单位就是埃不用做换算。这段代码改动量很小但已经能支撑一个基础的构象分析场景。如果想做得更全可以在两次点击之间画一条线3Dmol 支持直接构造线对象加入场景那一步就留给读者自己实现了。做这类二次开发我逐渐养成了一个习惯任何对 viewer 状态的改动无论是样式、模型还是尺寸最后都要检查 render 是否被调用了。3Dmol 的很多接口只是修改内部数据不触发重绘漏掉 render 就会遇到「代码执行了但画面没变化」的玄学现象。从那以后我每次跑完一段新功能都会强制走一遍「改动 → render → 浏览器 Console 确认无报错 → 旋转视角确认画面正常」的流程。这套流程帮我挡掉过至少一半的调试时间。希望这篇笔记能帮你在 3Dmol 前端项目上少走几步弯路跑起来、改得动。本文还有配套的精品资源点击获取