定義リストブロックのUPDATE
前回に続いてInnerBlockを使用し作成した定義リストブロックのアップデートを行った備忘録を残しておきます
前回作成した定義リストブロックはこちらから
こちらの定義リストブロックで改良を加えたい部分を自己流で機能を実装していく流れです
やりたいこととしては、
- リスト開閉のUIを追加する
- カラーピッカーの仕様変更
- リストのタイトルの背景色も変更可能にする
- 追加のCSS調整
- プレビューモードの仕様修正
こんなところですね
それでは上から順番に実装していこうと思います
リスト開閉のUIを追加する
ここはCSSに擬似要素を追加するだけでいけそうですね
考え方としては.panelOpen
クラスをJSで付け替えているのでこのクラスがある時にだけ疑似要素としてアイコンを表示するという感じでいけそうです
src/style.scss
/* アコーディオンのコンテンツ */ .panelOpen { .accordion__title { cursor: pointer; position: relative; margin-bottom: 2px; &:hover::after { color: rgb(68, 80, 82); } &:after { content: '\f107'; position: absolute; top: 25%; right: 3%; font-size: 20px; color: #ccc; transition: .3s; } &.is-active::after { content: '\f106'; } } .accordion__content { display: none; cursor: pointer; } .accordion__content.is-open { display: block; } } //.panelOpen
アイコンは適宜お好みで変更ください
ポイントは開けれると認識しやすくするためのアイコンとマウスオーバー時のポインターの変更、.is-active
クラス名を付与するようにしていたためこちらは閉じる側のアイコンを設定しました
カラーピッカーの仕様変更
現時点でWordPressコンポーネントであるカラーピッカーをインポートしてそのまま使用していますが、そのままでは使い勝手に気になるところがあったためこの仕様を変更したいと思います
やりたいこととしては
- 選択したカラーをリセットするボタンの実装
- 現在選択中のカラーが見にくいため、これを大きく表示
- カラーコードをコピーできると認識しやすくなるUIを追加
この3点を実装目標にしました
考え方としては、
現在のカラーピッカーを含む親コンポーネントを作成して、そこに必要な機能を盛り込んでいきたいと思います
親コンポーネント
まずは現在のカラーピッカーが表示されているインスペクターのメソッドを変更していきます
オリジナルのコンポーネントを記述し必要なプロパティを列挙して渡します
また、後にリストタイトルの背景色の実装も控えているためこのコンポーネントでは使い回しができるように、属性値などを扱う部分をプロパティとして与えています
src/block/dl.js
<PanelRow> <OjaColorPicker label="リスト背景色" attributes={attributes.themeColor} initialValue="#e1f5fe" setAttributes={(val) => setAttributes({ themeColor: val.hex })} colorReset={() => setAttributes({ themeColor: "#e1f5fe" })} /> </PanelRow>;
それではこれらのプロパティを使ってコンポーネントを作成していきましょう
./components/OjaColorPicker.js
import {ColorPicker} from "@wordpress/components"; const OjaColorPicker = (props) => { const { attributes, setAttributes, colorReset, initialValue, label } = props; const CopyedColor = () => { return ( <div className="copyedColor" style={{ backgroundColor: attributes }} ></div> ); } return [ <div className="ojaColorPicker"> <p>{label}</p> <ColorPicker color={attributes} onChangeComplete={setAttributes} defaultValue={initialValue} enableAlpha={true} /> <button onClick={colorReset}>resetする</button> <CopyedColor /> </div> ]; }; export default OjaColorPicker;
文頭では忘れずにカラーピッカーをインポートします
そしてprops
として受け取ったプロパティを分割代入でそれぞれのパラメータとして使用します
CopyedColor
というコンポーネントを作成していますがこちらが現在のカラーを表示できるように背景色に現在の値を設定しています
概要としては既存のカラーピッカーを追加したいメソッドやタグとともに新たにラップしたイメージです
このコンポーネントを作成したら忘れずに親ファイルでもインポートしておきましょう
src/block/dl.js
import OjaColorPicker from "./OjaColorPicker";
リストのタイトルの背景色を変更可能にする
実はさっきのコンポーネント作成でほとんど仕事は完了しています
プロパティとして値を受け取れるようにしておいたので、リストタイトル用の属性値を定義して渡すだけです
属性値を定義
src/block/dl.js
//属性値をattributesに追加 headTitleColor: { type: "string", default: "#0b048f", },
追加した属性値をコンポーネントに渡します
src/block/dl.js
<PanelBody title="リストデザイン設定" initialOpen={false}> //パネルとコンポーネントを追加 <PanelRow> <OjaColorPicker label="リストタイトル背景色" attributes={attributes.headTitleColor} initialValue="#0b048f" setAttributes={(val) => setAttributes({ headTitleColor: val.hex })} colorReset={() => setAttributes({ headTitleColor: "#0b048f" })} /> </PanelRow> <PanelRow> <OjaColorPicker label="リスト背景色" attributes={attributes.themeColor} initialValue="#e1f5fe" setAttributes={(val) => setAttributes({ themeColor: val.hex })} colorReset={() => setAttributes({ themeColor: "#e1f5fe" })} /> </PanelRow> </PanelBody>;
これで属性値の保存が可能になったので、この値を使って背景色をレンダリングメソッドに追加します
追加する場所はプレビューを表示するためのgetPreview()と最終的なフロントエンドとなるsaveメソッド内です
src/block/dl.js ※プレビューメソッド内とsaveメソッド内
{ attributes.dlTitle ? ( <h1 className="oja-dl-head" style={{ backgroundColor: attributes.headTitleColor }} > {attributes["dlTitle"]} </h1> ) : null; }
ここまで実装できたらエディター側で背景色の切り替えがリアルタイムに行うことが出来、またフロントエンド側にもしっかり反映されていることが確認できるはずです
確認ができたら管理画面のUIを簡単に整えます
管理画面のUIを仕上げる
今までの追加したカラーピッカーのUIを整えるだけです、適宜好みでどうぞ、
editor.scss
.ojaColorPicker { position: relative; p { border-top: 1px solid; font-weight: 600; margin-top: 10px; padding-top: 2px; } .components-spacer { display: none; } .components-flex-item { position: relative; &:after { content: 'コピー'; padding-left: 10px; font-size: 12px; } } button { cursor: pointer; display: inline; padding: 8px 3px; font-size: 12px; border-radius: 20px; border: 1px solid; margin-left: 10px; } .copyedColor { width: 60px; height: 25px; display: inline-block; margin-left: 20px; border-radius: 5px; } }
プレビューモードの見直し
最後に現在のプレビューモードの見直しです
現在プレビューモードはwithselect()
によってブロックの値を取得し渡すことでその値をレンダリングしています
edit: withSelect((select, ownProps) => { return { innerBlockProps: select("core/block-editor").getBlocks(ownProps.clientId), }; })((props) => { ※以下略。。。
そしてレンダリング方法ですが
特にループ処理をするわけでもなく、以下のように
<dt className="accordion__title"> {innerBlockProps[0].attributes.dtText} </dt> <dd className="accordion__content"> {innerBlockProps[1].attributes.ddText} </dd>
直接、ブロック要素の最初の2つを指定しているだけであったため
ブロックを追加ボタンを押してブロックを増やしていった際にすべてプレビューしきれないといった内容でありました
そこで今回のアップデートでこれをループ処理に書き換えて、ブロック要素がどれだけあろうと、全てレンダリングしてプレビューするようにしたいと思います
リストレンダーメソッドを定義
まずJSXでは条件分岐やループを記述することが出来ないため、メソッドを定義してその中で処理を行います
getPreview()メソッドのreturnのDLタグの部分を以下のように書き換えます
<dl className={addDlClass(className, attributes)}> {innerListContents(innerBlockProps)} </dl>;
そしてこのメソッドを定義します
getPreviewメソッド内
const innerListContents = (innerBlockProps) => { const dtContents = innerBlockProps.filter((dt) => dt.attributes.dtText); const ddContents = innerBlockProps.filter((dd) => dd.attributes.ddText); const listContents = ddContents.map((block, i) => { return ( <> <dt className="accordion__title"> {dtContents[i].attributes.dtText} </dt> <dd className="accordion__content"> {ddContents[i].attributes.ddText} </dd> </> ); }) return listContents; }
解説です
まず受け取ったブロックデータのオブジェクトは
innerBlockProps[0] => dtのデータ
innerBlockProps[1] => ddのデータ
といったように、dtとddが混在した状態であるためこれをそれぞれ取り出して新たな配列にします
innerBlockProps.filter((dt) => dt.attributes.dtText)
あとはこれらの要素を同時に出力できるようにmapメソッドのindex番号を使用し取り出していきます
ddContents.map((block, i) => dtContents[i].attributes.dtText}
しかしこれではブロック要素を削除されたりして、数が合わない場合などうまくレンダリング出来ないこともあるため、最良ではないと思います
もっと他にいい方法があるはずなので、ベストプラクティスを探したいと思います
今回は以上です
お疲れさまでした
コメントをお待ちしております