Vue.js製のブロックエディタを作ってみた話（WYSIWYGエディタの代替として）

# デモ

まずはデモ

<p class="codepen" data-height="595" data-theme-id="0" data-default-tab="result" data-user="takitakit" data-slug-hash="RmpVKL" data-preview="true" style="height: 595px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;" data-pen-title="block-editor-vue with source output demo">
  <span>See the Pen <a href="https://codepen.io/takitakit/pen/RmpVKL/">
  block-editor-vue with source output demo</a> by takitakit (<a href="https://codepen.io/takitakit">@takitakit</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://static.codepen.io/assets/embed/ei.js"></script>

# 背景

仕事でCMSの管理画面をスクラッチ制作する際の話。

例えば、お知らせの本文の編集欄を設計するとき、汎用性を考えてTinyMCEとかCKFinder(いわゆるWYSIWYGエディタ)を入れましょう、そうすると任意の場所に画像や見出しなどを自由に入力できるので便利です、とクライアントに説明して導入することが多いです。

それで何が問題かというと、WYSIWYGエディタは自由度が高い反面、「このエディタ操作して要素移動したらレイアウト崩れるんだけども」、とか、「操作性が悪くて使いづらい」、とおっしゃるクライアントさんが一定数おられるんですね。
確かに、制作者の立場でも、WYSIWYGエディタ上での編集（特に要素移動やテーブルなど）は若干慣れとコツがいると感じます。
(Wordpressなどに慣れていないクライアントさんもいらっしゃるので・・・）

また、制作者側の立場でも、想定外のクラスやスタイルを適用されて、意図しない表示になるのを防ぎたいので、ページの表示で使用するマークアップを限定しておきたい、というのもあります。
サイトのデザインテイストの一貫性は保ちたいですから、color:#f00の赤字やら、超大きい文字やらを自由に使われると困るわけです。
WYSIWYGエディタでも、使える要素の制限かけれるよ、と言われるとごもっともなのですが、クラス名や適用される文字スタイルなどを制限することは割と手間がかかると思います。

つまり、WYSIWYGエディタについて、下記を課題に感じています。

* 慣れないと使いづらい
* 慣れてもマークアップが崩れてしまうケースがある
* マークアップの制限がかけづらい、手間がかかる

# ブロックエディタの開発

ということで、WYSIWYGエディタの代替として、

* 使い勝手の良い、慣れなくても使いやすい
* マークアップを極力編集させない
* マークアップの制限を簡単にかけられる

という要件を満たしたエディタを作ってみよう、という流れになりました。
（Vue.jsを使ったのは、なかなか業務で触れる機会がなく、是非触ってみたい、ということで勉強がてらに始めていたからです。Vue.js、とても良いです！）

ソースは[Github](https://github.com/takitakit/block-editor-vue)にも上げているので、詳しくは参照お願いします。

## できること

* 決められたブロック要素を自由に組み合わせて編集し、全体として一つのマークアップを出力すること
* hidden要素を起点としてタグを書き出したり、読み込んだりすること（管理画面でPOSTすることを想定）

使い勝手を向上させる、という観点から、直接HTMLマークアップを編集したり、Wordから直接スタイルつきの文章をペーストしたりして整形したり、という事はできません。

## 使い方など

使用できるブロック要素の種類は下記になります。

* 段落（テキスト＋画像）
* 見出し
* リスト
* テーブル
* カラム（カラム以外の要素を入れ子にする）
* HTML（任意のHTMLマークアップの入力）

出力されるマークアップは、ブロック要素ごとにある程度決まっています。
例えば、段落の場合はこんな感じです。
クラス名(paragraph-wrap)などは、いろんな案件で使えるようにオプションで変更できるようになっています。

```html
<div class="paragraph-wrap align-left">
    <div class="text">
        "<a href="https://github.com/takitakit/block-editor-vue" target="_blank">block-editor-vue</a>" is a block editor that allows you to stack any combination of block elements, such as paragraphs, headings, lists, and so on.<br>If you are using the CMS management screen, you can use this editor as a means of editing the body HTML of an article.
    </div>
</div>
```

要素と要素の間にある (+) ボタンをマウスオーバーすると、要素追加のためのメニューが出てきます。
![block-editor-vue demo 2019-05-15 15-33-51.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/47348/0ce1b99e-4fd0-4323-5cfe-66e582d55ac9.jpeg)

また、要素名(Paragraph とか Headingなど)の部分をドラッグ&ドロップすると、要素単位で並べ替えを行うことができます。(ちょっと見づらいですが）
![block-editor-vue demo 2019-05-15 15-35-46.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/47348/fd04b2b5-80e4-38e4-4d90-51548972e6f7.jpeg)

個人的にも、WYSIWYGエディタでも特に使いづらいと感じるテーブルについても、一応セル結合、ドラッグ&ドロップによる入れ替え、列のサイズ変更も可能になっています。


<span>See the Pen <a href="https://codepen.io/takitakit/pen/arpLON/">
  block-editor-vue table demo</a> by takitakit (<a href="https://codepen.io/takitakit">@takitakit</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>

### 使用可能なブロック要素の種類を制限する

案件によっては、特定のブロック要素だけ使用可能にしたい、というケースもあります。
下記デモでは、使用できる要素を見出しと段落のみに、
またそれぞれに対して適用可能なCSSクラス名を
para-class1 / para-class2 および heading-class1 / heading-class2 に限定しています。

<span>See the Pen <a href="https://codepen.io/takitakit/pen/XwpeEj/">
  block-editor-vue  elements limitation demo</a> by takitakit (<a href="https://codepen.io/takitakit">@takitakit</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>

### プリセットの定義

特定のブロック要素とクラス名などをまとめて、プリセットとして名前を付けることができます。
例えば、下記は、

* 段落 + クラス名:description = "Description"
* 見出し(H2) + クラス名:title = "Title"
* 見出し(H3) + クラス名:sub-title = "Sub title"
 
というプリセットを設定しています。
クラス名が隠蔽されて表示されるので、入力者にCSSを意識させずに編集させることができます。

<span>See the Pen <a href="https://codepen.io/takitakit/pen/arNwGv/">
  block-editor-vue  presets demo</a> by takitakit (<a href="https://codepen.io/takitakit">@takitakit</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>

### インラインスタイルの定義

あらかじめインラインスタイルを定義しておき、
ブロック要素内のテキストに対して特定のインラインスタイルを適用することができます。

下記では、段落要素の中で、

* bold(太字）
* red（赤字）
* blue(青字)

を適用可能にしています。
サイトのデザインの都合上、制作側としては自由にテキストのスタイルを適用させたくないが、クライアント側の部分的にテキストを強調したりしたい、という要望にある程度応えるための機能です。

<span>See the Pen <a href="https://codepen.io/takitakit/pen/OYWzmg/">
  block-editor-vue inline-style demo</a> by takitakit (<a href="https://codepen.io/takitakit">@takitakit</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>

※ 出力されたマークアップ上では、style属性による直の指定ではなく、定義されたクラス名が適用されているだけなので、サイト上で表示を行う際には、別途スタイルの定義が必要になります。

マークアップの例

```html
<span class="ve-bold">Here is bold text.</span><!-- 太字 -->
<span class="ve-red">Here is red text.</span><!-- 赤字 -->
<span class="ve-blue">Here is blue text.</span><!-- 青字 -->
```

# 終わりに

ひとまず、できたライブラリを自社の業務に使用していますが、使いやすさの上で、ITリテラシーが低い方にもまずまず好評のようです。

当初目的にしていた

* 使い勝手の良い、慣れなくても使いやすい
* マークアップを極力編集させない
* マークアップの制限を簡単にかけられる

という点はある程度満たせたかな—と思っています。

もしこの記事をご覧になった方で、ご意見、ご要望のある方はコメントを寄せていただけますと嬉しいです。