Vue、React 与现有 Web 应用集成
DirectSurface UI 不要求业务应用更换 Vue、React 或现有路由系统。宿主框架负责 Canvas DOM 与页面生命周期,DirectSurface UI 负责 Canvas 内部的 Render Tree、布局、绘制和交互。
集成边界
Vue / React / 原生 Web
├─ 创建和定位 <canvas>
├─ 决定何时挂载、卸载
├─ 传入登录态、服务和初始参数
└─ 调用 AppHost.dispose()
DirectSurface UI
├─ 创建 RenderWindow / RenderPage
├─ 管理布局、组件、焦点和输入
├─ 管理 Popup、Overlay 与命令
└─ 调度 layout / paint / composite
不要让 Vue 或 React 同时管理 Canvas 内部控件;业务数据可以共享,但两套 UI 树应保持清晰边界。
React
在 effect 中挂载,在 cleanup 中释放。Canvas 引用变化或应用级依赖变化时,旧实例会先被正确销毁。
import { useEffect, useRef } from 'react'
import { Application, MedicalCompactLightTheme, type AppHost } from 'ds-ui'
import { createMainWindow } from './create-main-window'
export function CanvasWorkspace() {
const canvasRef = useRef<HTMLCanvasElement>(null)
useEffect(() => {
const canvas = canvasRef.current
if (!canvas) return
let host: AppHost | undefined
let cancelled = false
void import('ds-ui').then(async ({ loadDirectSurfaceFonts }) => {
await loadDirectSurfaceFonts()
if (cancelled) return
host = Application.mount('#ds-ui-workspace').run(createMainWindow(), {
theme: MedicalCompactLightTheme,
})
})
return () => {
cancelled = true
host?.dispose()
}
}, [])
return <canvas id="ds-ui-workspace" ref={canvasRef} className="canvas-workspace" />
}
cancelled 标记保证异步字体加载完成前组件已经卸载时,不会再创建一个失去宿主的 host。
Vue 3
<script setup lang="ts">
import { onBeforeUnmount, onMounted, ref } from 'vue'
import { Application, MedicalCompactLightTheme, loadDirectSurfaceFonts, type AppHost } from 'ds-ui'
import { createMainWindow } from './create-main-window'
const canvas = ref<HTMLCanvasElement>()
let host: AppHost | undefined
let cancelled = false
onMounted(async () => {
await loadDirectSurfaceFonts()
if (cancelled || !canvas.value) return
host = Application.mount('#ds-ui-workspace').run(createMainWindow(), {
theme: MedicalCompactLightTheme,
})
})
onBeforeUnmount(() => {
cancelled = true
host?.dispose()
host = undefined
})
</script>
<template>
<canvas id="ds-ui-workspace" ref="canvas" class="canvas-workspace" />
</template>
尺寸与样式
Canvas 必须从 CSS 获得明确尺寸。runtime 会根据逻辑尺寸与设备像素比同步绘图缓冲区;业务代码不要自行循环修改 canvas.width 和 canvas.height。
.canvas-workspace {
display: block;
width: 100%;
height: 100%;
min-width: 0;
min-height: 0;
}
如果 Canvas 位于 Flex 或 Grid 子项中,父级也要允许收缩并提供可计算高度,否则看似“没有渲染”往往只是宿主尺寸为零。
数据与服务注入
- 应用级登录态、服务和权限通过
ApplicationRunOptions.context或应用上下文注册表注入。 - 页面内业务状态可以保留在现有 store 中,再通过订阅或绑定更新 RenderObject。
- 不要把 React/Vue 组件实例传入 Render Tree,也不要从 Canvas 组件直接修改宿主 DOM。
继续阅读应用上下文、命令与权限和页面上下文与生命周期。