文章目录
1、UI组件/依赖库选择。
编辑器采用左右分割布局,左侧为Markdown编辑区,右侧为实时预览区,相关组件或依赖选择现成的开源库整合实现,减少开发成本。
1.1、左侧Markdown编辑区UI组件选择。
网上找了一下,仅发现RSyntaxTextArea https://github.com/bobbylight/rsyntaxtextarea这个组件比较适合。
RSyntaxTextArea的功能::
- 现成的文本编辑界面
- Markdown语法高亮显示
- 可定制的编辑功能
- 开源免费使用
1.2、webview组件选择
要创建markdown编辑,需要一个webview组件,在java里面可用的webview组件有:
- javafx.scene.web.WebView,开源免费,基于webkit内核
- jcef,开源免费,基于Chromium
- JxBrowser,商业收费,基于Chromium
在考虑免费和整合方便上,选择了javafx.scene.web.WebView。
1.3、markdown转html开源库选择。
-
CommonMark-java
- 基于CommonMark规范实现
- 轻量级,易于集成
- 支持标准Markdown语法
-
Flexmark-java
- 功能丰富的Markdown处理器
- 支持CommonMark和GitHub Flavored Markdown
- 可扩展性强,支持自定义扩展
-
Markdown4j
- 简单易用的Markdown解析器
- 基于JavaScript的markdown.js移植
- 适合基本的Markdown转换需求
-
Txtmark
- 轻量级Markdown处理器
- 性能较好
- 支持基本Markdown语法
Flexmark-java支持最完整,选择了它。
2、核心技术实现
2.1、左侧Markdown编辑区实现
编辑区采用RSyntaxTextArea,初始化代码如下:
// 初始化面板
private void initPanel() {
textArea = new RSyntaxTextArea();
textArea.setCodeFoldingEnabled(true);
textArea.setSyntaxEditingStyle(SyntaxConstants.SYNTAX_STYLE_MARKDOWN);
textArea.setAntiAliasingEnabled(true);
textArea.setFont(Config.getFont());
textArea.setLineWrap(Config.isIsLineWrap());
textArea.addCaretListener(e -> {
try
{
int pos = textArea.getCaretPosition();
//获取行数
int row = textArea.getLineOfOffset(pos) + 1;
//获取列数
int col = pos - textArea.getLineStartOffset(row - 1) + 1;
rowValueLabel.setText(String.valueOf(row));
columnValueLabel.setText(String.valueOf(col));
}
catch(Exception ex){
log.log(Level.SEVERE, " 无法获得当前光标位置 ", ex);
}
});
scrollPane = new RTextScrollPane(textArea);
this.add(scrollPane, BorderLayout.CENTER);
}
2.2、右侧webview预览实现
预览区采用javafx.scene.web.WebView,初始化代码如下:
private void initWebView(JFXPanel fxPanel){
WebView webView = new WebView();
webEngine = webView.getEngine();
webEngine.setOnAlert((WebEvent<String> wEvent) -> {
System.out.println("alert========: " + wEvent.getData());
});
webEngine.setOnError((WebErrorEvent wEvent) -> {
System.out.println("error========: " + wEvent.getMessage());
});
String body = "";
String markdown = textArea.getText();
if (!StrUtil.isEmpty(markdown)){
body = Markdown2Html.toHtml(markdown);
}
webEngine.loadContent(getHtml(body), "text/html");
Scene scene = new Scene(new StackPane(webView));
fxPanel.setScene(scene);
}
2.3、markdown转html实现
左侧编辑区增加文本变动监听器,使用flexmark-java将Markdown文本转换为HTML,并通过WebView加载。关键步骤包括:
// 监听文本编辑,如果文本内容有更新,则将markdown转为html,并更新webview。
class MdDocumentListener implements DocumentListener {
public void insertUpdate(DocumentEvent e) {
}
public void removeUpdate(DocumentEvent e) {
}
public void changedUpdate(DocumentEvent e) {
String markdown = editor.getTextArea().getText();
String html = Markdown2Html.toHtml(markdown);
Platform.runLater(() -> {
JSObject obj = (JSObject) webEngine.executeScript("window");
obj.setMember("javaContent", html);
webEngine.executeScript("addHtml(javaContent)");
});
}
}
public class Markdown2Html {
private static Parser parser = null;
private static HtmlRenderer renderer = null;
public static String toHtml(String markdown) {
MutableDataSet options = new MutableDataSet();
options.set(Parser.EXTENSIONS, Arrays.asList(
TablesExtension.create(),
FootnoteExtension.create(),
TaskListExtension.create()
));
if (parser == null){
parser = Parser.builder(options).build();
renderer = HtmlRenderer.builder(options).build();
}
Node document = parser.parse(markdown);
return renderer.render(document);
}
}
3、运行效果
3.1、界面展示
启动应用后,界面呈现左右分割布局:左侧为支持语法高亮的文本编辑区,底部显示当前光标所在的行和列位置;右侧为实时渲染的预览区。

附件实现下载
748

被折叠的 条评论
为什么被折叠?



