html拖拽移动元素,vue-draggable实现元素拖拽移动实践笔记

本文介绍了如何在Vue项目中使用vue-draggable插件实现列表元素的拖拽移动功能。详细讲解了组件的安装、引入及在模板中的使用,并提供了具体的代码示例,包括两个列表之间的拖放操作,以及限制已选元素数量不超过4个的逻辑处理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

今天分享一个vue项目中在不同列表拖拽设置选项的功能,这个功能也是在做项目中遇到的,先说下这个功能的要点(参考下图),有2个列表,左侧列表展示已选,右侧列表展示未选,通过拖拽进行设置,已选的选项不能超过4个,超过的话自动将拖拽之前的最后一项清除到右侧,且如果从已选往未选里拖的时候,右侧显示垃圾桶的提示(如图)。

拖拽功能图片:

5202906fe496e6c2a4942e4b970fd87e.png

垃圾桶显示图:

029e7d0c24b104d12b9f657976059926.png

首先讲讲vue-draggable的使用

安装vue-draggable:

npm install vuedraggable

在使用插件的组件内引入vue-draggable并注册组件:

import draggable from "vuedraggable"

components: {

draggable

}

然后在我们需要拖拽的列表中使用:

v-model="selectedTheme"

v-bind="dragOptions"

:move="onMove"

@end="onEnd"

>

v-for="item in selectedTheme"

:key="item.type"

>{{item.name}}

下面是拖拽功能组件的完整代码:

title="设置选项"

:visible.sync="dialogVisible"

width="648px"

:close-on-click-modal="false"

>

当前选项
从右侧拖拽添加

v-model="selectedTheme"

v-bind="dragOptions"

:move="onMove"

@end="onEnd"

>

v-for="item in selectedTheme"

:key="item.type"

>{{item.name}}

全部选项

v-model="unSelectTheme"

v-bind="dragOptions"

:move="onMove"

@end="onEnd">

v-for="item in unSelectTheme"

:key="item.type"

>{{item.name}}

恢复默认设置

保存

import {Message} from 'element-ui'

import draggable from "vuedraggable"

export default {

name: 'DragDrop',

components: {

draggable

},

data() {

return {

dialogVisible: false,

selectedTheme: [{

type: 1,

name: '选项1'

}, {

type: 2,

name: '选项2'

}, {

type: 3,

name: '选项3'

}, {

type: 4,

name: '选项4'

}], // 已选主题列表

unSelectTheme: [{

type: 5,

name: '选项5'

}, {

type: 6,

name: '选项6'

}], // 未选主题列表

backSelectedTheme: [{

type: 1,

name: '选项1'

}, {

type: 2,

name: '选项2'

}, {

type: 3,

name: '选项3'

}, {

type: 4,

name: '选项4'

}], // 已选主题列表备份用于恢复默认设置

backUnSelectTheme: [{

type: 5,

name: '选项5'

}, {

type: 6,

name: '选项6'

}], // 未选主题列表备份

relatedListLast: {}, // 已选主题列表最后一项

isShowDel: false

}

},

methods: {

showDrag() {

this.dialogVisible = true

},

onMove({ relatedContext, draggedContext, to }) {

const relatedElement = relatedContext.element

const draggedElement = draggedContext.element

let dragInEl = to['className']

if (dragInEl == 'selected-list') {

this.isShowDel = false

if (this.selectedTheme.length === 4) {

// 判断往已选列表拖时,如果已经满足4项,则记录已选列表的最后一项

// 拖拽结束时将此项清除到未选列表中

this.relatedListLast = this.selectedTheme[this.selectedTheme.length-1]

}

} else {

this.isShowDel = true // 判断如果是往未选列表里拖的话显示垃圾桶

}

return (

(!relatedElement || !relatedElement.fixed) && !draggedElement.fixed

)

},

onEnd(dragObj) {

let dragInEl = dragObj.to['className']

if (dragInEl == 'selected-list') {

if (this.selectedTheme.length > 4) {

// 判断已选列表大于4项,将记录的最后一项过滤出来,并push到未选列表数组

this.selectedTheme = this.selectedTheme.filter(item => {

return item.type != this.relatedListLast.type

})

this.unSelectTheme.push(this.relatedListLast)

}

}

if (dragInEl === 'theme-right-list') {

// 判断是往未选列表拖时,拖拽结束时将垃圾桶隐藏

this.isShowDel = false

}

},

// 保存设置

saveThemeSet() {

const params = {

taskTopicList: this.selectedTheme

}

if (this.selectedTheme.length !== 4) {

Message({

type: 'error',

message: '需设置4个选项 !'

})

return false

}

$ajax.save(params).then(data => {

this.dialogVisible = false

Message({

type: 'success',

message: '保存成功!'

})

this.$parent.refresh()

}).catch(err => {

console.log(err)

})

},

// 恢复默认设置

restoreDefault() {

this.selectedTheme = this.backSelectedTheme

this.unSelectTheme = this.backUnSelectTheme

}

},

computed: {

dragOptions() {

return {

animation: 0,

group: "description",

disabled: false,

ghostClass: "ghost"

}

}

}

};

