RDKit.js + Vue3快速上手

一、环境准备

1. 创建 / 进入 Vue3 项目

复制代码
npm create vite@latest my-vue-rdkit -- --template vue
cd my-vue-rdkit
npm install

2. 安装 RDKit.js

复制代码
npm install @rdkit/rdkit

3. 关键配置(Vite 必须)

修改 vite.config.js,优化 WASM 加载:

复制代码
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'

export default defineConfig({
  plugins: [vue()],
  optimizeDeps: {
    exclude: ['@rdkit/rdkit'] // 跳过预构建,避免 WASM 报错
  },
  server: {
    headers: {
      'Cross-Origin-Opener-Policy': 'same-origin',
      'Cross-Origin-Embedder-Policy': 'require-corp'
    }
  }
})

二、封装 RDKit 工具类(推荐)

新建 src/utils/rdkit.js,全局复用,避免重复初始化:

复制代码
import initRDKit from '@rdkit/rdkit';

let RDKit = null;

// 初始化 RDKit(全局只执行一次)
export async function initRDKitKit() {
  if (RDKit) return RDKit;
  RDKit = await initRDKit();
  console.log('RDKit 加载成功:', RDKit.version());
  return RDKit;
}

// 获取 RDKit 实例
export function getRDKit() {
  if (!RDKit) throw new Error('请先调用 initRDKitKit()');
  return RDKit;
}

三、Vue 组件完整示例(直接用)

创建 src/components/MoleculeViewer.vue

复制代码
<template>
  <div class="molecule-container">
    <h2>RDKit.js + Vue 3 分子工具</h2>

    <!-- 1. SMILES 输入框 -->
    <div class="input-group">
      <input
        v-model="smiles"
        placeholder="输入 SMILES,例如:CC(=O)Oc1ccccc1C(=O)O(阿司匹林)"
      />
      <button @click="loadMolecule">加载分子</button>
    </div>

    <!-- 2. 分子结构 SVG 显示 -->
    <div class="svg-box" v-html="molSvg"></div>

    <!-- 3. 理化性质展示 -->
    <div class="descriptors" v-if="descs">
      <h4>理化性质</h4>
      <p>分子量:{{ descs.MolWt.toFixed(2) }}</p>
      <p>脂水分配系数(LogP):{{ descs.LogP.toFixed(2) }}</p>
      <p>极性表面积(TPSA):{{ descs.TPSA.toFixed(2) }}</p>
    </div>

    <!-- 4. 子结构搜索 -->
    <div class="input-group" style="margin-top:10px">
      <input v-model="smarts" placeholder="输入 SMARTS 子结构,例如:O=CO" />
      <button @click="substructMatch">子结构匹配</button>
    </div>
  </div>
</template>

<script setup>
import { ref, onMounted, onUnmounted } from 'vue';
import { initRDKitKit, getRDKit } from '../utils/rdkit';

const smiles = ref('CC(=O)Oc1ccccc1C(=O)O'); // 默认:阿司匹林
const smarts = ref('O=CO');
const molSvg = ref('');
const descs = ref(null);
let currentMol = null; // 当前分子对象

// 页面挂载时初始化 RDKit
onMounted(async () => {
  await initRDKitKit();
  loadMolecule();
});

// 加载并渲染分子
function loadMolecule() {
  const RDKit = getRDKit();
  
  // 销毁旧分子(必须!防止内存泄漏)
  if (currentMol) currentMol.delete();

  // 创建分子
  currentMol = RDKit.get_mol(smiles.value);
  if (!currentMol) {
    alert('SMILES 格式错误');
    return;
  }

  // 生成 SVG
  molSvg.value = currentMol.get_svg(500, 350);
  
  // 获取理化性质
  descs.value = currentMol.get_descriptors();
}

