Разработать фреймворк визуального построения dooringx-lib с нуля

GitHub визуализация данных внешний фреймворк
Разработать фреймворк визуального построения dooringx-lib с нуля

демонстрационный адрес dooringx:платформа визуализации dooringx
Примечание: ⚠️Эта статья является первой подписанной статьей сообщества Nuggets, и её перепечатка без разрешения запрещена.

Визуальный редактор запущен в прошлом годуH5-dooringПрошел год, в течение которого многие энтузиасты сети и боссы выдвинули множество ценных предложений, и мы также шаг за шагом реализуем их.Ниже приведены некоторые типичные требования к платформе визуализации с низким кодом:

  • Возможность вывода кода(то есть функция загрузки исходного кода)
  • взаимодействие компонентов(То есть общий скачок ссылки, всплывающее окно взаимодействие, пользовательские события и т. Д.)
  • Управление источниками данных(То есть разные страницы, созданные пользователями, имеют возможность обмениваться данными, и разные компоненты также имеют возможность обмениваться данными)
  • магазин компонентов(то есть пользователь может самостоятельно производить компоненты, определять компоненты и получать доступ к данным компонентов)
  • возможность компоновки(т. е. пользователь может выбрать различные схемы макета для оформления страницы)
  • Интеграция общих функций(скриншоты страниц, совместное использование WeChat, возможности отладки)

Вышеупомянутые требования к мощности ужеH5-dooringЭто реализовывалось одно за другим, и соответствующие технические раздачи есть в моих предыдущих статьях. Однако, чтобы позволить большему количеству людей иметь свою собственную систему визуального построения по низкой цене, руководители нашей команды потратили много времени на исследования и осаждение, а недавно они также открыли исходный код системы визуального построения.dooringx-lib, мы можем легко сделать визуальный редактор на его основе, не рассматривая внутренние детали реализации.Далее я поделюсь с вами идеями использования и реализации этого визуального фреймворка, и большое вам спасибо.команда визуализации дверейТяжёлая работа у вас, ребята.

image.png

Базовое использование и техническая реализация каркаса визуального построения

Чтобы дать всем лучшее понимание структуры визуального построения, вот несколько наглядных примеров:

  1. antd——antd-pro

image.pngмы все знаемantdявляется популярной библиотекой интерфейсных компонентов, тогда фон управления основан на ее инкапсуляции верхнего уровня.antd-proЭто его верхнее приложение.

  1. GrapesJS——craft.js

image.png GrapesJSЭто фреймворк редактора сторонних страниц (подробнее см. в моих предыдущих статьях).Этот зарубежный фреймворк с открытым исходным кодом позволяет вам легко создать собственный редактор страниц.) ,Такcraft.jsЭто его верхняя структура приложения.

  1. dooringx-lib——dooringx

chrome-capture.gif

dooringx-libЭто визуальная структура построения, таким же образомdooringxоснован наdooringx-libвизуальный редактор.

Причина, по которой я хочу представить разницу между ними, заключается в том, что многие друзья раньше не очень ясно понимали эту концепцию.Каркас визуального построенияПосле «коннотации» мы начинаем сегодняшнее основное содержание.

1. Стек технологий

Конечно, прежде чем делиться идеями реализации фреймворка, мы должны отчитаться о себе, в плане реализации фреймворка мы пока используем знакомые.ReactЭкология, библиотека компонентов мобильного терминала, принятая командой ZhongAnzarm, который используется прикладным уровнем редактораantd, как и для других, таких кактяга,опорная линия,государственное управление,Механизм плагинаВсе это планы, разработанные нашими лидерами. Что, если выvueИли другие команды, основанные на технологическом стеке, вы также можете обратиться к идеям реализации, я думаю, это также вдохновит вас.

2. Основное использование

Прежде чем мы начнем, давайте посмотрим, как использовать этот фреймворк, нам нужно только установить и использовать его следующим образом:

npm/yarn  install dooringx-lib

В то же время мы также предоставляем базовую демонстрацию, которая удобна для всех, чтобы быстро начать работу в своих собственных проектах:

# 克隆项目
# cnpmjs
git clone https://github.com.cnpmjs.org/H5-Dooring/dooringx.git

# or
git clone https://github.com/H5-Dooring/dooringx.git


# 进入项目目录
cd dooringx

# 安装依赖
yarn install

# 启动基础示例
yarn start:example