body, ul, dl, dt, dd, li, h1, h3{

margin: 0;

padding: 0;

}

ul, ol, li {

list-style: none;

}

.theme-setting {

/deep/.el-dialog {

height: 476px;

border-radius: 6px;

.el-dialog__header {

height: 55px;

line-height: 56px;

padding: 0;

border-bottom: 1px solid rgba(13,20,30, 0.1);

.el-dialog__title {

height:21px;

font-size:16px;

font-family:MicrosoftYaHei-Bold,MicrosoftYaHei;

font-weight:bold;

color:rgba(13,20,30,1);

line-height:21px;

}

.el-dialog__headerbtn {

margin-top: -4px;

}

}

.el-dialog__body {

position: relative;

display: flex;

height: 331px;

padding: 0;

border-bottom: 1px solid rgba(13,20,30, 0.1);

.theme-left {

width: 218px;

margin-left: 24px;

border-right: 1px solid rgba(13,20,30, 0.1);

.theme-title {

display: flex;

margin-top: 24px;

.title {

height:19px;

margin-right: 4px;

font-size:14px;

font-family:MicrosoftYaHei-Bold,MicrosoftYaHei;

font-weight:bold;

color:rgba(13,20,30,1);

line-height:19px;

}

.des {

height:16px;

font-size:12px;

font-family:MicrosoftYaHei;

color:rgba(13,20,30,0.6);

line-height:19px;

}

}

.selected-list {

height: 240px;

margin-top: 24px;

overflow: hidden;

.selected-theme {

width:160px;

height:48px;

line-height:48px;

text-align: center;

margin-bottom: 16px;

cursor: pointer;

background:linear-gradient(180deg,rgba(43,46,83,1) 0%,rgba(108,116,150,1) 100%);

border-radius:6px;

font-size:14px;

font-family:MicrosoftYaHei;

color:rgba(255,255,255,1);

}

}

}

.theme-right {

padding: 0 24px;

.theme-right-title {

padding-top: 24px;

height:19px;

font-size:14px;

font-family:MicrosoftYaHei-Bold,MicrosoftYaHei;

font-weight:bold;

color:rgba(13,20,30,0.4);

line-height:19px;

}

.theme-right-list {

width: 357px;

height: 240px;

overflow: scroll;

margin-top: 24px;

.theme-right-item {

width: 160px;

height:48px;

line-height:48px;

float: left;

margin-right: 16px;

margin-bottom: 16px;

background:rgba(247,248,252,1);

border-radius:6px;

font-size:14px;

font-family:MicrosoftYaHei;

color:rgba(13,20,30,0.4);

text-align: center;

cursor: pointer;

}

}

.theme-right-list::before, .theme-right-list::after {

content: "";

display: table;

}

.theme-right-list::after {

clear: both;

}

}

.drag-drop-del {

position: absolute;

right: 1px;

top: 0;

width: 404px;

height: 331px;

display: flex;

justify-content: center;

align-items: center;

background-image: url('../../src/assets/imgs/drapDrop/drag_drop.png');

img {

width: 96px;

height: 96px;

}

}

}

.el-dialog__footer {

height: 88px;

padding: 24px 24px 0;

.dialog-footer {

.el-button+.el-button {

margin-left: 16px;

}

}

}

}

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值