VUE+H5跨组件元素拖拽并传递数据;拖拽结束自动计算布局;以及如何配合element的可拖拽tree使用
1.vue+H5实现跨组件拖拽与数据传递思路:
(1)可拖拽组件元素的dragstart事件中,将相关数据暂存在vuex;
(2)可放置组件元素的drop事件中,接收vuex中暂存的数据;
(3)清空vuex的暂存数据;
2.vue+H5实现跨组件拖拽与数据传递实现;
(1)可拖拽组件:
<template>
<div @dragstart="drag">
</div>
</template>
<script>
import { mapGetters, mapMutations} from 'vuex'
export default {
props: {
},
computed: {
...mapGetters(['curDragCell'])
},
methods: {
/**
* 开始拖动
*/
drag() {
this.setCurDrag(this.item)
},
...mapMutations(["setCurDrag"])
},
};
</script>
(2)vuex设计
state: {
curDragCell: null,
},
mutations: {
setCurDrag(state, v = {}) {
state.curDragCell = JSON.parse(JSON.stringify(v));
},
},
actions: {
},
getters: {
curDragCell: state => state.curDragCell,
},
(3)可放置拖拽组件
<template>
<div @drop="drop">
</div>
</template>
<script>
import { mapGetters, mapMutations } from "vuex";
export default {
...
computed: {
...mapGetters(["curDragCell"]),
},
methods:{
...mapMutations(["setCurDrag"]),
drop(e) {
//在这里通过this.curDragCell获取当前被拖拽的组件相关数据并处理
...
//处理结束后清空vuex中的暂存数据
this.setCurDrag(null);
}
}
}
</script>
3.拖拽结束自动计算布局
如果希望被拖拽过来的元素自动实现从左到右的自动布局,或者拖拽到其他元素中间实现插入布局,则需要一些坐标上的计算;
计算思路:
(1)在可放置拖拽组件的drop事件中,遍历所有参与布局的元素,获取其相对与画布元素的x,y坐标,以及其自身宽高,以计算出其中心坐标;
(2)获取拖拽结束事件的鼠标坐标,与上一步的所有参与布局的元素的中心坐标进行x、y坐标上的比较,根据需求算出权重值;(需要注意的是,从左到右从上到下排列时,计算权重是y轴坐标的权重需要比x轴坐标权重高出一个或几个数量级,具体数值由画布元素宽度决定,不知道计算原理的话越大越好。)
(3)权重最大(或最小)的元素位置便是需要处理的位置,根据鼠标坐标x坐标轴和该元素坐标x坐标轴比较,算出插入位置是左还是右,并实现插入。
代码实现:
/**
* 拖拽结算
*/
drop(e) {
e.preventDefault();
//通过x,y坐标判断插入位置
if (!this.curDragCell) return;
if (this.rules.length === 0) {
this.rules.push(this.curDragCell);
} else {
let drawing = this.$refs.rulesInput;
let pos = drawing.getBoundingClientRect();
let curX = e.x - pos.x;
let curY = e.y - pos.y;
let cells = (this.$refs.rulesInputCell.map((item) => item.$el)).filter(item=> this.curDragDom?!item.className.includes('cur'):true)
let minimum = null;
for (let i = 0; i < cells.length; i++) {
let item = cells[i];
let position =
curX - (item.offsetLeft + item.offsetWidth / 2) >= 0 ? 1 : 0; //1:右侧,0:左侧
let distanceItem = {
weight:
(position
? Math.abs(curX - item.offsetLeft - item.offsetWidth)
: Math.abs(curX - item.offsetLeft)) +
Math.abs(curY - item.offsetTop - item.offsetHeight / 2) * 10000, //加重y轴距离权重
position: position,
index: i,
};
if (!minimum || distanceItem.weight <= minimum.weight) {
minimum = distanceItem;
}
}
if (minimum.index === 0 && minimum.position === 0) {
this.rules.unshift(this.curDragCell);
} else if (
minimum.index === this.rules.length - 1 &&
minimum.position === 1
) {
this.rules.push(this.curDragCell);
} else {
this.rules.splice(
minimum.index + minimum.position,
0,
this.curDragCell
);
}
this.setCurDrag(null);
}
},
4.如何配合element的可拖拽tree使用
如果想要从element的tree组件中直接拖拽元素出来使用,其实有非常简便的方法;
思路:因为el-tree自带可拖拽的功能,且本身实现原理也是H5的拖拽,所以的拖拽相关事件都可以复用,只要在el-tree组件做一些配置即可
<el-tree
ref="tree"
:data="data"
@node-drag-start="handleDragStart"
draggable
:allow-drop="allowDrop"
:allow-drag="allowDrag"
></el-tree>
<script>
export default {
/**
* 拖动开始
*/
handleDragStart(node) {
node.data.name = node.data.elePathNameCh;
this.setCurDrag(node.data);
},
/**
* 不允许在此区域结束拖动
*/
allowDrop() {
return false;
},
/**
* 判断是否允许拖动
*/
allowDrag(node) {
if(this.onlyAcLeaf){
return this.isAllowDrag&&node.isLeaf;
}else{
return this.isAllowDrag
}
},
}
</script>