Skip to content

父组件集成

父组件通常负责路由、业务按钮、文件选择器、保存位置、分享反馈和权限状态;MolEditor 负责画布、历史、选区、对象编辑与插件 runtime。

完整宿主工具栏示例

vue
<script setup lang="ts">
import { ref } from 'vue'
import { MolEditor, PRESET_TOOLS, type DocumentSnapshot } from '@shangchien/molio'
import '@shangchien/molio/style.css'

const editorRef = ref<InstanceType<typeof MolEditor> | null>(null)
const fileInputRef = ref<HTMLInputElement | null>(null)
const snapshot = ref<DocumentSnapshot | null>(null)
const shareUrl = ref('')

function openFilePicker() {
  fileInputRef.value?.click()
}

async function onOpenFile(event: Event) {
  const input = event.target as HTMLInputElement
  const file = input.files?.[0]
  if (!file || !editorRef.value) return

  const nextSnapshot = await editorRef.value.loadDocumentWithWorkflow(file)
  if (nextSnapshot)
    editorRef.value.restoreDocumentSnapshot(nextSnapshot)

  input.value = ''
}

async function onSaveFile() {
  const blob = await editorRef.value?.saveDocumentWithWorkflow()
  if (!blob) return
  downloadBlob(blob, 'project.mpz')
}

async function onShare() {
  const shared = await editorRef.value?.shareDocumentWithWorkflow()
  shareUrl.value = shared?.url ?? ''
  if (shared?.url)
    await navigator.clipboard.writeText(shared.url)
}

function downloadBlob(blob: Blob, filename: string) {
  const url = URL.createObjectURL(blob)
  const link = document.createElement('a')
  link.href = url
  link.download = filename
  link.click()
  URL.revokeObjectURL(url)
}
</script>

<template>
  <div class="host-toolbar">
    <button type="button" :disabled="!editorRef?.canUndo" @click="editorRef?.undo()">Undo</button>
    <button type="button" :disabled="!editorRef?.canRedo" @click="editorRef?.redo()">Redo</button>
    <button type="button" @click="editorRef?.reset()">Reset</button>
    <button type="button" @click="openFilePicker">读取文件</button>
    <button type="button" @click="editorRef?.addExplicitHydrogens()">加显式氢</button>
    <button type="button" @click="editorRef?.removeExplicitHydrogens()">去显式氢</button>
    <button type="button" @click="editorRef?.exportStagePng('molio.png')">导出 PNG</button>
    <button type="button" @click="editorRef?.exportStageSvg('molio.svg')">导出 SVG</button>
    <button type="button" @click="onSaveFile">保存文件</button>
    <button type="button" @click="onShare">分享</button>
  </div>

  <input ref="fileInputRef" hidden type="file" accept=".mpz" @change="onOpenFile">

  <MolEditor
    ref="editorRef"
    v-model:document-snapshot="snapshot"
    :options="{ width: 960, height: 640, defaultTool: PRESET_TOOLS.select }"
  />

  <a v-if="shareUrl" :href="shareUrl" target="_blank" rel="noreferrer">打开分享链接</a>
</template>

方法返回值约定

方法返回值说明
undo() / redo()boolean历史栈有可执行项时返回 true
reset()void清空当前文档,并按 options.viewport.autoFitOnLoad 处理视口。
loadDocumentWithWorkflow(file)Promise<DocumentSnapshot | null>需要 persistence workflow;返回快照后由宿主调用 restoreDocumentSnapshot()
saveDocumentWithWorkflow()Promise<Blob | null>需要 persistence workflow;宿主决定下载、上传或自动保存。
shareDocumentWithWorkflow()Promise<{ url?: string, blob?: Blob } | null>需要 share workflow;宿主决定复制 URL、二维码或上传 blob。
exportStagePng(filename?) / exportStageSvg(filename?)void导出当前画布。
addExplicitHydrogens() / removeExplicitHydrogens()boolean有选区时作用于选中分子;无选区时作用于全部分子。

宿主自行读取 SMILES / SDF

loadDocumentWithWorkflow() 面向 .mpz 或宿主 persistence 服务。如果文件来自业务接口,父组件可以先使用工具函数解析,再写入编辑器:

ts
import { molOrSdfToRdkitJsons, smilesToRdkitJson } from '@shangchien/molio/utils'

const sdfText = await fetch('/api/molecules.sdf').then(res => res.text())
const sdf = await molOrSdfToRdkitJsons(sdfText)
if (sdf.ok)
  editorRef.value?.reload(sdf.data)

const ethanol = await smilesToRdkitJson('CCO')
if (ethanol.ok)
  editorRef.value?.importMolecules([ethanol.data])

受控快照

v-model:document-snapshot 适合宿主保存草稿、实现外部撤销栈或把文档同步到业务状态。组件会避免把刚刚 emit 出去的同一个快照立刻恢复回来,因此可以安全地接入 Vue ref。

Released under GPL-3.0-only.