1. Предпосылки
В настоящее время компания работает над библиотекой возможностей, чтобы расширить возможности будущего бизнеса компании, и ей просто нужна платформа визуального перетаскивания с низким кодом. так...
Стек технологий этого проекта: Vue3+TypeScript+Element-plus.
В этой статье будут представлены основные идеи реализации функций платформы.Подробности можно найти на gitee.Адрес онлайн-доступа к платформе:Vue3-Visual-Editor, кодовый адрес:gitee.
2. Как он выглядит и какие у него функции
Структура каталогов
├─public
└─src
├─assets 静态资源
│ ├─images
│ └─styles
├─data mock数据
├─packages
| ├─components 组件列表
│ | ├─block-resize - 拖拽改变尺寸组件
│ │ ├─dropdown - 右键下拉菜单组件
│ │ ├─import-export-dialog - 数据导入导出弹窗组件
│ │ ├─number-range - 数字范围组件
│ │ ├─table-prop-editor - 属性添加组件
│ │ └─visual-editor-block - 画布中展示的组件
│ ├─plugins
│ │ └─command - 注册头部操作功能
│ | ├─Command.plugin.ts - 命令注册基础函数
│ | └─VisualCommand.ts - 头部功能命令注册
│ ├─utils - 工具函数
| | └─event.ts - 发布订阅工具函数
| ├─layout - 工具函数
| | ├─visual-editor-content - 画布容器
│ │ ├─visual-editor-header - 头部操作区容器
│ │ ├─visual-editor-menu - 左侧组件列表容器
│ │ └─visual-editor-props - 右侧属性管理容器
| └─Index.tsx - 容器包裹层
├─main.ts - 入口
└─App.vue
Основная функция
- Перетащите компоненты в область холста.
- Состояние выбранного компонента холста, положение перетаскивания и изменение ширины и высоты
- Обнаружение обметывания линии маркировки
- Функция отмены повтора
- Функции импорта и экспорта
- Верх, низ, удалить, очистить функции
- Клавиши быстрого доступа к функциональным командам, поддержка одиночного и множественного выбора
- Щелкните правой кнопкой мыши компонент на холсте, чтобы отобразить элемент действия.
- Добавление свойств и полей привязки к компонентам на холсте
- Настройте поведение компонента с помощью слотов с заданной областью действия на основе идентификатора компонента.
3. Концепция дизайна и взаимодействие с данными
на основеJSON Schema, легко использовать. Основная идея заключается в том, что отображение представления управления данными и все рабочие функции по существу обрабатывают данные.
4. Разборка функций, анализ и реализация
Готов к работе
- App.vue
export default defineComponent({
name: "App",
data() {
return {
// 数据中心,展示就靠它
jsonData: {
container: {
width: 1000,
height: 1000
},
blocks: []
},
// 配置数据
config: VisualConfig,
// 绑定的数据
formData: {},
// 自定义属性
customProps: {}
};
}
});
</script>
проиллюстрировать:
- jsonData — это дата-центр всего проекта и основные данные, последующие операции по изменению данных — это их изменение. Дадим ему более смысловое имя
dataModel.- config — это зарегистрированный компонент меню.
- В проекте используется множество публикаций и подписок, включая регистрацию функции заголовка, а регистрация левого компонента реализована с помощью функции публикации и подписки.
Ниже приводится официальное введение в функциональные идеи, и вы однажды узнаете подробную реализацию кода.
Перетащите компонент меню в область холста.
основной:dragable,dragstart、dragend(используется в текущем компоненте перетаскивания),dragenter、dragover、dragleave、drop(используется на холсте)
Идеи:
- Компонент пресс-меню, холст addEventListener
dragenter,dragover,dragleave,dropЭти события будут запускать соответствующие функции при перетаскивании компонента на холст.- Компонент перетаскивается на холст и вызывается
createNewBlockСоздайте компонент и поместите его в блоки модели данных, тогда на холсте появится компонент.
Состояние выбранного компонента холста, положение перетаскивания и изменение ширины и высоты
- Компонент холста выбран, т.е.
mousedownПри установке данных компонентаfocusСвойство имеет значение true, чтобы добавить выбранный стиль.- Измените положение перетаскивания, то есть измените левое и верхнее значения данных компонента
- Измените ширину и высоту, перетащите, чтобы изменить ширину и высоту, обновить значения ширины и высоты
Обнаружение обметывания линии маркировки
Идеи:
Запишите и сохраните информацию о верхнем, нижнем, левом, правом и среднем положении всех компонентов на холсте.Во время процесса перетаскивания компонента числовое значение сравнивается, и отображается строка идентификации, если оно меньше 5.
Функция отмены повтора
Идеи:
commandsСохраняется слой собственной инкапсуляции, эквивалентный функции инициализации, которая выполняется при вызове соответствующего метода регистрации. В частности: выполнитьredoметод, будетredo,audoСохранитьqueueсередина.- Зарегистрируйте функции отмены и повтора, зарегистрированные функции будут сохранены в
queue, когда undo и redo выполняются за один проход, вызывается соответствующий метод.- Полный объект регистрации, включая имя, хранится в
commandArrayсередина.
const state = reactive({
// 游标,控制执行queue中的哪一项
current: -1,
// 撤回重做的方法都存在queue中
queue: [] as CommandExecute[], // [{undo, redo}, {deleteUndo, deleteRedo}, {dragUndo, dragRedo} ...]
// 注册的命令对应的撤回重做方法都存在这里
commands: {} as Record<string, (...args: any[]) => void>, // {undo:()=>{redo()}, redo:()=>{redo()}, delete:()=> {redo()}, drag:()=> {redo()}, ...}
// 注册的完整对象集合
commandArray: [] as Command[], [{name: 'xx', keywords: "", followQueue: false, execute: () => {redo, undo}}]
// 移除事件
destroyList: [] as ((() => void | undefined))[], removeEventListener
})
// 注册函数
const register = (command: Command) => {
// 保存注册的对象
state.commandArray.push(command);
// 根据名称构建注册对象,并保存,等到调用的时候执行内部代码
state.commands[command.name] = (...args) => {
// 执行redo
const { undo, redo } = command.execute(...args);
redo();
// 如果需要保存到queue中,则进行保存,游标加1
if (command.followQueue) {
let { queue, current } = state;
if (queue.length > 0) {
queue = queue.slice(0, current + 1); // 1 => 2 => 3 => 4 => 3 => 5, 4不会保留
state.queue = queue;
}
queue.push({ undo, redo })
state.current = current + 1;
}
}
// 调用注册对象的init方法
command.init && command.init();
}
Функции импорта и экспорта
идеи
- Импортируйте, назначьте импортированный json на
jsonData, данные изменяются, и представление будет отображаться соответствующим образом.- Экспортировать, то есть экспортировать данные jsonData.
Верх, низ, удалить, очистить функции
идеи
- Верх и низ означает изменение веса текущего компонента, повышение его приоритета и визуализацию со стилем.
- Ядром функций удаления и очистки является изменение данных jsonData. Функция удаления заключается в обходе jsonData для удаления соответствующих объектов данных компонента. Чтобы очистить его, вы можете очистить данные непосредственно на холсте.
Клавиши быстрого доступа к функциональным командам, поддержка одиночного и множественного выбора
Идеи:
Клавиша быстрого доступа к функциональной команде используется при регистрации команды (например, при регистрации таких функций, как отмена, повтор, перетаскивание и т. д.).windowсвязыватьkeydownсобытие и определите имя сочетания клавиш для команды. когда пользователь уходитkeydownсобытие, походcommonArray, сопоставьте соответствующую команду клавиатуры и выполните метод обновления, если он соответствуетredoфункция. Множественный выбор мониторингshiftKey,судитьshiftНажата ли кнопка, если нажата, считается, что пользователь хочет сделать множественный выбор.
Щелкните правой кнопкой мыши компонент на холсте, чтобы отобразить элемент действия.
Идеи:
Щелкните правой кнопкой мыши, активируйте системный методcontextMenu, вы можете настроить компонент опции во всплывающем окне.
Добавление свойств и полей привязки к компонентам на холсте
Идеи:
Выберите компонент на холсте, и список свойств справа динамически отобразит, какие свойства необходимо настроить для текущего компонента. Конфигурация атрибута, соответствующая компоненту, определяется при инициализации зарегистрированного компонента.VisualEditorConfig.tsx.
Настройте поведение компонента с помощью слотов с заданной областью действия на основе идентификатора компонента.
Идеи:
приложение слот. определение#myBtn, Vue будетcontextДобавьте в контекст метод myBtn, функция этого метода заключается в выполнении функции рендерингаrenderFnWithContext, получить Virtual-DOM. Определите идентификатор компонента, то есть добавьтеslotName. Все настраиваемые свойства будут привязаны к компоненту, поэтому, когда пользователь выполняет действие, оно будет найдено в настраиваемых свойствах.slotNameВыполняется соответствующий метод и запускается поведение компонента.
<template #myBtn>
<el-button v-if="formData.food === 'dangao'">自定义按钮</el-button>
<el-tag v-else>自定义标签</el-tag>
</template>
data() {
return {
// 绑定的数据
formData: {},
// 自定义属性
customProps: {
myBtn: { // myBtn是组件标识,即slotName
onClick: () => {
this.$notify({ message: "执行动作" });
}
},
mySelect: {
onChange: (val: any) => {
this.$notify({ message: `下拉框发生变化,${val}` });
}
}
}
};
}
5. Резюме
Вышеупомянутые реализации являются общими функциями, и есть много отличных функций, которые можно добавить, например:
- Добавить конфигурацию события
- Перетащите несколько компонентов, чтобы объединить и разделить их.
- Скопируйте и вставьте выбранный компонент на холст
- Вставить изображение
- ...
Когда у меня будет время в будущем, я продолжу улучшать связанные функции, чтобы сделать их лучше и универсальнее.