Analysis of Key Technical Principles for a Visual Drag-and-Drop Component Library

Analysis of the Following Technical Points: Editor Custom Components Drag and Drop Deleting Components, Adjusting Layer Hierarchy Zoom In and Out Undo, Redo Component Property Settings Snapping Preview, Save Code Binding Events Binding Animations Importing PSD Mobile Mode To make this article easier to understand, I have combined the above technical points to create a visual drag-and-drop component library DEMO: GitHub project address Online preview I recommend reading this alongside the source code for better results (this DEMO uses the Vue technology stack). 1. Editor Let's first look at the overall structure of the page. The editor discussed in this section is actually the canvas in the middle. Its role is: when a component is dragged from the left component list to the canvas, the canvas needs to render this component. The implementation approach for this editor is: Use an array componentData to maintain the data in the editor. When a component is dragged to the canvas, use the push() method to add the new component data to componentData. The editor uses the v-for directive to iterate through componentData, rendering each component one by one onto the canvas (you can also use JSX syntax with the render() method instead). The core code for editor rendering is as follows: Each component's data roughly looks like this: { component: 'v-text', // Component name, needs to be pre-registered in Vue label: 'Text', // Name displayed in the left component list propValue: 'Text', // Value used by the component icon: 'el-icon-edit', // Icon displayed in the left component list animations: [], // Animation list events: {}, // Event list style: { // Component styles width: 200, height: 33, fontSize: 14, fontWeight: 500, lineHeight: '', letterSpacing: 0, textAlign: '', color: '', }, } When iterating through the componentData, the is attribute is mainly used to identify which component should actually be rendered. For example, if the component data to be rendered is { component: 'v-text' }, then will be converted to . Of course, you need to register this component in Vue beforehand. If you want to learn more about the is attribute, please check the official documentation. 2. Custom Components In principle, using third-party components is also possible, but it's recommended that you encapsulate them. Whether third-party components or custom components, each component may require different properties, so each component's data can expose a property called propValue for passing values. For example, if component a only needs one property, your propValue can be written like this: propValue: 'aaa'. If multiple properties are needed, propValue can be an object: propValue: { a: 1, b: 'text' } In this DEMO component library, I defined three components. Image component Picture: export default { props: { propValue: { type: String, require: true, }, }, } Button component VButton: {{ propValue }} export default { props: { propValue: { type: String, default: '', }, }, } Text component VText: {{ text }} import { mapState } from 'vuex' export default { props: { propValue: { type: String, }, element: { type: Object, }, }, computed: mapState([ 'editMode', ]), methods: { handleInput(e) { this.$emit('input', this.element, e.target.value) }, }, } 3. Drag and Drop From Component List to Canvas For an element to be made draggable, it must have a draggable attribute added to it. Additionally, when dragging components from the component list to the canvas, two events play a key role: The dragstart event, triggered at the beginning of the drag. It's mainly used to pass the dragged component information to the canvas. The drop event, triggered at the end of the drag. Mainly used to receive the dragged component information. Let's first look at the code for the left component list: {{ item.label }} handleDragStart(e) { e.dataTransfer.setData('index', e.target.dataset.index) } You can see that the draggable attribute is set for each component in the list. Additionally, when the dragstart event is triggered, data is transmitted using dataTransfer.setData(). Now let's look at the code for receiving data: handleDrop(e) { e.preventDefault() e.stopPropagation() const component = deepCopy(componentList[e.dataTransfer.getData('index')]) this.$store.commit('addComponent', component) } When the drop event is triggered, dataTransfer.getData() is used to receive the transmitted index data, then the corresponding compon

Apr 7, 2025 - 13:39
 0
Analysis of Key Technical Principles for a Visual Drag-and-Drop Component Library

Analysis of the Following Technical Points:

  1. Editor
  2. Custom Components
  3. Drag and Drop
  4. Deleting Components, Adjusting Layer Hierarchy
  5. Zoom In and Out
  6. Undo, Redo
  7. Component Property Settings
  8. Snapping
  9. Preview, Save Code
  10. Binding Events
  11. Binding Animations
  12. Importing PSD
  13. Mobile Mode

To make this article easier to understand, I have combined the above technical points to create a visual drag-and-drop component library DEMO:

I recommend reading this alongside the source code for better results (this DEMO uses the Vue technology stack).

1. Editor

Let's first look at the overall structure of the page.

The editor discussed in this section is actually the canvas in the middle. Its role is: when a component is dragged from the left component list to the canvas, the canvas needs to render this component.

The implementation approach for this editor is:

  1. Use an array componentData to maintain the data in the editor.
  2. When a component is dragged to the canvas, use the push() method to add the new component data to componentData.
  3. The editor uses the v-for directive to iterate through componentData, rendering each component one by one onto the canvas (you can also use JSX syntax with the render() method instead).

The core code for editor rendering is as follows:

<component
  v-for="item in componentData"
  :key="item.id"
  :is="item.component"
  :style="item.style"
  :propValue="item.propValue"
/>

Each component's data roughly looks like this:

{
    component: 'v-text', // Component name, needs to be pre-registered in Vue
    label: 'Text', // Name displayed in the left component list
    propValue: 'Text', // Value used by the component
    icon: 'el-icon-edit', // Icon displayed in the left component list
    animations: [], // Animation list
    events: {}, // Event list
    style: { // Component styles
        width: 200,
        height: 33,
        fontSize: 14,
        fontWeight: 500,
        lineHeight: '',
        letterSpacing: 0,
        textAlign: '',
        color: '',
    },
}

When iterating through the componentData, the is attribute is mainly used to identify which component should actually be rendered.

For example, if the component data to be rendered is { component: 'v-text' }, then will be converted to . Of course, you need to register this component in Vue beforehand.

If you want to learn more about the is attribute, please check the official documentation.

2. Custom Components

In principle, using third-party components is also possible, but it's recommended that you encapsulate them. Whether third-party components or custom components, each component may require different properties, so each component's data can expose a property called propValue for passing values.

For example, if component a only needs one property, your propValue can be written like this: propValue: 'aaa'. If multiple properties are needed, propValue can be an object:

propValue: {
  a: 1,
  b: 'text'
}

In this DEMO component library, I defined three components.

Image component Picture:




Button component VButton:




Text component VText:

<template>
    <textarea
        v-if="editMode == 'edit'"
        :value="propValue"
        class="text textarea"
        @input="handleInput"
        ref="v-text"
    ></textarea>
    <div v-else class="text disabled">
        <div v-for="(text, index) in propValue.split('\n')" :key="index">{{ text }}</div>
    </div>
</template>

<script>
import { mapState } from 'vuex'

export default {
    props: {
        propValue: {
            type: String,
        },
        element: {
            type: Object,
        },
    },
    computed: mapState([
        'editMode',
    ]),
    methods: {
        handleInput(e) {
            this.$emit('input', this.element, e.target.value)
        },
    },
}
</script>

3. Drag and Drop

From Component List to Canvas

For an element to be made draggable, it must have a draggable attribute added to it. Additionally, when dragging components from the component list to the canvas, two events play a key role:

  1. The dragstart event, triggered at the beginning of the drag. It's mainly used to pass the dragged component information to the canvas.
  2. The drop event, triggered at the end of the drag. Mainly used to receive the dragged component information.

Let's first look at the code for the left component list:

 @dragstart="handleDragStart" class="component-list">
   v-for="(item, index) in componentList" :key="index" class="list" draggable :data-index="index">
     :class="item.icon">
    {{ item.label }}