PowerCMSのスニペットフィールドを利用して複数の入力欄を作成する必要が出たので「スニペットフィールドを使ってリンク入力欄(複数)を作成する | PowerCMS ブログ」を読みました。ただ、「ステップ 2. 入力画面用のテンプレートモジュールを作成」で「うっ…」となるのが正直な所ではないでしょうか。
ゆっくり落ち着いて読めば理解できるのですが、入力欄が増えたり複数のスニペットフィールドでこのコードを利用しはじめたりすると、なんだか作成・メンテナンスが大変そうです。
そこで、気軽に利用できるVue.jsで同じことを書いてみました。メリットは以下の2点だと考えます。まだ軽く動作確認をした段階ですが、PowerCMSブログのコードと同じ動作になっています。
- 同じような記述を繰り返す必要がない
- ライブラリに頼ることでコード量が減って見通しが良くなる
<mt:LocalVars>
<mt:Ignore>入力値を変数にセットする</mt:Ignore>
<mt:SetVar name="titles" />
<mt:SetVar name="urls" />
<mt:Loop name="customfield_entry_outerlink_title_loop">
<mt:SetVarBlock name="titles" function="push"><mt:Var name="snippet_option"></mt:SetVarBlock>
</mt:Loop>
<mt:Loop name="customfield_entry_outerlink_url_loop">
<mt:SetVarBlock name="urls" function="push"><mt:Var name="snippet_option"></mt:SetVarBlock>
</mt:Loop>
<mt:Ignore>入力フィールドの定義</mt:Ignore>
<div id="customfield_entry_outerlink">
<div v-for="(item, index) in items" :key="item.title" style="margin-block-start: 10px; padding: 10px; border: 1px solid #c0c6c9; background-color: #fff;">
<div><button type="button" @click="deleteItem(index)">削除</button></div>
<div>
<label :for="'customfield_entry_outerlink_title_' + index">リンクテキスト</label><br>
<input type="text" :id="'customfield_entry_outerlink_title_' + index" name="customfield_entry_outerlink_title" v-model="item.title" class="text full">
</div>
<div>
<label :for="'customfield_entry_outerlink_url_' + index">URL</label><br>
<input type="url" :id="'customfield_entry_outerlink_url_' + index" name="customfield_entry_outerlink_url" v-model="item.url" class="text full">
</div>
</div>
<div style="margin-block-start: 20px;"><button type="button" @click="addItem">入力欄を追加</button></div>
</div>
<mt:Ignore>入力フィールドのアプリケーション</mt:Ignore>
<script>
const { createApp } = Vue;
const defaultItem = {
// キーと初期値を列挙しておく
// 例)customfield_entry_outerlink_title だったら title にする。これが v-model="item.title" のような記述につながる。
title: '',
url: '',
};
createApp({
data() {
return {
// 入力値をJavaScriptのオブジェクトで出力する
// キーはdefaultItemの所に書いたものと同じにする
items: [<mt:If name="titles">
<mt:Loop name="titles">
<mt:Var name="__counter__" op="--" setvar="index" />
{
title: '<mt:Var name="titles" index="$index" />',
url: '<mt:Var name="urls" index="$index" />',
}<mt:unless name="__last__">,</mt:unless>
</mt:Loop>
<mt:Else>[{...defaultItem}]</mt:If>],
}
},
methods: {
deleteItem(index) {
if (window.confirm('削除しますか?')) {
this.items.splice(index, 1);
}
},
addItem() {
this.items.push(defaultItem);
},
}
}).mount('#customfield_entry_outerlink'); // 入力フィールドの定義に記述したID属性値をセット
</script>
</mt:LocalVars>
Vue.jsの読み込みが必要なので、PowerCMS設定内にある「<head> への埋め込み」欄に下記を記述しました。ローカルに設置してパスを書いてもOKです。また、フィールドのスタイルもCSSファイルにまとめ、パスをheadに追加するのが良いと思います。
<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
さらに改良するとすれば
Vue.jsのミックスインを使えばmethods
(フィールドの追加・削除処理)を1つにまとめることができるようです。ただ、Vue 3ではミックスインが非推奨になったようで、Composition APIを使用したコンポーザブル関数を使うのが良いそうです。(ひとまずミックスインでもいいかなぁ…)