# 启动 dooringx-lib
yarn start

# 启动 dooringx doc 文档
yarn start:doc

yarn build

demoизgithubПункты следующие:

image.png

адрес гитхаба:GitHub.com/H5-dooring/…

Поняв, как его использовать, давайте взглянем на базовую архитектуру и идеи реализации.

3.dooringx-lib инфраструктура и рабочий механизм

image.png

Картинка выше моя текущаяdooringx-libАрхитектурная диаграмма объединения архитектуры проекта в основном включает в себя большинство необходимых модулей для построения среды редактирования. Для обеспечения гибкости фреймворка мы также можем установить соответствующие функциональные компоненты по запросу, разработать собственные компоненты и т. д. Ниже приведен базовый случай импорта:

import {
    RightConfig,
    Container,
    useStoreState,
    innerContainerDragUp,
    LeftConfig,
    ContainerWrapper,
    Control,
} from 'dooringx-lib';

Мы разделяем весь фреймворк на разные модули, которые являются как независимыми, так и взаимосвязанными. Полный рабочий процесс выглядит следующим образом:

image.png

Как видно из приведенного выше рисунка, нам нужны только базовые возможности бизнес-исследований и разработок, и мы можем использоватьdooringx-libСоздание собственной строительной платформы похоже на суть любой программы:данныеилогика.

4. разработка плагинаdooringx-lib

Далее я поделюсь с вамиdooringx-libМетод разработки плагинов и конкретная реализация (как импортировать плагины, как писать компоненты, как регистрировать функции и т. д.), если вам интересно, вы также можете использовать следующие методы для практики.

4.1 Как импортировать компоненты

image.png

Мы можем видеть на картинке выше, что левая сторона — это область материала нашего компонента, которая разделена наосновные компоненты,медиа-компонент,Визуальная составляющая, их дополнения будут размещены в единомLeftRegistMapБазовая структура выглядит следующим образом:

const LeftRegistMap: LeftRegistComponentMapItem[] = [
  {
      type: 'basic', // 组件类别
      component: 'button', // 组件名称
      img: 'icon-anniu', // 组件icon
      displayName: '按钮', // 组件中文名
      urlFn: () => import('./registComponents/button'),  // 注册回调
  },
];

Левый компонент поддерживает синхронный импорт или асинхронный импорт.

Если вам нужно импортировать компоненты асинхронно, вам необходимо заполнитьurlFn, который требует возвратаpromiseФункция. Также поддерживается удаленная загрузка компонентов, еслиwebpackВы можете добавить его.

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

initComponentCache: {
  modalMask: { component: MmodalMask },  
},

4.2 Как настроить левую панель

image.png

Левая панель входящаяleftRenderListCategoryВот и все.

leftRenderListCategory: [
  {
type: 'basic',
icon: <HighlightOutlined />,
displayName: '基础组件',
  },
  {
type: 'xxc',
icon: <ContainerOutlined />,
custom: true,
customRender: <div>我是自定义渲染</div>,
  },
],

typeявляется категорией, категория, в которой отображается левый компонент, определяется этим полем.iconЭто маленький значок категории слева (как показано выше). когдаcustomзаtrue, ты можешь использоватьcustomRenderПользовательский рендеринг.

4.3 Разработка пользовательского компонента визуализации

Компонент должен экспортироватьComponentItemFactoryСгенерированный объект:

const MButton = new ComponentItemFactory(
	'button',
	'按钮',
	{
style: [
	createPannelOptions<FormMap, 'input'>('input', {
		receive: 'text', 
		label: '文字',
	}),
],
animate: [createPannelOptions<FormMap, 'animateControl'>('animateControl', {})],
actions: [createPannelOptions<FormMap, 'actionButton'>('actionButton', {})],
	},
	{
props: {
	...
	text:'x.dooring'// input配置项组件接收的初始值
},
	},
	(data, context, store, config) => {
return <ButtonTemp data={data} store={store} context={context} config={config}></ButtonTemp>;
	},
	true
);

export default MButton;

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

Третий параметр используется для настройки компонентов элемента конфигурации правой панели. Ключ — это категория правой панели, а значение — массив компонентов элемента конфигурации.

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

В этом начальном значении есть много полезных свойств. Например, fixed представляет использование фиксированного позиционирования. Это значение можно изменить в сочетании с элементами конфигурации, чтобы можно было зафиксировать и позиционировать компонент.

