react native expo框架,如何实现一款移动端的markdown文章编辑器

28 阅读3分钟

掘金编辑器支持完整的Markdown语法

基于WebView实现Markdown编辑的核心逻辑

在Expo中使用WebView,本质是将Web端成熟的Markdown编辑方案嵌入到原生APP中,核心优势是能复用Web生态丰富的编辑器资源,同时保留原生APP的交互体验。

组件截图

Vue官方Logo

技术选型思路

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端编辑器的交互与存储功能正常运行。

具体实现步骤

  1. 搭建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端的消息格式统一,避免因数据格式错误导致通信失败。