掘金编辑器支持完整的Markdown语法
基于WebView实现Markdown编辑的核心逻辑
在Expo中使用WebView,本质是将Web端成熟的Markdown编辑方案嵌入到原生APP中,核心优势是能复用Web生态丰富的编辑器资源,同时保留原生APP的交互体验。


技术选型思路
1. Web端编辑器选择
● 轻量需求:选择 SimpleMDE 或 Editor.md ,这类编辑器体积小、集成简单,支持基础Markdown语法与实时预览。
● 复杂需求:选择 Slate.js 或 ProseMirror ,可实现自定义排版、协同编辑等高级功能,但需要更多的二次开发。
● 推荐优先使用 Marked.js + CodeMirror 组合,前者负责Markdown解析,后者提供代码编辑与语法高亮能力,灵活性更高。
2. Expo WebView组件配置
● 使用Expo官方的 expo-webview 组件,它对原生WebView进行了封装,支持Android和iOS平台的一致性体验。
● 开启 javaScriptEnabled 与 domStorageEnabled ,确保Web端编辑器的交互与存储功能正常运行。
具体实现步骤
- 搭建Web端编辑页面 ● 创建一个独立的HTML文件(如 editor.html ),引入所选的Web端编辑器资源:
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/simplemde@1.11.2/dist/simplemde.min.css">
</head>
<body>
<textarea id="editor"></textarea>
<script src="https://cdn.jsdelivr.net/npm/simplemde@1.11.2/dist/simplemde.min.js"></script>
<script>
// 初始化编辑器
const simplemde = new SimpleMDE({ element: document.getElementById('editor') });
// 接收原生APP传递的初始内容
window.addEventListener('message', (event) => {
if (event.data.type === 'INIT_CONTENT') {
simplemde.value(event.data.content);
}
});
// 向原生APP发送编辑后的内容
simplemde.codemirror.on('change', () => {
window.ReactNativeWebView.postMessage({
type: 'CONTENT_CHANGE',
content: simplemde.value()
});
});
</script>
</body>
</html>
● 将HTML文件放置在Expo项目的 assets 目录下,通过 expo-asset 加载本地资源。
2. Expo端集成WebView ● 安装依赖:
expo install expo-webview expo-asset
● 在React组件中使用WebView,实现原生与Web端的通信:
import React, { useState, useRef } from 'react';
import { View, StyleSheet } from 'react-native';
import { WebView } from 'expo-webview';
import { Asset } from 'expo-asset';
export default function MarkdownEditor() {
const [content, setContent] = useState('');
const webViewRef = useRef(null);
// 加载本地HTML文件
const getHtmlUri = async () => {
const asset = Asset.fromModule(require('./assets/editor.html'));
await asset.downloadAsync();
return asset.uri;
};
// 接收Web端发送的内容
const handleMessage = (event) => {
const data = JSON.parse(event.nativeEvent.data);
if (data.type === 'CONTENT_CHANGE') {
setContent(data.content);
}
};
// 向Web端发送初始内容
const sendInitContent = () => {
webViewRef.current.postMessage(JSON.stringify({
type: 'INIT_CONTENT',
content: '# 初始Markdown内容'
}));
};
return (
<View style={styles.container}>
<WebView
ref={webViewRef}
source={{ uri: getHtmlUri() }}
onMessage={handleMessage}
onLoadEnd={sendInitContent}
javaScriptEnabled={true}
domStorageEnabled={true}
style={styles.webView}
/>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
},
webView: {
flex: 1,
},
});
关键交互与通信实现
1. 内容双向同步
● 原生→Web:通过 postMessage 将初始内容或已保存的内容发送到Web端,Web端编辑器接收后更新显示。
● Web→原生:监听Web端编辑器的内容变化事件,实时将最新Markdown文本发送回原生APP,保存到本地或上传服务器。
2. 原生功能调用
● 若需要调用原生设备能力(如选择图片、打开相机),可通过WebView的 postMessage 向原生发送指令,原生处理完成后再将结果返回给Web端。
● 示例:Web端触发图片选择,原生调用 expo-image-picker 选择图片,上传至图床后将图片URL返回给Web端,插入到Markdown内容中。
优势与注意事项
● 复用Web生态:直接使用Web端成熟的Markdown编辑器,无需从零开发复杂的编辑逻辑。
● 跨平台一致性:WebView中的编辑体验在Android和iOS平台基本一致,减少适配成本。
● 功能拓展灵活:可通过Web端技术快速实现协同编辑、云端备份等高级功能。
注意事项
● 性能优化:WebView加载本地HTML文件比远程URL更快,建议将编辑器资源打包到本地。
● 交互适配:Web端编辑器的工具栏按钮尺寸、字体大小需适配移动端屏幕,避免操作不便。
● 通信稳定性:确保原生与Web端的消息格式统一,避免因数据格式错误导致通信失败。