иcanDragПодобно команде блокировки, заблокированные элементы нельзя перетаскивать.

в начальном значенииrotateнужен объект,valueпредставляет собой угол поворота,canRotateУказывает, можно ли управлять вращением. (поддерживается с версии 0.7.0)

Пятый параметр — это функция, вы получите элемент конфигурации вreceiveсвойства (на данный момент конфигурация по умолчаниюreceive) конфигурация, такая как в приведенном выше примереreceiveдаtext, то функцияdataполучит это поле.

contextОбычно толькоpreviewиedit, используется для вынесения экологических суждений.

configВы можете получить все данные и использовать их при создании событий.

шестой параметрresizeСудить о том, можно ли выполнить масштабирование, когда оноfalse, масштабирование невозможно.

седьмой параметрneedPosition, некоторые компоненты будут перетаскиваться по умолчанию после их перемещения на основу.true, это позиция, которую нужно перетащить, дляfalseбудет использовать сам компонентtopиleftположение для размещения.

4.4 Регистрация на мероприятие

image.png

  1. Время регистрации

События можно разделить наВремя регистрацииифункция, компонент может пройтиhookспособ достижения времени регистрации:

useDynamicAddEventCenter(pr, `${pr.data.id}-init`, '初始渲染时机'); //注册名必须带id 约定!
useDynamicAddEventCenter(pr, `${pr.data.id}-click`, '点击执行时机');

useDynamicAddEventCenterПервый параметрrenderОбъект, состоящий из четырех параметров. Второй параметр — это имя времени регистрации, за которым должен следоватьidСвязано это с соглашением, иначе несколько компонентов могут вызвать конфликты имен, и легко найти время.

После регистрации времени нам нужно поместить время в соответствующее положение триггера, например, этоbuttonВремя выполнения клика помещается вonclickсередина:

<Button
    onClick={() => {
eventCenter.runEventQueue(`${pr.data.id}-click`, pr.config);
    }}
>
    x.dooring
</Button> 

Первый параметр — это зарегистрированное имя времени, а второй —renderпоследний параметр в функцииconfig

  1. регистрация функции

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

Регистрация функции должна быть введенаuseEffect, при удалении компонента требуется функция удаления! В противном случае это приведет к увеличению количества функций.

useEffect(() => {
const functionCenter = eventCenter.getFunctionCenter();
const unregist = functionCenter.register(
	`${pr.data.id}+改变文本函数`,
	async (ctx, next, config, args, _eventList, iname) => {
		const userSelect = iname.data;
		const ctxVal = changeUserValue(
			userSelect['改变文本数据源'],
			args,
			'_changeval',
			config,
			ctx
		);
		const text = ctxVal[0];
		setText(text);
		next();
	},
	[
		{
			name: '改变文本数据源',
			data: ['ctx', 'input', 'dataSource'],
			options: {
				receive: '_changeval',
				multi: false,
			},
		},
	]
);
return () => {
	unregist();
};
}, []);

Параметры и конфигурация в функции показаны в разработке функции позже.

4.5 Развитие правой панели

chrome-capture (2).gif

Чтобы разработать пользовательскую правую панель свойств, нам просто нужно настроить разработанный компонент как объект и поместить его вinitFormComponentsВот и все. Для хорошего опыта разработки необходимо определитьformMapтип:

export interface FormBaseType {
    receive?: string;
}
export interface FormInputType extends FormBaseType {
    label: string;
}
export interface FormActionButtonType {}
export interface FormAnimateControlType {}
export interface FormMap {
    input: FormInputType;
    actionButton: FormActionButtonType;
    animateControl: FormAnimateControlType;
}

formMapКлючевое имяinitFormComponentsключевое имя,formMapЗначение соответствует значению, которое должен получить компонент.

отinputкомпонент в качестве примера,FormInputTypeНа данный момент есть 2 свойства:label, receive.

Затем при разработке этого компонентаpropsполучит:

interface MInputProps {
    data: CreateOptionsRes<FormMap, 'input'>;
    current: IBlockType;
    config: UserConfig;
}

этоdataдаformMapтип, покаcurrentкомпонент, на который нажали в данный момент,configРазумеется.

Помните третий параметр в разработке компонентов слева? Это все связано:

style: [
    createPannelOptions<FormMap, 'input'>('input', {
        receive: 'text',  
        label: '文字'
    })
],

