DirectSurface UIDirectSurface UI
开始使用
文档/开始使用

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.widthcanvas.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。

继续阅读应用上下文命令与权限页面上下文与生命周期