介绍:vue2拖拽插件,一对一拖拽,一个格子只有一个数据,当然也可以多个(多个更简单)各种拖拽吧。
先看gif格式的动态图片,最后有我写的纯前端demo,只要安装了插件就能用
先介绍插件(不会介绍必定插件不是我写的我只是用):我看的这个文档还挺详细的
中文地址vue.draggable中文文档 - itxst.com
- npm下载 npm install vuedraggable
- 那个页面要用在那个页面做引入
import draggable from 'vuedraggable' // 引入 components: {draggable},// 注册 - 最基础的简单使用(里面有不算详细的介绍)(这里只介绍了一个因为我感觉有很多东西需要咱们自己看文档,我么办法一个个介绍,主要是简单啊)
<div class="col">
<div class="title">A组</div>
<!--
<transition-group>标签不知道干啥用的带上跟不带我没发现什么区别
!! 切记 <draggable>或者说<transition-group>标签下面只能单纯的一个div循环出来别瞎写不然报错!!
!只能写一个div让他循环就行了!
v-model表示数据源 (不必多说)
group 这个想象成一个组 相同的组之间才可以相互拖拽
animation 是过渡动画
。。。还有不少东西,不过基础的够用了,需要更多的请查看官网快速入门里面的介绍
-->
<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">B组(本组不能拖入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>
————————————————
版权声明:本文为CSDN博主「卑信-吾天」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/weixin_56718509/article/details/133863083
4.基础的已经没什么了(带你入个门而已别的可以看官网就行)。我介绍一下我写的吧比较复杂一点(不想听可以直接复制代码纯前端的demo vue2+Element写的别的框架的话直接改el-即可),我这边业务需求是有三个数据源,患者+两个设备(都是独立的),并且每个框框只能放一条数据。这样的话就有点麻烦用到了动态的group(代码里面有写)一个动态里面的name对应一个静态的。并且在动态的里面可以设置是否能拖进去或者拖出来.....(累了直接看代码吧,有不足请指教,谢谢)
5.纯前端demo,只要安装了插件就能用
<template>
<div style="display: flex;padding: 10px;">
<div class="patient" style="">
<div class="tetx_nav">患者</div>
<div class="nav">
<div class="text">待分配</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?'女':'男'}}</span>
<span>{{item.age}}岁</span>
</div>
<div class="list_time">
<span>{{item.time}}</span>
<span>开始监护</span>
</div>
</div>
</transition-group>
</draggable>
</div>
</div>
</div>
<div class="info">
<div class="tetx_nav">
入科:0 | 在科:0 | 出科: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}}床位</div>
<div class="box_div">
<div class="notNull dox_sty" :class="{ 'glow-effect': isDraggingUser&&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">请分配患者至床位</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?'女':'男'}}</span>
<span>{{item.age}}岁</span>
</div>
<div class="list_time">
<span>{{item.time}}</span>
<span>开始监护</span>
</div>
</div>
</draggable>
</div>
</div>
<div class="device_div dox_sty" :class="{ 'glow-effect': isDraggingDevjhy&&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">监护仪</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&&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">呼吸机</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">
设备
</div>
<div class="nav">
<div class="nav_tab" style="padding-right: 5px;">
<div class="text">监护仪</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="暂无设备"></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">呼吸机{{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="暂无设备"></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">
患者信息
</div>
<div class="nav">
<div style="display: flex;line-height: 40px;">
<div class="nav_left">姓名:</div>
<div style="flex: 1;">{{userInfo.name!=''?userInfo.name:'-'}}</div>
</div>
<div style="display: flex;line-height: 40px;">
<div class="nav_left">性别:</div>
<div style="flex: 1;">{{userInfo.xb===''?'-':userInfo.xb==1?'男':'女'}}</div>
</div>
<div style="display: flex;line-height: 40px;">
<div class="nav_left">年龄:</div>
<div style="flex: 1;">{{userInfo.age!=''?userInfo.age:'-'}}</div>
</div>
<div style="display: flex;line-height: 40px;">
<div class="nav_left">科室:</div>
<div style="flex: 1;">-</div>
</div>
<div style="display: flex;line-height: 40px;">
<div class="nav_left">病区:</div>
<div style="flex: 1;">-</div>
</div>
<div style="display: flex;line-height: 40px;">
<div class="nav_left">床位号:</div>
<div style="flex: 1;">-</div>
</div>
<div style="display: flex;line-height: 40px;">
<div class="nav_left">住院号:</div>
<div style="flex: 1;">-</div>
</div>
<div style="display: flex;line-height: 40px;">
<div class="nav_left">责任医生:</div>
<div style="flex: 1;">-</div>
</div>
<div style="display: flex;line-height: 40px;">
<div class="nav_left">诊断信息:</div>
<div style="flex: 1;">-</div>
</div>
<div style="display: flex;line-height: 40px;">
<div class="nav_left">护理等级:</div>
<div style="flex: 1;">-</div>
</div>
<div style="display: flex;line-height: 40px;">
<div class="nav_left">病情等级:</div>
<div style="flex: 1;">-</div>
</div>
<div style="display: flex;line-height: 40px;">
<div class="nav_left">通气模式:</div>
<div style="flex: 1;">-</div>
</div>
<div style="display: flex;line-height: 40px;">
<div class="nav_left">起搏模式:</div>
<div style="flex: 1;">-</div>
</div>
<div style="display: flex;line-height: 40px;">
<div class="nav_left">设备号(监护仪):</div>
<div style="flex: 1;">-</div>
</div>
<div style="display: flex;line-height: 40px;">
<div class="nav_left">设备号(呼吸机):</div>
<div style="flex: 1;">-</div>
</div>
<div style="display: flex;line-height: 40px;">
<div class="nav_left">监护状态:</div>
<div style="flex: 1;">-</div>
</div>
<div style="display: flex;line-height: 40px;">
<div class="nav_left">监护开始时间:</div>
<div style="flex: 1;">-</div>
</div>
<div style="display: flex;line-height: 40px;">
<div class="nav_left">监护时长:</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: '张三',
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: '狂徒',
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, //是否可以拖出去
put: true, //是否可以拖进来
},
devHxjB: {
name: "devHxj",
pull: true, //拖出去
put: true, //拖进来
},
})
}
},
methods: {
// 患者信息详情
userItem(item) {
this.userInfo = item
},
// 新增数据 -- 患者
userAdd(data, i) {
this.$set(this.allList[i].userB, 'pull', true)
this.$set(this.allList[i].userB, 'put', false)
},
// 移动结束 -- 患者
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)
}
},
// 新增数据 -- 呼吸机
devHxjAdd(data, i) {
this.$set(this.allList[i].devHxjB, 'pull', true)
this.$set(this.allList[i].devHxjB, 'put', false)
},
// 移动结束 -- 呼吸机
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)
}
},
// 新增数据 -- 监护仪
devJhyAdd(data, i) {
this.$set(this.allList[i].devJhyB, 'pull', true)
this.$set(this.allList[i].devJhyB, 'put', false)
},
// 移动结束 -- 监护仪
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)
}
},
// 《------------------------------外发光效果 内部文字消失
startDragging() { // 开始拖动时触发的事件 -- 患者
this.isDraggingUser = true;
this.isClose('user',true)
},
stopDragging() { // 选中后松开鼠标的事件 -- 患者
this.isDraggingUser = false;
// this.open()
},
startDevjhy() { // 开始拖动时触发的事件 -- 监护仪
this.isDraggingDevjhy = true;
this.isClose('Devjhy',true)
},
stopDevjhy() { // 选中后松开鼠标的事件 -- 监护仪
this.isDraggingDevjhy = false;
// this.open()
},
startDevhxj() {// 开始拖动时触发的事件 -- 呼吸机
this.isDraggingDevhxj = true;
this.isClose('Devhxj',true)
},
stopDevhxj() { // 选中后松开鼠标的事件 -- 呼吸机
this.isDraggingDevhxj = false;
// this.open()
},
// 外发光效果-------------------------------》
// 由于自定义然而name的效果好像失效了(bug:可以任意的拖拽),所以只能禁用拖进的事件
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
// })
// }
},
}
</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; //文字不可被选中
.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; //文字不可被选中
.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>