1. The background


The company is currently working on a library of capabilities to power its future business and needs a low-code visual drag and drop platform. So…

The stack is Vue3+TypeScript+ element-plus

This article will introduce the main functions of the platform implementation ideas, details please go to Gitee, platform online access address: vue3-Visual -Editor, code address: gitee.

2. What it looks like and what it does


The directory structure

├ ─ public └ ─ SRC ├ ─ assets static resource │ ├ ─ images │ └ ─ styles ├ ─ data mock data ├ ─ packages | ├ ─ components component list │ | ├ ─ block - resize - │ │ ├─ Heavy Exercises - Heavy Exercises - Heavy Exercises - Heavy Exercises - Heavy Exercises - Heavy Exercises - Heavy Exercises - Heavy Exercises - Heavy Exercises - Heavy Exercises - Heavy Exercises - Heavy Exercises - Heavy Exercises - Heavy Exercises - Heavy Exercises - Heavy Exercises - Heavy Exercises - Heavy Exercises - Heavy Exercises - Heavy Exercises - Heavy Exercises - Heavy Exercises - Heavy Exercises - Heavy Exercises - Heavy Exercises - Heavy Exercises - Heavy Exercises - Heavy Exercises - Heavy Exercises - Heavy Exercises - Heavy Exercises - Heavy Exercises - Heavy Exercises ├ ─ table - prop - editor - attributes add components │ │ └ ─ visual - editor - block - the canvas display component │ ├ ─ plugins │ │ └ ─ the command - registered head operation function │ | ├ ─ Command. The plugin. Ts - based function Command register │ | └ ─ VisualCommand. Ts - head function Command register │ ├ ─ utils - tools function | | └ ─ event. Ts - release subscription tool function | ├ ─ layout - Tool function | | ├ ─ visual - editor - the content - the canvas container │ │ ├ ─ visual - editor - the header - head operation area container │ │ ├ ─ visual - editor - menu - on the left side of the component list container │ │ └ ─ visual - editor - props - on the right side of property management container | └ ─ Index. The TSX - wrapper layer ├ ─ main. Ts - entry └ ─ App. VueCopy the code

The main function

  • Drag and drop components into the canvas area
  • Canvas component selected, drag position and change width and height
  • Marking line edge detection
  • Undo the redo function
  • Import/Export function
  • Top, bottom, delete, empty function
  • Function Command shortcut keys, supporting single or multiple options
  • Right-click the component on the canvas to display action items
  • Add properties, bind fields to the component in the canvas
  • Customize component behavior through scope slots based on component identity

3. Design concept and data interaction


Based on theJSON SchemaEasy to use. The central idea is that the data control view shows that all operational functions are essentially manipulating data.

4. Functional disassembly, analysis and implementation


The preparatory work

  • App.vue
export default defineComponent({
  name: "App".data() {
    return {
      // Data center, display depends on it
      jsonData: {
        container: {
          width: 1000.height: 1000
        },
        blocks: []},// Configure data
      config: VisualConfig,
      // Bind data
      formData: {},
      // Custom attributes
      customProps: {}}; }}); </script>Copy the code

Description:

  1. JsonData is the data center of the whole project and is the core data, which is changed by various changes in subsequent operations. Let’s give him a more semantic namedataModel.
  2. Config is the registered menu component.
  3. The project uses a lot of publish and subscribe, including the header function registration, the left component registration is realized by using publish and subscribe function.

The following formal start functional ideas, detailed implementation of a stroke of the code will know.

Drag and drop menu components into the canvas area

Core: Dragable, Dragstart, Dragend (for the current drag component), Dragenter, dragover, Dragleave, drop (for the canvas)

Ideas:

  1. Click on the component in the menu to give the canvas addEventListenerdragenter,dragover,dragleave,dropThese events, when the component is dragged onto the canvas, trigger the corresponding function.
  2. Drag the component onto the canvas and callcreateNewBlockCreate a component and place it in dataModel blocks. The canvas now has a component.

Canvas component selected, drag position and change width and height

  1. The canvas component is selected, that ismousedownTo set the component datafocusProperty to true, add the selected style.
  2. Change the drag position, that is, change the left and top values of the component data
  3. Change width and height, drag and drop to change width and height

Marking line edge detection

Record and save the information about the middle position of all components in the canvas. In the process of dragging and dropping components, compare the values. If the value is less than 5, the identification line will be displayed.

