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.
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.
Rare Earth Juejin Tech Community
Juejin, a tech community that helps developers grow.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.