将 drawio HTML 嵌入 React

问题描述

从 draw.io 可以将图表嵌入为 HTML,但是,当尝试在 React 应用程序中使用生成的 HTML 时,屏幕上没有任何显示。以下脚本也加载到 HTML 页面中:<script type="text/javascript" src="https://viewer.diagrams.net/js/viewer-static.min.js"></script>

知道为什么这不起作用吗?

如果我将完全相同的代码和 HTML 放在一个没有 React 的文件中,一切都会按预期进行。

JS

const mystyle = {
  maxWidth: "100%",border: "1px solid transparent"
}

ReactDOM.render(
  <div className="mxgraph" style={mystyle} data-mxgraph="{&quot;highlight&quot;:&quot;#0000ff&quot;,&quot;nav&quot;:true,&quot;resize&quot;:true,&quot;toolbar&quot;:&quot;zoom layers lightBox&quot;,&quot;edit&quot;:&quot;_blank&quot;,&quot;xml&quot;:&quot;&lt;mxfile host=\&quot;app.diagrams.net\&quot; modified=\&quot;2021-04-08T16:37:39.233Z\&quot; agent=\&quot;5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML,like Gecko) Chrome/89.0.4389.114 Safari/537.36\&quot; etag=\&quot;O3fNti_B0JlDfU6ko1tb\&quot; version=\&quot;14.5.8\&quot; type=\&quot;google\&quot;&gt;&lt;diagram id=\&quot;3VQJ_haBxNLfYGOJBekl\&quot; name=\&quot;Page-1\&quot;&gt;zZZdb5swFIZ/DZeRAqQ0vUwJ68c0dVJUTdoNcu0TbBUwsg8D9utngiEgWjW7ibiKec4by+exZXD8MKsfFCn4D8kgdbw1qx1/73ieG6y35qcljSXu+rYjiRKsY+szOIi/YIM9LQUDbVmHUMoURTGFVOY5UJwwopssprGjTNkEFCSByTJacKAkhVnsl2dio7q9GaUfQSQch/5sJSN92ALNCZPVCPmR44dKSuxGWR1C2tqbevn2SXVYmIIcL/nDHW1U9DtSm9fb77s4eno5Pq9WdpY/JC1twzQVjr8zbE80f5nesdCQrgNsei1KljmDdmbX8e8rLhAOBaFttTInwTCOWWrL+h2QcvtwlDke7EQf9NAvCBRcpuK2pweQGaBqTMRWVxvr154wr3+uztvl9nvAR1sVWEbsCUmGqc8SzcB6/A+n3sypyIsSY4byZDZIzQru35QZJe0oqoGWKPJkV4inNrk3weUKd4MLhG+vKdyfCYdeaUwKEZf0S++vGkKiYcHaN97StG9m2lvZhFLQOk4IQkWaD8UPN4sRvzvFF+w92C7N+83Muyzx0gvm5RRd9g1zd8mVflXlwUx5oUCbDkF9afxZy/znkF6udfOSvJ5283j+8jnVRh+QfvQP&lt;/diagram&gt;&lt;/mxfile&gt;&quot;}"></div>,document.getElementById('root')
);

HTML

<div id="root"></div>

解决方法

我的任务是做类似的事情,但用的是 Vue JS 而不是 React。有了这个警告,我很高兴分享我的经验。

我们的目标是将 Drawio 实例嵌入到可以在更大的 Vue 应用程序中使用的 Vue 组件中。为此,我们试图让 Drawio 吐出它的 HTML,然后可以将其封装到一个组件中。不幸的是,由于多种原因,这不起作用:

  • 出于安全原因,在 Vue 中运行 vanilla JS(如 <script> 标签内)存在问题
  • 尝试等待 Drawio 部分完成加载存在时间问题
  • 他们在一起玩得很不愉快

几个小时后,我们意识到如果不分叉 Drawio 和大量重写库,这个任务基本上是不可能的。

下面是我们的非理想解决方案:

  1. 将 Drawio 代码托管在与静态服务器上的 Vue 代码不同的位置
  2. 使用 <iframe> 将 Drawio 代码导入到 Vue 上下文中
  3. 创建一个封装了 <iframe>
  4. 的 Vue 组件
<template>
    <iframe ref="drawioIFrame" :src="iFrameSrc" />
</template>

<script lang="ts">
import { Component,Vue } from 'vue-property-decorator'

@Component
export default class DiagramFrame extends Vue {

    get iFrameSrc(): string {
        return `http://mydrawiourl.com`
    }
}

</script>
  1. 为了在 Vue 和 Drawio 之间进行通信,我们使用了 window.postMessage。从 iframe 获取引用,我们可以发送这样的消息:

    drawIoWindow.postMessage(message,"*")
    

    在 Drawio 中:

    window.parent.postMessage({
      message
    },"*");
    
  2. 为了侦听来自另一端的消息,我们使用了以下内容:

    Vue:

    mounted() {
        window.addEventListener('message',this.handleMessagesFromDrawIo)
    }
    
    beforeDestroy() {
        window.removeEventListener('message',this.handleMessagesFromDrawIo)
    }
    

    绘图:

    mxEvent.addListener(window,'message',mxUtils.bind(this,messageHandler)); 
    

虽然不理想,但这种模式实际上对我们来说效果很好。