Introduction: vue2 drag and drop plug-in, one-to-one drag and drop, each grid has only one data. Of course, you can also drag and drop multiple (multiple is simpler). First look at the dynamic pictures in gif format,
Let’s introduce the plug-in first (I won’t introduce the plug-in, it must not be written by me, I just use it): The document I read is quite detailed.
Chinese address vue.draggable Chinese document – itxst.com
- npm download
npm install vuedraggable
- Which page should be used for import
import draggable from 'vuedraggable' // Import components: {draggable},//Registration
- The most basic and simple use (there is not a detailed introduction in it) (I only introduce one here because I feel that there are many things that we need to read the document ourselves, so I will introduce them one by one, mainly for simplicity)
<div class ="itxst"> <div class="col"> <div class="title">Group A</div> <!-- I don’t know what the <transition-group> tag is used for. I don’t see any difference whether it is used or not. ! ! Remember that only one div can be looped under the <draggable> or <transition-group> tag. Don’t write it randomly or you will get an error! ! ! You can only write a div and let it loop! v-model represents the data source (needless to say) group This is imagined as a group. Only the same groups can drag each other. animation is a transition animation . . . There are still a lot of things, but the basics are enough. If you need more, please check the introduction in the quick start of the official website. --> <draggable v-model="arr1" group="site" animation="300"> <transition-group> <div class="item" v-for="item in arr1" :key="item.id">{<!-- -->{item.name}}</div> <div class="item">0</div> </transition-group> </draggable> </div> <div class="col"> <div class="title">Group B (this group cannot be dragged into group A)</div> <draggable v-model="arr2" group="site" animation="100"> <transition-group> <div class="item" v-for="item in arr2" :key="item.id">{<!-- -->{item.name}}</div> </transition-group> </draggable> </div> </div> <script> import draggable from 'vuedraggable' export default { components: {draggable,}, data() { return { arr1: [{id: 1,name: 'name1'}, {id: 2,name: 'name2'}, {id: 3,name: 'name3'}, {id: 4,name: 'name4'} ], arr2: [], }; }, methods: {} } </script> <style> .itxst {margin: 10px;} .title {padding: 6px 12px;} .col { width: 40%; flex: 1; padding: 10px; border: solid 1px #eee; border-radius: 5px; float: left; } .col + .col {margin-left: 10px;} .item { padding: 6px 12px; margin: 0px 10px 0px 10px; border: solid 1px #eee; background-color: #f1f1f1; } .item:hover {background-color: #fdfdfd;cursor: move;} .item + .item {border-top: none;margin-top: 6px;} </style>
- There’s not much more to the basics (it just shows you how to get started. For other things, just check the official website). Let me introduce what I wrote. It is a bit more complicated (if you don’t want to hear that you can directly copy the code of other frameworks written by pure front-end demo vue2 + Element, just change it to el-). My business needs here are three data sources. Patients + Two devices (both independent), and each frame can only hold one piece of data. In this case, it is a bit troublesome to use dynamic group (written in the code). A dynamic name corresponds to a static one. And in the dynamic, you can set whether it can be dragged in or out… (If you are tired, just look at the code, please let me know if you have any shortcomings, thank you)
- Pure front-end demo, you can use it as long as the plug-in is installed
<template> <div style="display: flex;padding: 10px;"> <div class="patient" style=""> <div class="tetx_nav">Patient</div> <div class="nav"> <div class="text">To be allocated</div> <div class="oveCC"> <draggable v-model="userList" group="user" animation="300"> </transition-group> <div class="list" v-for="(item,ind) in userList" :key="ind" @click="userItem(item)" @mousedown="startDragging" @mouseup="stopDragging" @dragstart="startDragging" @dragend="stopDragging"> <div class="list_info"> <svg class="icon" aria-hidden="true"> <use v-if="item.xb" xlink:href="#icon-portrait"></use> <use v-else xlink:href="#icon--man-"></use> </svg> <span class="list_name">{<!-- -->{item.name}}</span> <span>{<!-- -->{item.xb?'Female':'Male'}}</span> <span>{<!-- -->{item.age}} years old</span> </div> <div class="list_time"> <span>{<!-- -->{item.time}}</span> <span>Start monitoring</span> </div> </div> </transition-group> </draggable> </div> </div> </div> <div class="info"> <div class="tetx_nav"> Enrolled: 0 | Enrolled: 0 | Graduated: 0 </div> <div class="nav"> <div class="nav_wrap"> <div class="dra_box" v-for="(it,ind) in allList" :key="ind"> <div class="box_text">{<!-- -->{ind}}beds</div> <div class="box_div"> <div class="notNull dox_sty" :class="{ 'glow-effect': isDraggingUser & amp; & amp;it.userObj.length==0 }"> <div class="list_dra"> <draggable v-model="it.userObj" :group="it.userB" @add="userAdd(it,ind)" @end="userEnd(it,ind)" animation="300"> <div style="width: 100%;height: 80px;" v-if="it.userObj.length==0"> <span v-if="!isDraggingUser">Please assign patients to beds</span> </div> <div v-else :class="it.userObj.length==1?'':'forbid'" v-for="(item,index) in it.userObj" :key="index" class="list" @mousedown="startDragging" @mouseup="stopDragging" @dragstart="startDragging" @dragend="stopDragging"> <div class="list_info"> <svg class="icon" aria-hidden="true"> <use v-if="item.xb" xlink:href="#icon-portrait"></use> <use v-else xlink:href="#icon--man-"></use> </svg> <span class="list_name">{<!-- -->{item.name}}</span> <span>{<!-- -->{item.xb?'Female':'Male'}}</span> <span>{<!-- -->{item.age}} years old</span> </div> <div class="list_time"> <span>{<!-- -->{item.time}}</span> <span>Start monitoring</span> </div> </div> </draggable> </div> </div> <div class="device_div dox_sty" :class="{ 'glow-effect': isDraggingDevjhy & amp; & amp;it.devJhy.length==0 }"> <draggable v-model="it.devJhy" :group="it.devJhyB" @add="devJhyAdd(it,ind)" @end="devJhyEnd(it,ind)" animation="300"> <div style="width: 100%;height: 80px;" v-if="it.devJhy.length==0"><span v-if="!isDraggingDevjhy">Monitor</span></div> <div v-else class="deviceCode" v-for="(item,index) in it.devJhy" :key="item.id" @mousedown="startDevjhy" @mouseup="stopDevjhy" @dragstart="startDevjhy" @dragend="stopDevjhy"> <div class="dev_text"> {<!-- -->{item.text}} </div> <div class="dev_id"> {<!-- -->{item.id}} </div> </div> </draggable> </div> <div class="device_div dox_sty" :class="{ 'glow-effect': isDraggingDevhxj & amp; & amp;it.devHxj.length==0 }"> <draggable v-model="it.devHxj" :group="it.devHxjB" @add="devHxjAdd(it,ind)" @end="devHxjEnd(it,ind)" animation="300"> <div style="width: 100%;height: 80px;" v-if="it.devHxj.length==0"><span v-if="!isDraggingDevhxj">Ventilator</span></div> <div v-else class="deviceCode" v-for="(item,index) in it.devHxj" :key="item.id" @mousedown="startDevhxj" @mouseup="stopDevhxj" @dragstart="startDevhxj" @dragend="stopDevhxj"> <div class="dev_text"> {<!-- -->{item.text}} </div> <div class="dev_id"> {<!-- -->{item.id}} </div> </div> </draggable> </div> </div> </div> </div> </div> </div> <div class="device"> <div class="tetx_nav"> \t\t\t\tequipment </div> <div class="nav"> <div class="nav_tab" style="padding-right: 5px;"> <div class="text">Monitor</div> <div class="oveCC"> <draggable v-model="jhydev" group="devJhy" animation="300" @start="startDevjhy" @unchoose="stopDevjhy"> <div v-if="jhydev.length===0" style="width: 100px;height: 100px;"> <el-empty description="No device yet"></el-empty> </div> <div v-else class="deviceCode" v-for="(item,ind) in jhydev" :key="item.id"> <div class="dev_text"> {<!-- -->{item.text}} </div> <div class="dev_id"> {<!-- -->{item.id}} </div> </div> </draggable> </div> </div> <div class="nav_tab" style="padding-left: 5px;"> <div class="text">Ventilator{<!-- -->{hxjdev.length}}</div> <div class="oveCC"> <draggable v-model="hxjdev" group="devHxj" animation="300" @start="startDevhxj" @unchoose="stopDevhxj"> <div v-if="hxjdev.length===0" style="width: 100px;height: 100px;"> <el-empty description="No device yet"></el-empty> </div> <div v-else class="deviceCode" v-for="(item,ind) in hxjdev" :key="item.id"> <div class="dev_text"> {<!-- -->{item.text}} </div> <div class="dev_id"> {<!-- -->{item.id}} </div> </div> </draggable> </div> </div> </div> </div> <div class="details"> <div class="tetx_nav"> patient information </div> <div class="nav"> <div style="display: flex;line-height: 40px;"> <div class="nav_left">Name:</div> <div style="flex: 1;">{<!-- -->{userInfo.name!=''?userInfo.name:'-'}}</div> </div> <div style="display: flex;line-height: 40px;"> <div class="nav_left">Gender:</div> <div style="flex: 1;">{<!-- -->{userInfo.xb===''?'-':userInfo.xb==1?'Male':'Female'}}< /div> </div> <div style="display: flex;line-height: 40px;"> <div class="nav_left">Age:</div> <div style="flex: 1;">{<!-- -->{userInfo.age!=''?userInfo.age:'-'}}</div> </div> <div style="display: flex;line-height: 40px;"> <div class="nav_left">Department:</div> <div style="flex: 1;">-</div> </div> <div style="display: flex;line-height: 40px;"> <div class="nav_left">Ward:</div> <div style="flex: 1;">-</div> </div> <div style="display: flex;line-height: 40px;"> <div class="nav_left">Bed number:</div> <div style="flex: 1;">-</div> </div> <div style="display: flex;line-height: 40px;"> <div class="nav_left">Hospital number:</div> <div style="flex: 1;">-</div> </div> <div style="display: flex;line-height: 40px;"> <div class="nav_left">Responsible doctor:</div> <div style="flex: 1;">-</div> </div> <div style="display: flex;line-height: 40px;"> <div class="nav_left">Diagnostic information:</div> <div style="flex: 1;">-</div> </div> <div style="display: flex;line-height: 40px;"> <div class="nav_left">Care Level:</div> <div style="flex: 1;">-</div> </div> <div style="display: flex;line-height: 40px;"> <div class="nav_left">Condition level:</div> <div style="flex: 1;">-</div> </div> <div style="display: flex;line-height: 40px;"> <div class="nav_left">Ventilation mode:</div> <div style="flex: 1;">-</div> </div> <div style="display: flex;line-height: 40px;"> <div class="nav_left">Pacing mode:</div> <div style="flex: 1;">-</div> </div> <div style="display: flex;line-height: 40px;"> <div class="nav_left">Equipment number (monitor):</div> <div style="flex: 1;">-</div> </div> <div style="display: flex;line-height: 40px;"> <div class="nav_left">Equipment number (ventilator):</div> <div style="flex: 1;">-</div> </div> <div style="display: flex;line-height: 40px;"> <div class="nav_left">Guardianship status:</div> <div style="flex: 1;">-</div> </div> <div style="display: flex;line-height: 40px;"> <div class="nav_left">Monitoring start time:</div> <div style="flex: 1;">-</div> </div> <div style="display: flex;line-height: 40px;"> <div class="nav_left">Monitoring duration:</div> <div style="flex: 1;">-</div> </div> </div> </div> </div> </template> <script> import draggable from 'vuedraggable' export default { components: { draggable }, data() { return { isDraggingUser: false, isDraggingDevjhy: false, isDraggingDevhxj: false, userInfo: { name: '', xb: '', age: '', time: '', }, userList: [{ name: 'Zhang San', xb: 1, age: 75, time: '2023-10-13 10:44:30' }, { name: '李思', xb: 0, age: 65, time: '2023-10-13 10:44:30' }, { name: '王*马', xb: 1, age: 45, time: '2023-10-13 10:44:30' }, { name: 'Madman', xb: 0, age: 58, time: '2023-10-13 10:44:30' }], jhydev: [{ id: 'MB02A91006', text: '1' }, { id: 'MB02A91007', text: '2' }, { id: 'ME02B22032', text: '3' }, { id: 'ME02B22033', text: '4' }, { id: 'ME02B22035', text: '5' }, { id: 'ME02B22036', text: '6' }, { id: 'ME26B19026', text: '7' }, ], hxjdev: [{ id: 'VE03B1A001', text: '-' }, { id: 'VE03B1A002', text: '-' }, { id: 'VE03B1A003', text: '-' }, { id: 'VE03B1A004', text: '-' }], allList: [], } }, mounted() { for (let i = 0; i < 40; i + + ) { this.allList.push({ userObj: [], devJhy: [], devHxj: [], userB: { name: "user", pull: false, put: true, }, devJhyB: { name: "devJhy", pull: true, //Can it be dragged out? put: true, //Can it be dragged in? }, devHxjB: { name: "devHxj", pull: true, //Drag out put: true, //Drag in }, }) } }, methods: { //Patient information details userItem(item) { this.userInfo = item }, //Add new data -- patients userAdd(data, i) { this.$set(this.allList[i].userB, 'pull', true) this.$set(this.allList[i].userB, 'put', false) }, // End of movement -- patient userEnd(data, i) { console.log(JSON.parse(JSON.stringify(this.allList)), JSON.parse(JSON.stringify(this.allList[0]))) if (data.userObj.length == 0) { this.$set(this.allList[i].userB, 'pull', false) this.$set(this.allList[i].userB, 'put', true) } else { this.$set(this.allList[i].userB, 'pull', true) this.$set(this.allList[i].userB, 'put', false) } }, // Add new data -- ventilator devHxjAdd(data, i) { this.$set(this.allList[i].devHxjB, 'pull', true) this.$set(this.allList[i].devHxjB, 'put', false) }, // End of movement -- ventilator devHxjEnd(data, i) { if (data.devHxj.length == 0) { this.$set(this.allList[i].devHxjB, 'pull', false) this.$set(this.allList[i].devHxjB, 'put', true) } else { this.$set(this.allList[i].devHxjB, 'pull', true) this.$set(this.allList[i].devHxjB, 'put', false) } }, // Add new data -- monitor devJhyAdd(data, i) { this.$set(this.allList[i].devJhyB, 'pull', true) this.$set(this.allList[i].devJhyB, 'put', false) }, // End of movement -- monitor devJhyEnd(data, i) { if (data.devJhy.length == 0) { this.$set(this.allList[i].devJhyB, 'pull', false) this.$set(this.allList[i].devJhyB, 'put', true) } else { this.$set(this.allList[i].devJhyB, 'pull', true) this.$set(this.allList[i].devJhyB, 'put', false) } }, \t\t\t \t\t\t // "---------------------------------Outer glow effect, inner text disappears startDragging() { // Event triggered when starting dragging -- patient this.isDraggingUser = true; this.isClose('user',true) }, stopDragging() { // Event of releasing mouse after selection -- patient this.isDraggingUser = false; // this.open() }, \t\t\t startDevjhy() { // Event triggered when starting dragging -- monitor this.isDraggingDevjhy = true; this.isClose('Devjhy',true) }, stopDevjhy() { // Event of releasing mouse after selection -- monitor this.isDraggingDevjhy = false; // this.open() }, \t\t\t startDevhxj() {// Event triggered when starting dragging -- ventilator this.isDraggingDevhxj = true; this.isClose('Devhxj',true) }, stopDevhxj() { // Event for releasing the mouse after selecting -- ventilator this.isDraggingDevhxj = false; // this.open() }, //Outer glow effect---------------------------------》 \t\t\t \t\t\t // Due to customization, the effect of name seems to be invalid (bug: you can drag and drop arbitrarily), so you can only disable the drag-in event. isClose(name,e){ if(name === 'user'){ this.allList.forEach(item=>{ if(item.userObj.length == 0){ item.userB.put = true }else{ item.userB.put = false } item.devJhyB.put = false item.devHxjB.put = false }) }else if(name === 'Devjhy'){ this.allList.forEach(item=>{ item.userB.put = false if(item.devJhy.length == 0){ item.devJhyB.put = true }else{ item.devJhyB.put = false } item.devHxjB.put = false }) }else if(name === 'Devhxj'){ this.allList.forEach(item=>{ item.userB.put = false item.devJhyB.put = false if(item.devHxj.length == 0){ item.devHxjB.put = true }else{ item.devHxjB.put = false } }) } }, // open(){ // this.allList.forEach(item=>{ // item.userB.put = true // item.devJhyB.put = true // item.devHxjB.put = true // }) // } \t\t\t }, } </script> <style lang="scss" scoped> .glow-effect { animation: glow 1s infinite alternate; border: 1px dashed rgba(0, 255, 0, 0.5) !important; } @keyframes glow { 0% { box-shadow: 0 0 10px rgba(0, 255, 0, 0.5); } 100% { box-shadow: 0 0 20px rgba(0, 255, 0, 0.8); } } ::-webkit-scrollbar { width: 4px; height: 4px; } ::-webkit-scrollbar-track { background-color: transparent; -webkit-border-radius: 2em; -moz-border-radius: 2em; border-radius: 2em; } ::-webkit-scrollbar-thumb { background-color: rgb(147, 147, 153, 0.5); -webkit-border-radius: 2em; -moz-border-radius: 2em; border-radius: 2em; } $customHeight: 100%; $boxHeight: calc(100vh - 100px); .tetx_nav { text-align: center; color: #333; font-size: 16px; font-weight: 600; line-height: 30px; } .patient { height: $boxHeight; width: 230px; min-width: 230px; .nav { height: $customHeight ; padding: 10px 5px; border-radius: 10px; background-image: linear-gradient(180deg, #ebf2fa, #fff); .text { color: #758491; font-family: PingFangSC-Semibold; font-size: 14px; font-weight: 600; text-align: center; } .oveCC { overflow: hidden; overflow: auto; height: 100%; .list { background: #fff; border: 1px solid #dde6ed; border-radius: 10px; height: 78px; padding: 10px; position: relative; margin-top: 5px; cursor: pointer; user-select: none; //Text cannot be selected .list_info { padding-bottom: 10px; border-bottom: #bdbdbd 1px solid; display: flex; align-items: center; font-size: 14px; color: #969696; span { margin-left: 10px; } svg { width: 30px; height: 30px; } .list_name { font-size: 16px; font-weight: 600; color: #000; } } .list_time { line-height: 25px; display: flex; align-items: center; justify-content: space-between; font-size: 12px; color: #969696; } } } } } .info { height: $boxHeight; min-width: 500px; flex: 1; padding: 0 10px; .nav { height: $customHeight; border-radius: 10px; background-color: #8f9ad5; padding: 7px; ::-webkit-scrollbar-thumb { background-color: rgb(103, 127, 213); -webkit-border-radius: 2em; -moz-border-radius: 2em; border-radius: 2em; } .nav_wrap { display: flex; flex-wrap: wrap; overflow: hidden; overflow: auto; height: 100%; .dra_box { background: #fff; border: 1px solid #dde6ed; border-radius: 8px; border-radius: 12px; float: left; height: 160px; margin: 5px; padding: 1px; user-select: none; flex: 1; min-width: 440px; .box_text { height: 36px; text-align: center; width: 100%; } .box_div { background: #fff; border-radius: 12px; padding: 10px; display: flex; justify-content: space-between; .notNull { width: 220px; min-width: 220px; .list_dra { position: relative; cursor: pointer; user-select: none; //Text cannot be selected .list_info { line-height: normal; padding-bottom: 10px; border-bottom: #bdbdbd 1px solid; display: flex; align-items: center; font-size: 14px; color: #969696; span { margin-left: 10px; } svg { width: 45px; height: 45px; } .list_name { font-size: 16px; font-weight: 600; color: #000; } } .list_time { line-height: 35px; display: flex; align-items: center; justify-content: space-between; font-size: 12px; color: #969696; } } } .device_div { width: 100px; min-width: 100px; .deviceCode { font-size: 12px; .dev_text { height: 40px; text-align: center; line-height: 40px; } .dev_id { color: #758491; height: 40px; text-align: center; line-height: 40px; } } } .dox_sty { height: 100px; line-height: 78px; color: #c6cfd7; font-size: 16px; font-weight: 400; text-align: center; padding: 10px; border-radius: 10px; border: 1px solid #dde6ed; background: #fff; } } } } } } .device { height: $boxHeight; width: 240px; min-width: 240px; .nav { height: $customHeight; padding: 10px; border-radius: 10px; background-image: linear-gradient(180deg, #ebf2fa, #fff); display: flex; .nav_tab { width: 110px; min-width: 110px; .text { color: #758491; font-family: PingFangSC-Semibold; font-size: 14px; font-weight: 600; text-align: center; } .oveCC { overflow: hidden; overflow: auto; height: 100%; .deviceCode { cursor: pointer; margin-top: 5px; background: #fff; border: 1px solid #dde6ed; border-radius: 10px; height: 100px; padding: 10px; position: relative; .dev_text { height: 60px; text-align: center; line-height: 60px; } .dev_id { color: #758491; } } } } } } .details { height: $boxHeight; width: 240px; min-width: 240px; padding-left: 10px; .nav { height: $customHeight; border-radius: 10px; background-image: linear-gradient(180deg, #ebf2fa, #fff); padding: 10px; .nav_left { width: 120px; } } } </style>