Получение атрибутов InnerBlocks и сохранение их в родительском - PullRequest
0 голосов
/ 23 января 2020

Я создал блок «Панели с вкладками» ( содержимое с вкладками ), который по сути является просто компонентом InnerBlocks, который допускает только блок «Панель». Когда вы создаете панель, вы должны дать ей заголовок, который затем используется на панели, а также кнопка «Вкладка». Поэтому в моей функции рендеринга панелей с вкладками мне нужно извлечь заголовок из дочерних блоков панелей.

Есть несколько подходов, которые я мог бы использовать, например, просто использовать регулярное выражение в рендеринге с вкладками. php функция поиска дочерних элементов html для правильных атрибутов, но это не кажется лучшим подходом.

Я думаю, что самым простым решением было бы прослушать любые изменения в блоках Panel и сохранить изменяется (заголовок и идентификатор в этом случае) на родителя. Мой текущий подход основан на этом обсуждении , которое использует хуки для прослушивания изменений. Эта часть, кажется, работает нормально, но мне нужно где-то сохранить выходные данные, поэтому я сохраняю их как атрибуты в блоке с вкладками. Поначалу кажется, что это нормально работает, но использование метода setAttributes непосредственно в функции редактирования приводит к проблемам. Если на странице слишком много блоков с вкладками, то React выдает ошибку «слишком много отрисовок».

Где должна жить моя функция «setAttributes», или есть ли лучший подход для передачи данных от дочернего элемента к родитель? Я думал об использовании ловушки useDispatch в дочернем процессоре, но мне нужно проверить много событий (заголовок меняется, блок переупорядочен, блок удален и т. Д. c.)

Вот соответствующие файлы js и php. Есть некоторые пользовательские элементы, но вы должны иметь возможность их анализировать.

tabbed-panel. js

import { arraysMatch } from 'Components/utils.js'
const { InnerBlocks } = wp.blockEditor
const { createBlock } = wp.blocks
const { Button } = wp.components
const { useDispatch, useSelect } = wp.data
const { __ } = wp.i18n

export const tabbedPanels = {
  name: 'my/tabbed-panels',
  args: {
    title: __('Tabbed Panels', '_ws'),
    description: __('Tabbable panels of content.', '_ws'),
    icon: 'table-row-after',
    category: 'common',
    supports: {
      anchor: true
    },
    attributes: {
      headings: {
        type: 'array',
        default: []
      },
      uids: {
        type: 'array',
        default: []
      }
    },
    edit: props => {
      const { setAttributes } = props
      const { headings, uids } = props.attributes
      const { insertBlock } = useDispatch('core/block-editor')
      const { panelHeadings, panelUids, blockCount } = useSelect(select => {
        const blocks = select('core/block-editor').getBlocks(props.clientId)
        return {
          panelHeadings: blocks.map(b => b.attributes.heading),
          panelUids: blocks.map(b => b.clientId),
          blockCount: select('core/block-editor').getBlockOrder(props.clientId).length
        }
      })
      if (!arraysMatch(panelHeadings, headings)) {
        setAttributes({ headings: panelHeadings })
      }
      if (!arraysMatch(panelUids, uids)) {
        setAttributes({ uids: panelUids })
      }
      return (
        <div className="block-row">
          <InnerBlocks
            allowedBlocks={ ['my/panel'] }
            templateLock={ false }
            renderAppender={ () => (
              <Button
                isSecondary
                onClick={ e => {
                  insertBlock(createBlock('my/panel'), blockCount, props.clientId)
                } }
              >
                { __('Add Panel', '_ws') }
              </Button>
            ) }
          />
        </div>
      )
    },
    save: props => {
      return (
        <InnerBlocks.Content />
      )
    }
  }
}

tabbed-Panel-render. php

<?php
function block_tabbed_panels($atts, $content) {
  $atts['className'] = 'wp-block-ws-tabbed-panels ' . ($atts['className'] ?? '');
  $headings = $atts['headings'] ?? '';
  $uids = $atts['uids'] ?? '';
  ob_start(); ?>
    <div class="tabs" role="tablist">
      <?php
      foreach ($headings as $i=>$heading) : ?>
        <button
          id="tab-<?= $uids[$i]; ?>"
          class="tab"
          role="tab"
          aria-selected="false"
          aria-controls="panel-<?= $uids[$i]; ?>"
          tabindex="-1"
        >
          <?= $heading; ?>
        </button>
        <?php
      endforeach; ?>
    </div>
    <div class="panels">
      <?= $content; ?>
    </div>
  <?php
  return ob_get_clean();
}

панель. js

import ComponentHooks from 'Components/component-hooks.js'
const { InnerBlocks, RichText } = wp.blockEditor
const { __ } = wp.i18n

export const panel = {
  name: 'my/panel',
  args: {
    title: __('Panel', '_ws'),
    description: __('Panel with associated tab.', '_ws'),
    icon: 'format-aside',
    category: 'common',
    supports: {
      customClassName: false,
      html: false,
      inserter: false,
      reusable: false
    },
    attributes: {
      heading: {
        type: 'string'
      },
      uid: {
        type: 'string'
      }
    },
    edit: props => {
      const { setAttributes } = props
      const { heading } = props.attributes
      return (
        <>
          <ComponentHooks
            componentDidMount={ () => setAttributes({ uid: props.clientId }) }
          />
          <RichText
            label={ __('Tab Name', '_ws') }
            placeholder={ __('Tab Name', '_ws') }
            tagName="h4"
            onChange={ newValue => setAttributes({ heading: newValue }) }
            value={ heading }
          />
          <InnerBlocks
            templateLock={ false }
          />
        </>
      )
    },
    save: props => {
      return (
        <InnerBlocks.Content />
      )
    }
  }
}

панель-рендер. php

<?php
function block_panel($atts, $content) {
  $uid = $atts['uid'] ?? '';
  ob_start(); ?>
    <div
      id="panel-<?= $uid ?>"
      class="panel"
      role="tabpanel"
      aria-labelledby="tab-<?= $uid; ?>"
      tabindex="0"
      hidden="hidden"
    >
      <?= $content; ?>
    </div>
  <?php
  return ob_get_clean();
}

1 Ответ

0 голосов
/ 08 апреля 2020

Вы можете получить доступ к дочерним блокам от родителя и получить атрибуты (заголовок вкладки в вашем случае).

componentDidUpdate(previousProps, previousState) {
    var myID = this.props.clientId;
    var tabs_title = [];
    this.myBlock = wp.data.select('core/block-editor').getBlock(myID);
    this.myBlock.innerBlocks.map(block => {
         tabs_title.push( block.attributes.title );
    });
    this.props.setAttributes({ 'tabs_title': tabs_title });
}
...