Undo the redo function

Ideas:

  1. commandsSave is its own encapsulation of a layer, equivalent to the initialization function, the function is called when the corresponding registration method is executed. Specific done: implementationredoMethods,Redo, audoSave toqueueIn the.
  2. Register undo and redo functions, registered functions will be saved toqueueWhen undo and redo are performed once, the corresponding methods are called.
  3. The complete register object, including name, is stored incommandArrayIn the.
const state = reactive({
    // the cursor controls which item in the queue is executed
    current: -1.// Undo redo methods are stored in the queue
    queue: [] as CommandExecute[], // [{undo, redo}, {deleteUndo, deleteRedo}, {dragUndo, dragRedo} ...]
    // The undo redo methods for the registered commands are stored here
    commands: {} as Record<string, (. args: any[]) = > void>, // {undo:()=>{redo()}, redo:()=>{redo()}, delete:()=> {redo()}, drag:()=> {redo()}, ... }
    // The complete collection of registered objects
    commandArray: [] as Command[],  [{name: 'xx'.keywords: "".followQueue: false.execute: () = > {redo, undo}}]
    // Remove the event
    destroyList: [] as ((() = > void | undefined))[],  removeEventListener
})
// Register the function
const register = (command: Command) = > {
    // Save the registered object
    state.commandArray.push(command);
    // Build the registered object by name and save it until it is called to execute the internal code
    state.commands[command.name] = (. args) = > {
        / / redo
        const{ undo, redo } = command.execute(... args); redo();// If you want to save to queue, save it and increment the cursor by 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 is not reserved
                state.queue = queue;
            }
            queue.push({ undo, redo })
            state.current = current + 1; }}// Call the init method of the registered object
    command.init && command.init();
}
Copy the code

Import/Export function

Train of thought

  1. Import, which assigns the imported JSON tojsonDataThe data changes and the view is rendered accordingly.
  2. Export, that is, export jsonData data.

Top, bottom, delete, empty function

Train of thought

  1. Top and bottom is to change the weight of the current component, increase its priority, and match the style to render.
  2. The core of the deletion and clearing function is to modify jsonData data. The deletion function is to traverse jsonData to delete the corresponding component data objects. If the deletion is cleared, the data in the canvas can be directly cleared.

Function Command shortcut keys, supporting single or multiple options

Function Command shortcut keys are used to bind the KeyDown event to window and define the name of the command shortcut key when registering a command (for example, registering an unregister, redo, drag, delete, etc.). When the user initiates a keyDown event, the commonArray is iterated, the corresponding keyboard command is matched, and the redo function is executed. Multi-select monitors shiftKey to determine whether the Shift key is pressed, and if it is, the user is expected to select multiple.

Right-click the component on the canvas to display action items

Right click, trigger system method contextMenu, then popup custom option component can be.

Add properties, bind fields to the component in the canvas

If you select a component in the canvas, the property list on the right side will dynamically render the properties that the current component needs to configure. The property configuration for the component is defined when the registered component is initialized, as described in VisualEditorConfig.tsx.

Customize component behavior through scope slots based on component identity

Ideas: Slot application. Define #myBtn, and Vue will add a myBtn method to the context, which executes the render function renderFnWithContext to get the Vitual-DOM. Define a component identity by adding a slotName. The custom properties are all bound to the component, so when the user performs an operation, the slotName method is found in the custom property and executed, and the component action is triggered.

<template #myBtn>
  <el-button v-if="formData.food === 'dangao'">Custom button</el-button>
  <el-tag v-else>Custom labels</el-tag>
</template>
Copy the code
data() {
  return {
    // Bind data
    formData: {},
    // Custom attributes
    customProps: {
      myBtn: { // myBtn is the component identifier (slotName)
        onClick: () = > {
          this.$notify({ message: "Perform the action."}); }},mySelect: {
        onChange: (val: any) = > {
          this.$notify({ message: 'The drop-down box changes,${val}`}); }}}}; }Copy the code

5. Summary


The above implementation is common functions, there are many excellent features can be added, such as:

  • Adding event Configuration
  • Drag and drop boxes to select multiple components to combine or split
  • Copy and paste a selected component on the canvas
  • Insert the picture
  • .

Later, I will continue to improve relevant functions to make it more useful and versatile.

6. Reference materials


  • resct-visual-editor
  • Technical points of visual drag and drop component library
  • ref-line