You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flutter集成Mermaid API遇阻,无法预览Mermaid代码为图表

Flutter Web集成Mermaid图表渲染解决方案

核心问题定位

  1. index.html中Mermaid脚本加载位置错误,DOM元素未就绪就执行渲染逻辑
  2. JS interop调用未处理异步特性,导致渲染时机偏差
  3. Markdown转换后的代码块未正确替换为Mermaid可识别的渲染容器

分步修复方案

1. 修正index.html配置

将Mermaid脚本放在<body>末尾,确保DOM元素先加载,同时提前全局配置Mermaid(与Dart端保持一致):

<!DOCTYPE html>
<html>
<head>
  <base href="$FLUTTER_BASE_HREF">
  <meta charset="UTF-8">
  <title>Flutter Mermaid Demo</title>
</head>
<body>
  <div id="mermaid-container"></div>
  <script src="https://cdn.jsdelivr.net/npm/mermaid@10/dist/mermaid.min.js"></script>
  <script>
    mermaid.initialize({
      securityLevel: 'strict',
      logLevel: 'error',
      startOnLoad: false,
      arrowMarkerAbsolute: true,
      flowchart: { htmlLabels: true }
    });
  </script>
  <script src="main.dart.js" type="application/javascript"></script>
</body>
</html>

2. 调整Dart代码逻辑

确保DOM完全加载后执行渲染,正确处理Mermaid异步渲染,并替换代码块容器:

import 'dart:html';
import 'package:flutter/material.dart';
import 'package:markdown/markdown.dart' as md;
import 'package:js/js.dart';
import 'package:js/js_util.dart';

// JS Interop 定义
@JS()
library mermaid;

@JS('mermaid.render')
external Promise<String> mermaidRender(String elementId, String mermaidCode);

// 自定义Sanitizer(保持原实现)
final nullSanitizer = NullTreeSanitizer();
class NullTreeSanitizer implements NodeTreeSanitizer {
  @override
  void sanitizeTree(Node node) {}
}

// 测试用Mermaid Markdown内容
const testContent = """
Sequence Diagram
------------------
```mermaid
sequenceDiagram
    actor Alice
    actor Bob
    Alice->>Bob: Hi Bob
    Bob->>Alice: Hi Alice

""";

class MermaidRenderer extends StatefulWidget {
@override
_MermaidRendererState createState() => _MermaidRendererState();
}

class MermaidRendererState extends State {
@override
void initState() {
super.initState();
// 等待Flutter框架和Web DOM都就绪后渲染
WidgetsBinding.instance.addPostFrameCallback((
) => renderCharts());
}

Future renderCharts() async {
final container = querySelector('#mermaid-container') as DivElement;
// 转换Markdown为HTML
final htmlContent = md.markdownToHtml(
testContent,
extensionSet: md.ExtensionSet.gitHubWeb,
);
container.setInnerHtml(htmlContent, treeSanitizer: nullSanitizer);

// 遍历所有Mermaid代码块,逐个渲染
final codeBlocks = container.querySelectorAll('code.language-mermaid');
for (var block in codeBlocks) {
  final parent = block.parent;
  if (parent is PreElement) {
    // 创建唯一ID的渲染容器
    final renderId = 'mermaid-${DateTime.now().millisecondsSinceEpoch}';
    final renderContainer = DivElement()..id = renderId;
    // 替换原pre/code容器
    parent.replaceWith(renderContainer);
    // 调用Mermaid异步渲染
    final svgResult = await promiseToFuture(mermaidRender(renderId, block.text));
    renderContainer.setInnerHtml(svgResult, treeSanitizer: nullSanitizer);
  }
}

}

@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Mermaid Chart Demo')),
body: const HtmlElementView(viewType: 'mermaid-container'),
);
}
}

### 3. 关键注意事项
- 不要混用`HtmlWidget`:该组件针对Flutter非Web端设计,Web端直接使用`HtmlElementView`绑定DOM元素更可靠
- 异步处理:Mermaid的`render`方法返回Promise,必须通过`promiseToFuture`转换为Dart Future等待结果
- 容器替换:Markdown转换后的`<pre><code>`块需要替换为独立Div容器,避免渲染冲突
- 安全级别:本地测试可临时将`securityLevel`设为`'loose'`,避免SVG被拦截,正式环境改回`'strict'`

---

## 简化替代方案:WebView直接加载
如果JS interop流程过于复杂,可直接用`webview_flutter`加载本地HTML文件:
1. 在`web`目录下创建`mermaid-chart.html`:
```html
<!DOCTYPE html>
<html>
<head>
  <script src="https://cdn.jsdelivr.net/npm/mermaid@10/dist/mermaid.min.js"></script>
  <script>mermaid.initialize({ startOnLoad: true });</script>
</head>
<body style="margin:0;">
  <pre class="mermaid">
sequenceDiagram
    actor Alice
    actor Bob
    Alice->>Bob: Hi Bob
    Bob->>Alice: Hi Alice
  </pre>
</body>
</html>
  1. Flutter中加载该文件:
import 'package:webview_flutter/webview_flutter.dart';

class MermaidWebView extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return WebView(
      initialUrl: 'mermaid-chart.html',
      javascriptMode: JavascriptMode.unrestricted,
      backgroundColor: Colors.transparent,
    );
  }
}

内容的提问来源于stack exchange,提问作者Omar Boshra

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.01 12:05:20