Vue.jsにマークダウンエディタを埋め込む【mavonEditor】

#この記事でできること

- マークダウンエディタをVueを使ってWebページに埋め込む
- prop,emitの使い方を理解できるようになる

#マークダウンとは

Qiitaの記事もこの書き方を採用しています。いちばんは誰が書いても簡単に書けて、綺麗に書き方が統一した文章が書けることですね。PCでメモを取る人や、エンジニアの大半の人はこれを愛用しています。

#mavonEditorとは

https://github.com/hinesboy/mavonEditor/blob/master/README-EN.md
Vue.jsで簡単に使うことができるマークダウンエディタです。
中国人が開発しているようで全部中国語で書かれています。ですが英語のREADMEもあるのでここを参考にしました。

以下の画像もこちらから抜粋

<img width="884" alt="スクリーンショット 2019-09-05 8.20.41.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/305510/dc6cca27-c2cc-ef17-d931-30d9f9ed94ab.png">

#Vue.jsへの導入手順



まずnpmかyarnでインストールします。

```terminal:
$ npm install mavon-editor --save 
または
$ yarn add mavon-editor
```
今回使うバージョンです。

```json:package.json
  "dependencies": {
    "mavon-editor": "^2.7.5",
    "vue": "^2.6.10"
  }
```

あとはvueファイルに記述していきます、ミニマムの構成が以下になります。
`v-model``="value"`は双方向レンダリングでvalueがマークダウンのテキスト内容が反映されます。`<mavon-editor>`タグを使っているところが実際にエディタが表示される部分です。

```vuejs:App.vue
<template>
  <div id="app">
    <div id="main">
      <mavon-editor v-model="value" />
    </div>
  </div>
</template>

<script>
import Vue from "vue";
import mavonEditor from "mavon-editor";
import "mavon-editor/dist/css/index.css";
Vue.use(mavonEditor);

export default {
  name: "app",
  data() {
    return { value: "" }; 
  }
};
</script>
```


#エディタの設定を変更する

具体的には**props**を使って設定します。
propsは「親→子」間コンポーネントの値渡しとして使われます。
言い換えると「コンポーネントに値を渡して動きを変える＝コンポーネントの設定を変える」ということです。

READMEを見るといろんな設定ができます。例えば上記のままだと中国語のエディタになるので、英語に変更しましょう。propsのlanguageを使います。

```html:App.vue
<div id="main">
  <mavon-editor v-model="value" language="en"/>  //languageを追加
</div>
```

さらにツールバーの設定もやっておきたいところです。

`:toolbars="markdownOption"`を追加します

```html:App.vue
<div id="main">
  <mavon-editor v-model="value" :toolbars="markdownOption" language="en" />
</div>
```
script側です。
ツールバーに表示したいものだけtrueにすればOKです。
設定項目が多すぎるので一部だけ抜粋しました、残りはREADMEを参考にしてください。
https://github.com/hinesboy/mavonEditor/blob/master/README-EN.md

```javascript:App.vue
data() {
    return {
      value: "",
      toolbars: {
        bold: true,
        italic: true,
        header: true,
      }
    };
  },
```


#エディタのイベントを検知する

こちらは**emit**を使います
emitは「子→親」間のコンポーネントの値渡しとして使われます、ただし値を直接渡すのではなく、イベントを発行する形とります。
ここでは子は`<mavonEditor>`コンポーネントなので、コンポーネント内で変更を検知したときにイベントが発行されて、親であるコンポーネントを使うページでイベントを受け取ることができるのです。

具体的な書き方ですが、例として「エディタに入力された値が変更されたとき」にイベントを発行する`change`を使ってみます。`<mavonEditor>`コンポーネントではどのタイミングでイベントを発行するかは定義済みなので、あとは親側（コンポーネントを使う側）を記述をすればOKです。
<img width="902" alt="スクリーンショット 2019-09-05 8.52.58.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/305510/629ccfbc-025b-d405-87a4-9f7aae74efdf.png">

まずテンプレート側
`@change="changeText"`でイベントを受け取ります
`changeText`は適当な名前でOKです
あとで動きがわかるように`mdText`と`htmlText`を表示させます

```html:App.vue
<template>
  <div id="app">
    <div id="main">
      <!-- @changeを追加 -->
      <mavon-editor v-model="value" language="en" @change="changeText" />
    </div>
    <div>mdText:{{ mdText }}</div>
    <div>htmlText:{{ htmlText }}</div>
  </div>
</template>
```

次にscript側です
イベントを受け取る関数を定義します。引数には`value`がマークダウンのテキスト、`reder`がHTMLタグに変換されたテキストになります。ここではあらかじめdataで定義した`mdText`と`htmlText`に代入させます
（rederはrenderの間違いような気がしますが、READMEに合わせておきます。）

```javascript:App.vue
export default {
  name: "app",

  data() {
    return { value: "", mdText: "", htmlText: "" }; //mdTextとhtmlTextを追加
  },

  // changeTextメソッドを追加
  methods: {
    changeText(value, reder) {
      this.mdText = value;
      this.htmlText = reder;
    }
  }
};
```

実際の動きです。
![Sep-05-2019 07-44-16.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/305510/1401355b-c85d-3590-19fa-353ece4063cb.gif)

#悩み
###取得したHTMLテキストを取り扱う際に注意が必要
上の例だと`htmlText`の中身を[v-htmlで表示](https://jp.vuejs.org/v2/guide/syntax.html#%E7%94%9F%E3%81%AE-HTML)させれば、マークダウン対応の掲示板が作れたりします。
ただしリンク先でも書いてありますが、``v-htmlを使う際はXSSを引き起こさないようにする必要があります``、たとえばタグを制限するなどです。問題点という程ではないですが、HTML形式でを埋め込む際には別で対処が必要なのが悩ましいところです。

###一部ショートカットキーが使いづらい
エディタ内でショートカットキーが使えるのですが、言ってしまうと`CTRL(Command)+BreakSpace`が使いづらいです。
書いた内容が全て消えてしまいます。Macでは`(Command)+BreakSpace`で一行削除なのですが、これが使えない上に私はよく使っているので間違って全部消してしまうことがよくあります。これは直してほしい。。。

#まとめ

- 使いながらprop,emitの使い方を復習できた
- mavonEditorは導入が簡単な反面、多少面倒でも便利なマークダウンエディタを探して使ってみたほうがいいかも