基于vue实现拖拽排序功能

742 阅读1分钟

需求如下:

要实现一个菜单拖拽排序的需求,通过配置项决定是否可以跨越父级菜单拖拽

思路:

设置元素draggable为true,并添加dragend、drop事件

属性:
draggable: true

事件:
drag: 拖动中触发
dragstart: 开始拖动时触发
dragend: 完成拖动后触发
dragenter: 拖拽元素进入目标区域时触发,在拖拽元素上也会触发一起
dragover: 拖拽元素在目标区域移动时触发
dragleave: 拖动元素离开目标区域时触发
drop: 释放元素时触发,使用时必须dropover事件,

贴代码:

<template>
	<div class="demo">
		<div v-for="menu in menus" :key="menu.id">
			<h3>{{ menu.name }}</h3>
			<ul>
				<li
					v-for="item in menu.children"
					:key="item.id"
					draggable="true"
					@dragend="dragEnd(item, menu)"
					@dragover.prevent
					@drop="drop(item, menu)">{{item.id}}{{item.name}}</li>
			</ul>
		</div>
	</div>
</template>

<script>
export default {
	data() {
		return {
			menus: {
				menu1: {
					name: "菜单一",
					id: 111,
					children: [
						{ id: 1, name: '用户管理' },
						{ id: 2, name: '系统管理' },
						{ id: 3, name: '角色管理' },
						{ id: 4, name: '权限管理' },
					]
				},
				menu2: {
					name: "菜单二",
					id: 222,
					children: [
						{ id: 5, name: '数据概览' },
						{ id: 6, name: '业务管理' },
						{ id: 7, name: '菜单管理' }
					]
				}
			},
			dragItem: null,
			targetItem: null,
			dragParent: null,
			targetParent: null,
			across: false
		}
	},
	methods: {
		dragEnd(menu, parent) {
			this.dragItem = menu
			this.dragParent = parent
			let targetIndex = this.targetParent.children.findIndex(item => item.id === this.targetItem.id)
			let dragIndex = this.dragParent.children.findIndex(item => item.id === this.dragItem.id)
			if(this.across) {
				// 允许跨级
				this.dragParent.children.splice(dragIndex, 1)
				this.targetParent.children.splice(targetIndex, 0, this.dragItem)
			}else {
				// 不允许跨级
				if(this.dragParent.id === this.targetParent.id) {
					this.dragParent.children.splice(dragIndex, 1)
					this.targetParent.children.splice(targetIndex, 0, this.dragItem)
				}
			}
		},
		drop(menu, parent) {
			this.targetItem = menu
			this.targetParent = parent
		}
	}
}
</script>

<style lang="scss" scoped>
.demo {
	padding: 40px;
	ul {
		display: flex;
		flex-wrap: wrap;
		li {
			width: 100px;
			height: 100px;
			background-color: pink;
			margin: 20px;
		}
	}
}
</style>