LoginSignup
108
88

More than 3 years have passed since last update.

Reactでマークダウンエディタ作成とマークダウンからHTMLに変換(ハイライト付き)

Last updated at Posted at 2020-03-17

Reactでマークダウンエディタの作成と、マークダウン表記をHTMLに変換(ハイライト付き)してみました。
ライブラリを組み合わせることで、楽に実装することができます。

環境

  • OS : macOS Catalina 10.15.3
  • node.js : 12.13.1
  • React : 16.12.0

Reactのライブラリは以下を使用します。

  • react-simplemde-editor(EasyMDE) : 4.1.0
  • marked : 0.8.0
  • highitjs : 9.16.2

参考までに、紹介するコードはGitHubにあります。

https://github.com/txkxyx/react-mde

マークダウンエディタを作成する

Webの画面にマークダウンエディタを埋め込む場合、元々SimpleMDEというライブラリが使用されていましたが、今はEasyMDEというSimpleMDEをフォークして作られたライブラリが使用されています。

↓EasyMDE

https://github.com/Ionaru/easy-markdown-editor

今回はEasyMDEのReactラッパーコンポーネントであるreact-simplemde-editorを使用してマークダウンエディタを作成します。

↓react-simplemde-editor

https://www.npmjs.com/package/react-simplemde-editor

まずは使用するパッケージをインストールします。

$ npm install react-simplemde-editor

コンポーネントを作成します。
実装はとてもシンプルです。SimpleMDEのコンポーネントとEasyMDEのcssファイルをインポートします。
SimpleMDEコンポーネントにはonChangeイベントで起動する関数を渡す必要があります。この関数は合成イベントを受け取り、その値がエディターで入力したマークダウンになります。

import React, { useState } from "react";
import SimpleMDE from 'react-simplemde-editor';
import 'easymde/dist/easymde.min.css';

const MarkDownEditor = () => {

    const [markdown, setMarkdown] = useState('');

    return(
        <SimpleMDE onChange={(e) => setMarkdown(e)}/>
    )
}
export default MarkDownEditor;

video1.gif

ツールバーにメニューが表示されています。デフォルトでは以下のメニューが表示されます。

