トップへ戻る
BLOGS

定義リストブロックのUPDATE

定義リストブロックの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}

しかしこれではブロック要素を削除されたりして、数が合わない場合などうまくレンダリング出来ないこともあるため、最良ではないと思います

もっと他にいい方法があるはずなので、ベストプラクティスを探したいと思います

今回は以上です

お疲れさまでした

コメントをお待ちしております

お気軽にコメントをどうぞ。

CAPTCHA