实现效果
左右两模块支持左侧内容拖拽到右侧,左侧树支持单独拖动,右侧内容支持单独拖动。当左侧内容拖动到右侧时,内容被覆盖,右侧内容内部拖动时,不进行覆盖 内容更换位置。
index.vue
<template>
<div class="dragdrop">
<el-row :gutter="20">
<el-col :span="6">
<div :class="['global-layout']">
<left-tree />
</div>
</el-col>
<el-col :span="18">
<div :class="['global-layout']">
<right-content />
</div>
</el-col>
</el-row>
</div>
</template>
<script lang="ts" setup>
import { ref, onMounted, reactive } from 'vue'
import leftTree from './leftTree.vue'
import rightContent from './rightContent.vue'
</script>
<style scoped lang="scss">
.global-layout {
min-height: calc(100vh - 100px);
overflow-y: auto;
background: #fff;
border-radius: 10px;
padding: 20px;
box-shadow: 0 0 20px rgba(0, 0, 0, 0.1);
}
</style>
leftTree.vue
<template>
<div>
<el-tree
style="max-width: 600px"
:data="data"
node-key="id"
draggable
:allow-drop="allowDrop"
:allow-drag="allowDrag"
default-expand-all
:expand-on-click-node="false"
@node-drag-start="handleDragStart"
>
<template #default="{ node, data }">
<span class="custom-tree-node">
<span>{{ node.label }}</span>
</span>
</template>
</el-tree>
</div>
</template>
<script lang="ts" setup>
import Vue from 'vue'
import type Node from 'element-plus/es/components/tree/src/model/node'
import type {
AllowDropType,
NodeDropType,
} from 'element-plus/es/components/tree/src/tree.type'
const data = [
{
label: 'Level one 1',
children: [
{
label: 'Level two 1-1',
children: [
{
label: 'Level three 1-1-1',
},
],
},
],
},
{
label: 'Level one 2',
children: [
{
label: 'Level two 2-1',
children: [
{
label: 'Level three 2-1-1',
},
],
},
{
label: 'Level two 2-2',
children: [
{
label: 'Level three 2-2-1',
},
],
},
],
},
{
label: 'Level one 3',
children: [
{
label: 'Level two 3-1',
children: [
{
label: 'Level three 3-1-1',
},
],
},
{
label: 'Level two 3-2',
children: [
{
label: 'Level three 3-2-1',
},
],
},
],
},
]
const renderTreeNodes = (data: Node[]) => {}
const handleDragStart = (node: Node, ev: any) => {
ev.dataTransfer.setData('text/plain', node.data.label)
}
const handleDrop = (ev: any) => {
console.log('tree drop111:', ev)
}
const allowDrop = (draggingNode: Node, dropNode: Node, type: AllowDropType) => {
if (dropNode.data.label === 'Level two 3-1') {
return type !== 'inner'
} else {
return true
}
}
const allowDrag = (draggingNode: Node) => {
return true
// return !draggingNode.data.label.includes('Level three 3-1-1')
}
</script>
<style lang="sass" scoped>
</style>
rightContent.vue
<template>
<div class="rightContent">
<div class="headerRight">
<el-icon :size="34" :class="colorFour">
<Menu @click="handlechangeolor('four')" />
</el-icon>
<el-icon :size="34" :class="colorNine">
<Grid @click="handlechangeolor('nine')" />
</el-icon>
</div>
<div class="gridContent">
<el-row :gutter="20">
<el-col
:span="colorFour == 'colorActive' ? 12 : 8"
v-for="(item, index) in boxs"
:key="index"
>
<div
:class="[
'glaobalBox',
colorFour == 'colorActive' ? 'bigBox' : 'smallBox',
]"
draggable="true"
@dragstart="(e) => dragStartFn(e, item, index)"
@dragenter="dragEnterFn($event, index)"
@dragover="dragoverFn($event, index)"
@drop="(e) => dropFn(e, item, index)"
>
{{ item }}
</div>
</el-col>
</el-row>
</div>
</div>
</template>
<script lang="ts" setup>
import Vue, { onMounted, reactive, ref } from 'vue'
let colorFour = ref<string>('colorActive')
let colorNine = ref<string>('colorDefualt')
let num = ref<number>(0)
let boxs = ref<Array<any>>(['a', 'b', 'c', 'd'])
const handlechangeolor = (type: string) => {
if (type == 'four') {
boxs.value = boxs.value.slice(0, 4)
colorFour.value = 'colorActive'
colorNine.value = 'colorDefualt'
} else if (type == 'nine') {
boxs.value = boxs.value.concat(new Array(5).fill(1))
colorFour.value = 'colorDefualt'
colorNine.value = 'colorActive'
}
}
// 拖动
const dragIndex = ref<number>()
const enterIndex = ref(0)
const selectedRow = ref()
const draggable = ref(true)
// 该事件在用户开始拖动元素时触发
const dragStartFn = (event: any, item: Number, index: Number) => {
event.dataTransfer.setData('text/plain', item)
selectedRow.value = item
dragIndex.value = index
}
// ondragenter事件在拖动元素进入目标元素时触发,通常用于设置拖动时的样式。
const dragEnterFn = (e: any, index: number) => {
e.preventDefault()
enterIndex.value = index
}
// ondragover事件在拖动元素在目标元素上方时触发,通常用于防止默认的拖放行为。可以通//过event.preventDefault()方法阻止默认行为。
const dragoverFn = (e: any, index: number) => {
e.preventDefault()
}
//从外部拖拽放置到当前列表
const dropFn = (event: any, item: string, index: number) => {
var data = event.dataTransfer.getData('text/plain')
//执行自己的操作
let arr = JSON.parse(JSON.stringify(boxs.value))
//释放位置 原本的值
let targetItem = arr[index]
//将拖动的值放在释放位置上
arr.splice(index, 1, data)
//如果内部拖动 则 内容互换
//若外部拖动进来的内容则直接覆盖
if (dragIndex.value == 0 || dragIndex.value > 0) {
arr.splice(dragIndex.value, 1, targetItem)
}
dragIndex.value = -1
boxs.value = arr
}
</script>
<style lang="scss" scoped>
.rightContent {
.headerRight {
display: flex;
justify-content: flex-end;
margin-bottom: 20px;
.colorActive {
color: #409eff;
}
.colorDefualt {
color: #999;
}
}
.gridContent {
.glaobalBox {
background: #e5ebf136;
border: 1px solid #409eff;
margin-bottom: 20px;
padding: 20px;
}
.bigBox {
height: 40vh;
min-height: 300px;
}
.smallBox {
height: 26vh;
min-height: 280px;
}
}
}
</style>