メニュー 説明 表記
bold 強調 ****
italic 強勢 **
heading 見出し #
quote 引用 >
unordered-list 箇条書き *
ordered-list 番号付きリスト 1.
link リンク挿入  [](https://)
image 画像挿入  ![](https://)
preview プレビューモード なし
side-by-side 入力とプレビューで画面分割 なし
fullscreen 全画面でプレビューモード なし
guide マークダウン記法ガイド なし 

メニューの一覧は以下を確認してください。

https://github.com/Ionaru/easy-markdown-editor#toolbar-icons

メニューを追加する場合は以下のように実装します。
メニューを追加するとデフォルトのメニューが消えてしまうので、デフォルトのメニューを追加したい場合は別途追加します。

import React, { useState } from "react";
import SimpleMDE from 'react-simplemde-editor';
import 'easymde/dist/easymde.min.css';

const toolbar = [
        {
            name: "save",
            action: function customFunction(editor) {
                alert(editor.value())
                // save action
            },
            className: "fa fa-save",
            title: "Save"
        },
        '|',
        'bold',
        'italic',
        'heading',
        '|',
        'quote',
        'unordered-list',
        'ordered-list',
        '|',
        'link',
        'image',
        '|',
        'preview',
        'side-by-side',
        'fullscreen',
        '|',
        'guide',
    ]

const MarkDownEditor = () => {

    const [markdown, setMarkdown] = useState('');

    return(
        <SimpleMDE onChange={(e) => setMarkdown(e)} options={{toolbar:toolbar}}/>
    )
}
export default MarkDownEditor;

video2.gif

マークダウンエディタを拡張する

EasyMDEは機能を拡張することができます。その一つのCodeMirrorのイベント処理を利用して、JavaScriptのイベントをハンドリングしてみます。

CodeMirrorのイベントは以下から確認してください。

https://codemirror.net/doc/manual.html#events

画像などのファイルをマークダウンエディタにドロップして、そのデータを取得してみます。

import React, { useState } from "react";
import SimpleMDE from 'react-simplemde-editor';
import 'easymde/dist/easymde.min.css';

const MarkDownEditor = () => {

    const [markdown, setMarkdown] = useState('');

    function handleDrop(data, e){
        let files = e.dataTransfer.files;
        if(files.length > 0){
            let file = files[0];
            alert('FileName : ' + file.name );
            // any action
        }
    } 

    return(
        <SimpleMDE onChange={(e) => setMarkdown(e)} events={{'drop':handleDrop}}/>
    )
}
export default MarkDownEditor;

video3.gif

SimpleMDEのコンポーネントのeventsのpropsにドロップ時に起動する関数を指定します。
この関数内でファイルオブジェクトを取得することができます。この関数内で画像アップロードをすると、画像アップロード込みのマークダウンエディタを実装することができます。

マークダウン表記をHTMLに変換する

マークダウン形式の文字列をHTMLに変換するために、markedライブラリを使用します。

$ npm install marked

先ほど作成したエディタで入力されたマークダウンをmarkedでHTMLに変換し画面に表示します。
インポートしたmarkedの引数に、マークダウン形式の文字列を渡すだけです。

import React, { useState } from "react";
import SimpleMDE from 'react-simplemde-editor';
import 'easymde/dist/easymde.min.css';
import marked from "marked";

const MarkDownEditor = () => {

    const [markdown, setMarkdown] = useState('');

    return(
        <div>
            <SimpleMDE onChange={(e) => setMarkdown(e)}/>
            <div id="body" >
                <span dangerouslySetInnerHTML={{ __html: marked(markdown)}}/>
            </div>
        </div>

    )
}
export default MarkDownEditor;

video4.gif

これで、エディタで入力したマークダウンをHTMLに変換して表示することができます。

ではコードを挿入している部分にハイライトを追加していきます。

ハイライトをつける

コードを挿入している部分にハイライトを付けるために、highlightjsを導入します。
JavaScriptのハイライトのライブラリの中でも対応言語が多く、パレットの種類も豊富です。(185言語、91スタイル)

https://highlightjs.org/static/demo/

ライブラリをインストールします。

$ npm install highlightjs

実装は以下のようになります。

import React, { useState } from "react";
import SimpleMDE from 'react-simplemde-editor';
import 'easymde/dist/easymde.min.css';
import marked from "marked";
import highlight from 'highlightjs';
import 'highlightjs/styles/docco.css';

const MarkDownEditor = () => {

    const [markdown, setMarkdown] = useState('');

    return(
        <div>
            <SimpleMDE onChange={(e) => setMarkdown(e)}/>
            <div id="body" >
                <span dangerouslySetInnerHTML={{ __html: marked(markdown)}}/>
            </div>
        </div>

    )
}
export default MarkDownEditor;

video5.gif

highlightjsと適用したいスタイルのCSSファイルをインポートします。今回はdoccoというスタイルを使用したので、docco.cssをインポートしています。
CSSファイルはhighlightjs/styles/スタイル名.cssで指定できます。たまに違う場合もありますので、その時はハイフンを付けたりしてみてください。
highlightjsは表示する<code>タグのclass属性に指定されている言語名に応じてスタイルを適用します。

例えば、マークダウンで記載したPythonのコードは以下のような流れで表示されます。

  • マークダウン形式

```python

コード

```

  • markedでHTMLに変換

<span><code class="language-python">コード</code></span>

マークダウンで言語をPythonに指定しているので、markedでHTMLに変換したい際にcodeタグのclass属性にlanguage-pythonが指定され、highlightjsのスタイルが適用されます。
```python:test.pyのように言語名の後にファイル名を記載している場合、class属性にファイル名まで適用されてしまうため、markedのオプションを使用しレンダリング前にファイル名を除去することもできます。

実装は以下のようになります。


import React, { useState } from "react";
import SimpleMDE from 'react-simplemde-editor';
import 'easymde/dist/easymde.min.css';
import marked from "marked";
import highlight from 'highlightjs';
import 'highlightjs/styles/docco.css';

// delete file name
marked.setOptions({
    highlight: function (code, lang) {
        return highlight.highlightAuto(code, [lang.split(':')[0]]).value;
    }
});

const MarkDownEditor = () => {

    const [markdown, setMarkdown] = useState('');

    return(
        <div>
            <SimpleMDE onChange={(e) => setMarkdown(e)}/>
            <div id="body" >
                <span dangerouslySetInnerHTML={{ __html: marked(markdown)}}/>
            </div>
        </div>

    )
}
export default MarkDownEditor;

スタイルは豊富に用意されているので、サイトに合わせたハイライトを選択してみてください。

まとめ

Reactでライブラリを使用して、マークダウンエディタとマークダウンをHTMLに変換してみました。
コンポーネント一つ追加するだけで、簡単にマークダウンエディタを導入できます。拡張もできるので自由度はかなり高いかなと思っています。
他にもreact-mdeなどのエディタがありますが、デザインなどの面からreact-simplemde-editorの方が個人的には好みです。
もし使用する機会があれば検討してみてください。

108
88
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
108
88