ある案件でさまざまなフィールドに触れていると、Vue.jsでPowerCMS Xのカスタム編集タイプを作成してみたくなり試してみました。Vue.jsを使用した経験はあるのですが昨年はReactを使用することが多かったため、「Vue 3から始める、Vue.js | CodeGrid」を読みつつ作成してみました。
表示サンプル
料理の材料名と分量を入力できるようになっています。Addボタンを押すと行が増えます。Up / Downボタンで行の入れ替えができます。Deleteを押すとその行は削除されます。
Addボタンの下にあるテキストエリアは開発用にJSONデータを表示させています。お客様に納品する際は非表示にします。
サンプルコード
GitHubのhideki-a/pcmsx-plugin-vue-editに格納しました。
Vue.jsを使用するメリット
- テンプレートとロジックを分離することができ、コードの見通しが良い
- データを操作すればリアクティブにUIが再描画される
- MTMLを知らなくても複雑な入力UIを作成できる
テンプレートはvue_edit.tmpl、Vue.jsはingredients.jsに記述していますが、シンプルに感じませんか? 行を増やす操作は空のデータを追加するだけ、項目を上下に移動させる操作もDOMを入れ替えるのではなくデータの順序を入れ替えるだけなので実装が簡単です。
CMSとのデータの受け渡し
- CMSからデータを受け取る際はJSONをBase64エンコードして
data-value
属性の値としました - 入力値をCMSに渡す際はtextarea要素にJSONをセットするようにしました(つまり通常の入力欄と同じです)
Base64エンコードした理由は、JSON文字列を属性値にするのが大変そうだと感じたからです。必須入力項目…例えばタイトルを入力しないで保存ボタンを押したときはエラーが発生しますが、それまで入力したデータが消えないように工夫しました。
アセットを指定可能にするパターン
フィールド(カスタムフィールド)の設定で表示される「アセット」のテンプレートを基にVue.jsに組み込んだところ、カスタム編集タイプでもアセット(画像)が選択できるようになりました。これを用いるとクックパッドのサイトにある「料理の作り方」のような入力も簡単に行えるようになります。
このサンプルは、PowerCMS Xが標準でロードしているBootstrapのGrid systemを用いてスマートフォンから幅の広い画面まできれいに表示されるように調整しました。サンプルコードは現在hideki-a/pcmsx-plugin-vue-editのtext-and-assetブランチに格納しています。
テンプレート
このエディタで編集してできあがったJSONは、そのままの状態でデータベースに保存されます。カラム名をcustom_edit
、画像のキーをasset_id
、テキストのキーをtext
とすると、以下のようなテンプレートでデータを表示することができます。
<mt:entrycustomedit from_json="vue_edit" />
<mt:loop name="vue_edit">
<mt:if name="__first__"><dl></mt:if>
<dt>画像</dt><dd><mt:var name="asset_id" escape /></dd>
<dt>テキスト</dt><dd><mt:var name="text" escape /></dd>
<mt:if name="__last__"></dl></mt:if>
</mt:loop>
コンポーネントベースのブロックエディタへの発展
ここまでのコードをさらに発展させるとPowerCMSブログで紹介されている「フィールドブロック(スニペットフィールドとカスタムオブジェクトによる入力欄セット追加UI)」のようなコンポーネントをベースにしたブロックエディタ(設計済のHTML/CSSコンポーネントに対応した入力フィールドを用意するブロックエディタ)も実装できそうです。試作品ではtinymce-vueを組み込み、リストや画像の挿入も可能です。ドラッグ&ドロップによるブロックの順序変更にも対応しています。
Vue.jsを使用しているとはいえ、入力フィールドのテンプレート作成で通常のHTML・MTMLと異なるのは主にv-model
の指定を追加することであり、それほどハードルは高くないのでは?と考えています。課題はブロックを選択した時に追加する空のオブジェクト(未入力のデータ)がブロックにより異なる点をどうクリアするかでしょうか。将来的には管理画面でブロック定義が可能になるかもしれません。
またパフォーマンスについて今後調査の必要がありますが、現状では画面に表示されているブロックのDOMのみ追加されていること、Vue.jsは仮想DOMによる高速レンダリングを実現していることがPowerCMSのフィールドブロックとの大きな違いです。