createPannelOptionsЗаполнение соответствующего компонента в дженерике этой функции даст хорошую подсказку к полученному элементу конфигурации.

Все, что вам нужно сделать в компоненте элемента конфигурации, — это получить элемент конфигурации из компонента, а затем изменить его.currentсвойства:

function MInput(props: MInputProps) {
	const option = useMemo(() => {
return props.data?.option || {};
	}, [props.data]);
	return (
<Row style={{ padding: '10px 20px' }}>
	<Col span={6} style={{ lineHeight: '30px' }}>
		{(option as any)?.label || '文字'}:
	</Col>
	<Col span={18}>
            <Input
                value={props.current.props[(option as any).receive] || ''}
                onChange={(e) => {
                        const receive = (option as any).receive;
                        const clonedata = deepCopy(store.getData());
                        const newblock = clonedata.block.map((v: IBlockType) => {
                                if (v.id === props.current.id) {
                                        v.props[receive] = e.target.value;
                                }
                                return v;
                        });
                        store.setData({ ...clonedata, block: [...newblock] });
                }}
            ></Input>
	</Col>
</Row>
	);
}

Так как легко получитьstore, поэтому данные могут быть изменены где угодно.

компонентаvalueассоциацияcurrentхарактеристики,onChangeмодифицироватьstore, что завершает двустороннюю привязку.

Примечание. Если ваш правильный компонент должен использоватьblockДругим свойствам может потребоваться определить, находится ли он во всплывающем режиме.

4.6 Настройка контекстного меню

chrome-capture (3).gif

Контекстное меню можно настроить:

// 自定义右键
const contextMenuState = config.getContextMenuState();
const unmountContextMenu = contextMenuState.unmountContextMenu;
const commander = config.getCommanderRegister();
const ContextMenu = () => {
	const handleclick = () => {
unmountContextMenu();
	};
	const forceUpdate = useState(0)[1];
	contextMenuState.forceUpdate = () => {
forceUpdate((pre) => pre + 1);
	};
	return (
<div
	style={{
            left: contextMenuState.left,
            top: contextMenuState.top,
            position: 'fixed',
            background: 'rgb(24, 23, 23)',
	}}
>
	<div
            style={{ width: '100%' }}
            onClick={() => {
                    commander.exec('redo');
                    handleclick();
            }}
        >
            <Button>自定义</Button>
	</div>
</div>
	);
};
contextMenuState.contextMenu = <ContextMenu></ContextMenu>;

получить это первымcontextMenuState,contextMenuStateEстьunmountContextMenuЯвляется ли закрыть метод меню правой кнопкой мыши. Так близко нужно вызывать после клика. В то же время вышеизложенноеleftиtopЩелчок правой кнопкой мыши. Кроме того, нам также необходимо увеличить прочную кисть в компоненте, назначить значение.forceUpdate, чтобы следовать за компонентом во время его движения.

4.7 Идеи отправки проверки формы

image.png

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

При нажатии кнопки отправки вызываются функции проверки и отправки всех компонентов, и они передаются в контекст, а затем агрегируются в объекты с помощью функции агрегации контекста и, наконец, отправляются в соответствующий бэкэнд через функцию отправки в завершить весь процесс. мы можемdooringxпопробуй этоdemo.

Другой способ — написать кнопку отправки специально, с фиксированными параметрами и некоторыми правилами, например, все формы на странице будут собираться и отправляться.

Затем мы можем использовать источник данных для автоматической отправки всего содержимого вывода формы в источник данных, а окончательная кнопка отправки имеет формат, указанный источником данных.keyИзвлечь, отправить на сервер.

Позднее планирование

На более позднем этапе мы продолжим итеративно оптимизировать функции продукта. Если у вас есть хорошие предложения, вы также можете связаться с нами в любое время. Вы также можете активно участвовать в github.issue.

Если вы заинтересованы в визуальном конструировании или low-code/zero-code, вы также можете обратиться к моим предыдущим статьям или обменяться мыслями и опытом в области комментариев.Добро пожаловать, чтобы вместе изучить настоящую фронтенд-технологию.

github: Dooringx | Быстро и эффективно создайте платформу визуального перетаскивания
Стартер:Технологическое сообщество Nuggets
команда:Группа визуализации дверей
Столбец:визуализация с низким кодом
Официальный аккаунт: Интересный интерфейс разговора

больше рекомендаций