Frontend Development 10 min read

Implementing Customizable Home Page Module Cards with Vue 3 and vue-draggable-next

This guide explains how to use Vue 3 with the vue-draggable-next plugin to create customizable, draggable home‑page module cards, covering technology selection, data structures, component rendering, drag‑handle configuration, and advanced customization options.

Rare Earth Juejin Tech Community
Rare Earth Juejin Tech Community
Rare Earth Juejin Tech Community
Implementing Customizable Home Page Module Cards with Vue 3 and vue-draggable-next

Requirement Overview

The requirement is to allow different logged‑in users to customize the home page module cards, i.e., add and drag‑drop dashboard modules.

Technology Selection

Native JavaScript supports drag‑and‑drop via the draggable="true" attribute, but it lacks many features, so a mature third‑party library is preferred.

Our main project uses Vue 3; after comparison we chose the vue-draggable-next plugin, which has about 30 k weekly downloads, indicating reliability.

Installation instructions are available on npm and Chinese documentation sites.

Implementation Approach

Requirement and Technical Analysis

We need group drag‑and‑drop across three columns (A, B, C). The official example shows multiple draggable tags with the same group name.

Implementation Plan

Framework Implementation

First import the component:

<script lang="ts" setup>
import { VueDraggableNext } from 'vue-draggable-next'
// ...
</script>

Define an array to store the module data:

<script lang="ts" setup>
  import { VueDraggableNext } from 'vue-draggable-next'
  const moduleList = ref([
    {
      "columnIndex": 1,
      "moduleDetail": [
        {"moduleCode": "deviation", "moduleName": "控制失调空间"},
        {"moduleCode": "meeting_pending", "moduleName": "会议待办"},
        {"moduleCode": "abnormal_events", "moduleName": "异常事件"},
        {"moduleCode": "audit_matters", "moduleName": "事项审批"}
      ]
    },
    {
      "columnIndex": 2,
      "moduleDetail": [
        {"moduleCode": "air_conditioning_terminal", "moduleName": "空调末端"}
      ]
    },
    {
      "columnIndex": 3,
      "moduleDetail": [
        {"moduleCode": "run_broadcast", "moduleName": "运行播报"},
        {"moduleCode": "my_schedule", "moduleName": "我的日程"},
        {"moduleCode": "cold_station", "moduleName": "冷站"}
      ]
    }
  ])
</script>

Render the three columns with a v‑for loop:

<div v-for="moduleColumn in moduleList" :key="moduleColumn.columnIndex" class="box">
  <VueDraggableNext :list="moduleColumn.moduleDetail" group="column">
    <div v-for="(item, index) in moduleColumn.moduleDetail" :key="item.moduleCode" class="drag-item">
</div>
  </VueDraggableNext>
</div>

Using the same group="column" makes modules draggable between the three columns.

Drag Handle Settings

To restrict dragging to a specific handle, use the handle prop, e.g., :handle=".move" .

<VueDraggableNext :list="moduleColumn.moduleDetail" handle=".move" group="column">
  <div class="drag-item">
    <div class="move">Drag Area</div>
</div>
</VueDraggableNext>

Data Add/Remove/Update

When the list is modified (e.g., via API), the moduleList updates automatically after drag‑and‑drop, so no extra handling is required.

How to Dynamically Render Components

Import all possible module components and create a lookup array:

import MeetingPending from '../components/meetingPending.vue'
import AbnormalEvents from '../components/abnormalEvents/index.vue'
import MySchedule from '../components/mySchedule.vue'
import TransactionApproval from '../components/transactionApproval.vue'
import RunningBroadcast from '../components/runningBroadcast.vue'
import CodeSite from '../components/codeSite/index.vue'
import MismatchSpace from '../components/mismatchSpace/index.vue'
import AirDevice from '../components/airDevice/index.vue'

export const allModuleList = [
  { moduleCode: 'meeting_pending', label: '会议待办', component: MeetingPending },
  { moduleCode: 'my_schedule', label: '我的日程', component: MySchedule },
  { moduleCode: 'audit_matters', label: '事项审批', component: TransactionApproval },
  { moduleCode: 'abnormal_events', label: '异常事件', component: AbnormalEvents },
  { moduleCode: 'deviation', label: '控制失调空间', component: MismatchSpace },
  { moduleCode: 'run_broadcast', label: '运行播报', component: RunningBroadcast },
  { moduleCode: 'cold_station', label: '冷站', component: CodeSite },
  { moduleCode: 'air_conditioning_terminal', label: '空调末端', component: AirDevice }
]

Then render the appropriate component based on moduleCode :

<VueDraggableNext :list="moduleColumn.moduleDetail" handle=".move" group="column">
  <div v-for="(item, index) in moduleColumn.moduleDetail" :key="item.moduleCode" class="drag-item">
    <div class="move">Drag Area</div>
    <component :is="getComponentsByCode(item.moduleCode)"></component>
  </div>
</VueDraggableNext>

More Customization Requirements

The component offers many additional props such as group , sort , delay , touchStartThreshold , disabled , animation , filter , draggable , ghost-class , chosen-class , drag-class , force-fallback , fallback-class , fallback-on-body , fallback-tolerance , scroll , scroll-fn , scroll-sensitivity , and scroll-speed to achieve complex behaviors.

Conclusion

For further reading, see the related article on module anchor positioning and flashing prompts.

frontendjavascriptVueDrag and Dropvue-draggable-next
Rare Earth Juejin Tech Community
Written by

Rare Earth Juejin Tech Community

Juejin, a tech community that helps developers grow.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.