文章目录
拖拽原理及相关定义
自定义指令实现
在utils目录下建立directives.js文件
import Vue from 'vue'
// v-drag: 拖拽
Vue.directive('drag', {
bind(el, binding, vnode, oldVnode) {
//el即为当前元素
el.style.cursor = 'move'
// 获取原有属性 ie dom元素.currentStyle 火狐谷歌 window.getComputedStyle(dom元素, null);
const sty = el.currentStyle || window.getComputedStyle(el, null)
el.onmousedown = (e) => {
//获取鼠标按下位置
const disX = e.clientX
const disY = e.clientY
// 获取当前元素的定位信息
// 获取到的值带px 正则匹配替换
let styL, styT
// 注意在ie中 第一次获取到的值为组件自带50% 移动之后赋值为px
// +的作用是将字符串转为数字
if (sty.left.includes('%')) {
styL = +document.body.clientWidth * (+sty.left.replace(/\%/g, '') / 100)
styT = +document.body.clientHeight * (+sty.top.replace(/\%/g, '') / 100)
} else {
styL = +sty.left.replace(/\px/g, '')
styT = +sty.top.replace(/\px/g, '')
}
document.onmousemove = function(e) {
// 通过事件委托,计算移动的距离
const l = e.clientX - disX
const t = e.clientY - disY
// 移动当前元素
el.style.left = `${l + styL}px`
el.style.top = `${t + styT}px`
}
//鼠标弹起,移除相应事件
document.onmouseup = function(e) {
document.onmousemove = null
document.onmouseup = null
}
}
}
})
// v-dragWidth: 标签宽度拖大 拖小
Vue.directive('dragWidth', {
bind(el, binding, vnode, oldVnode) {
el.style.cursor = 'crosshair'
// 获取原有属性 ie dom元素.currentStyle 火狐谷歌 window.getComputedStyle(dom元素, null);
const sty = el.currentStyle || window.getComputedStyle(el, null)
el.onmousedown = (e) => {
const disX = e.clientX
// 获取到的值带px 正则匹配替换
let styW
// 注意在ie中 第一次获取到的值为组件自带50% 移动之后赋值为px
if (sty.left.includes('%')) {
styW = +document.body.clientWidth * (+sty.width.replace(/\%/g, '') / 100)
} else {
styW = +sty.width.replace(/\px/g, '')
}
document.onmousemove = function(e) {
e.preventDefault() // 移动时禁用默认事件
// 通过事件委托,计算移动的距离
const l = e.clientX - disX
el.style.width = `${styW + l}px`
}
document.onmouseup = function(e) {
document.onmousemove = null
document.onmouseup = null
}
}
}
})
指令使用
main.js中引入
import './utils/directives.js';
组件内使用
<div v-drag></div>
<div v-dragWidth></div>
动态拖拽交换位置——draggable指令
<template>
<transition-group tag="div" class="container">
<div class="item"
v-for="item in items"
:key="item.key"
:style="{background:item.color,width:'80px',height:'80px',}"
draggable="true"
@dragstart="handleDragStart($event, item)"
@dragover.prevent="handleDragOver($event, item)"
@dragenter="handleDragEnter($event, item)"
@dragend="handleDragEnd($event, item)" >
</div>
</transition-group>
</template>
<script>
export default {
name: 'Toolbar',
data() {
return {
items: [
{ key: 1, color: '#ffebcc' },
{ key: 2, color: '#ffb86c' },
{ key: 3, color: '#f01b2d' }
],
dragging: null
};
},
methods: {
handleDragStart(e, item) {
this.dragging = item;
},
handleDragEnd(e, item) {
this.dragging = null;
},
// 首先把div变成可以放置的元素,即重写dragenter/dragover
handleDragOver(e) {
e.dataTransfer.dropEffect = 'move';// e.dataTransfer.dropEffect="move";//在dragenter中针对放置目标来设置!
},
handleDragEnter(e, item) {
e.dataTransfer.effectAllowed = 'move';// 为需要移动的元素设置dragstart事件
if (item === this.dragging) {
return;
}
const newItems = [...this.items];
const src = newItems.indexOf(this.dragging);
const dst = newItems.indexOf(item);
newItems.splice(dst, 0, ...newItems.splice(src, 1));
this.items = newItems;
}
}
};
</script>
<style scoped>
.container{
width: 80px;
height: 300px;
position: absolute;
left: 0;
display:flex;
flex-direction: column;
padding: 0;
}
.item {
margin-top: 10px;
transition: all linear .3s
}
</style>