Создание пользовательского блока отображения

В NocoBase блок — это область содержимого на странице. Этот пример показывает, как с помощью BlockModel создать простейший пользовательский блок — поддерживающий редактирование HTML-содержимого в интерфейсе. Пользователь может через панель конфигурации изменять отображаемое содержимое блока.

Это первый пример, затрагивающий FlowEngine — будут использованы BlockModel, renderComponent, registerFlow и uiSchema.

Предварительное чтение

Рекомендуется сначала ознакомиться со следующим — это упростит разработку:

Конечный результат

Мы делаем блок «Simple block»:

  • Появляется в меню «Добавить блок»
  • Рендерит сконфигурированное пользователем HTML-содержимое
  • Через панель конфигурации (registerFlow + uiSchema) позволяет пользователю редактировать HTML

Полный исходный код см. в @nocobase-example/plugin-simple-block. Если хотите запустить и посмотреть локально:

yarn pm enable @nocobase-example/plugin-simple-block

Ниже шаг за шагом построим этот плагин с нуля.

Шаг 1: создать каркас плагина

Выполните в корне репозитория:

yarn pm create @my-project/plugin-simple-block

Это сгенерирует базовую файловую структуру в packages/plugins/@my-project/plugin-simple-block. Подробное описание см. в Написание первого плагина.

Шаг 2: создать модель блока

Создайте src/client-v2/models/SimpleBlockModel.tsx. Это ядро плагина — здесь определяется, как блок рендерится и как настраивается.

// src/client-v2/models/SimpleBlockModel.tsx
import React from 'react';
import { BlockModel } from '@nocobase/client-v2';
import { tExpr } from '../locale';

export class SimpleBlockModel extends BlockModel {
  renderComponent() {
    return <div dangerouslySetInnerHTML={{ __html: this.props.html }} />;
  }
}

// 设置区块在「添加区块」菜单里的显示名
SimpleBlockModel.define({
  label: tExpr('Simple block'),
});

// 注册配置面板,让用户可以编辑 HTML 内容
SimpleBlockModel.registerFlow({
  key: 'flow1',
  title: tExpr('Simple Block Flow'),
  on: 'beforeRender', // 渲染前执行
  steps: {
    editHtml: {
      title: tExpr('Edit HTML Content'),
      // uiSchema 定义配置面板的表单 UI
      uiSchema: {
        html: {
          type: 'string',
          title: tExpr('HTML Content'),
          'x-decorator': 'FormItem',
          'x-component': 'Input.TextArea',
        },
      },
      // 配置面板的默认值
      defaultParams: {
        html: `<h3>This is a simple block</h3>
<p>You can edit the HTML content.</p>`,
      },
      // 把配置面板的值写入 model 的 props
      handler(ctx, params) {
        ctx.model.props.html = params.html;
      },
    },
  },
});

Несколько ключевых моментов:

  • renderComponent() — рендеринг UI блока, чтение HTML-содержимого через this.props.html
  • define() — установка отображаемого имени блока в меню «Добавить блок». tExpr() используется для отложенного перевода, потому что define() выполняется на этапе загрузки модуля, и в этот момент i18n ещё не инициализирован
  • registerFlow() — добавление панели конфигурации. uiSchema определяет форму через JSON Schema (синтаксис см. в UI Schema), handler записывает значения, заполненные пользователем, в ctx.model.props, а renderComponent() их читает

Шаг 3: добавить файлы локализации

Отредактируйте файлы перевода в src/locale/ плагина, добавьте переводы для всех ключей, использованных в tExpr():

// src/locale/zh-CN.json
{
  "Simple block": "简单区块",
  "Simple Block Flow": "简单区块配置",
  "Edit HTML Content": "编辑 HTML 内容",
  "HTML Content": "HTML 内容"
}
// src/locale/en-US.json
{
  "Simple block": "Simple block",
  "Simple Block Flow": "Simple Block Flow",
  "Edit HTML Content": "Edit HTML Content",
  "HTML Content": "HTML Content"
}
Внимание

При первом добавлении файла языка нужно перезапустить приложение, чтобы он вступил в силу.

О формате файлов перевода и других способах использования tExpr() подробнее см. в i18n Интернационализация.

Шаг 4: зарегистрировать в плагине

Отредактируйте src/client-v2/plugin.tsx, через registerModelLoaders подгружайте модель по требованию:

// src/client-v2/plugin.tsx
import { Plugin } from '@nocobase/client-v2';

export class PluginSimpleBlockClient extends Plugin {
  async load() {
    this.flowEngine.registerModelLoaders({
      SimpleBlockModel: {
        // 按需加载,首次用到时才加载模块
        loader: () => import('./models/SimpleBlockModel'),
      },
    });
  }
}

export default PluginSimpleBlockClient;

registerModelLoaders использует динамический импорт — код модели загружается только при первом обращении. Это рекомендуемый способ регистрации.

Шаг 5: включить плагин

yarn pm enable @my-project/plugin-simple-block

После включения создайте новую страницу, нажмите «Добавить блок» — Вы увидите «Simple block». После добавления нажмите кнопку настройки блока, чтобы редактировать HTML-содержимое.

Полный исходный код

Резюме

Возможности, использованные в этом примере:

ВозможностьИспользованиеДокументация
Рендеринг блокаBlockModel + renderComponent()FlowEngine → Расширение блоков
Регистрация в менюdefine({ label })Обзор FlowEngine
Панель конфигурацииregisterFlow() + uiSchemaОбзор FlowEngine
Регистрация моделиregisterModelLoaders (ленивая загрузка)Plugin (Плагин)
Отложенный переводtExpr()i18n Интернационализация

Связанные ссылки