// 子结构匹配 + 高亮
function substructMatch() {
  if (!currentMol) return;
  const RDKit = getRDKit();

  // 子结构查询
  const qmol = RDKit.get_qmol(smarts.value);
  if (!qmol) {
    alert('SMARTS 格式错误');
    return;
  }

  // 获取匹配的原子
  const match = currentMol.get_substruct_match(qmol);
  qmol.delete(); // 用完销毁

  if (match) {
    // 高亮匹配部分
    const opts = JSON.stringify({
      atoms: match.atoms,
      bonds: match.bonds,
      width: 500,
      height: 350
    });
    molSvg.value = currentMol.get_svg_with_highlights(opts);
  } else {
    alert('未匹配到子结构');
  }
}

// 页面离开时销毁分子
onUnmounted(() => {
  if (currentMol) currentMol.delete();
});
</script>

<style scoped>
.molecule-container {
  max-width: 600px;
  margin: 20px auto;
  padding: 20px;
}
.input-group {
  display: flex;
  gap: 8px;
  margin-bottom: 15px;
}
input {
  flex: 1;
  padding: 8px;
  border: 1px solid #ddd;
  border-radius: 4px;
}
button {
  padding: 8px 12px;
  background: #42b983;
  color: white;
  border: none;
  border-radius: 4px;
  cursor: pointer;
}
.svg-box {
  border: 1px solid #eee;
  padding: 10px;
  min-height: 350px;
  display: flex;
  align-items: center;
  justify-content:center;
}
.descriptors {
  margin-top:15px;
  padding:10px;
  background:#f5f5f5;
  border-radius:4px;
}
</style>

四、在 App.vue 中使用

复制代码
<template>
  <MoleculeViewer />
</template>

<script setup>
import MoleculeViewer from './components/MoleculeViewer.vue';
</script>

五、运行项目

复制代码
npm run dev

打开浏览器即可看到:

  • SMILES 输入与分子实时渲染
  • 分子量、LogP、TPSA 自动计算
  • 子结构搜索 + 高亮匹配

六、RDKit.js + Vue 核心知识点

1. 生命周期注意事项

  • onMounted:初始化 RDKit(WASM 异步加载)
  • onUnmounted :必须销毁分子对象 mol.delete()
  • 避免在 setup 顶层直接调用 RDKit

2. 常用 API 速查

javascript

运行

复制代码
// 创建分子
const mol = RDKit.get_mol('SMILES');

// SVG 渲染
mol.get_svg(宽度, 高度);
mol.get_svg_with_highlights(高亮配置);

// 理化性质
mol.get_descriptors(); 

// 子结构
const qmol = RDKit.get_qmol('SMARTS');
mol.get_substruct_match(qmol);

// 格式转换
mol.get_molblock();
mol.get_inchikey();

3. 内存管理(非常重要)

  • 每次创建 get_mol() / get_qmol() 必须调用 .delete()
  • 切换分子前先销毁旧分子
  • 组件销毁时清理所有分子对象
相关推荐
想吃火锅10059 小时前
【leetcode】405.数字转换为十六进制数js
开发语言·javascript·ecmascript
阿猫的故乡12 小时前
Vue过渡动画从入门到装X:淡入淡出、滑动、列表动画、第三方库全搞定
前端·javascript·vue.js
裕波12 小时前
Vue&ViteConf 2026 将于 7 月 18 日在上海举办,尤雨溪将现场发表主题演讲
vue.js·vite
小和尚敲木头12 小时前
vue3 vite动态拼接图片路径
javascript
我叫黑大帅13 小时前
前端如何竖屏固定视口背景
前端·javascript·面试
不会敲代码113 小时前
我花了三天时间,终于把 Cookie、XSS、CSRF 和浏览器存储给整明白了
javascript·面试
贩卖黄昏的熊13 小时前
flex 布局快速梳理
开发语言·javascript·css3·html5
swipe13 小时前
Mem0 x Agent 实战系列:分层记忆 + 三路召回,搭建真正可用的长期记忆层
前端·javascript·面试
kyriewen14 小时前
手写 call、apply、bind:从原理到实现,附 3 个最容易忽略的边界情况
前端·javascript·面试
胡萝卜术14 小时前
从内存视角重新认识 JavaScript 数据类型:一份深度学习笔记
前端·javascript·面试