背景
工作中遇到这样的一个需求:将页面侧边菜单拖拽到页面中间的画布中,然后在画布内可对此菜单进行随意移动。操作如下图所示:
代码查看地址
功能分析
页面分为菜单和画布两个部分,其中菜单部分为拖拽元素,画布部分为放置元素。
整个操作也分为两个部分,首先从侧边栏拖拽到画布中央,放置在画布上后,再次点击画布中的元素可对其进行拖拽移动。
功能实现
第一步:从侧边拖拽到画布上
<div class="main">
<draggable group="components" draggable=".draggable" @add="onAdd"></draggable>
</div>
// draggable 指定元素内的哪些项目应可拖动
// sort 列表内排序
// group 要将元素从一个列表拖到另一个列表中,两个列表必须具有相同的组名
<div class="aside">
<draggable class="draggable-tab" draggable=".panel-item"
group="components" :sort="false" @end="onEnd">
....
</draggable>
import draggable from 'vuedraggable'
export default {
methods: {
onAdd (evt) { // 元素从另一个列表拖放到列表中
console.log(evt)
},
onEnd (evt) { // 元素拖动结束
if (evt.pullMode) {
console.log(evt)
}
}
}
}
第二步:拖拽移动画布中的元素位置
被移动元素需设置为绝对定位,其父元素设置为相对定位
<div class="aside">侧边菜单栏</div>
<div class="container">
<div class="panel-item" id="panel">
<div class="move" @mousedown="mousedown"></div>
</div>
</div>
<style>
.container {
position: relative;
}
.panel-item {
position: absolute;
}
</style>
import $ from 'jquery'
export default {
methods: {
mousedown (evt) {
$('#panel').css('z-index', ++this.zIndex)
const offsetX = evt.offsetX
// 限制拖拽范围,不超过当前可视窗口
const drag = (evt) => {
let xScale
if (this.position === 'right') {
xScale = evt.x < (document.body.clientWidth - $('.aside').width() - 10) &&
evt.x > 10
} else {
xScale = evt.x < (document.body.clientWidth - 50) &&
evt.x > $('.aside').width()
}
if (xScale) {
if (this.position === 'right') {
const left = (evt.x - offsetX)
$('#panel').css('left', left)
} else {
if ($('.aside').width() > 0) {
$('#panel').css('left', evt.x - offsetX - 180)
} else {
$('#panel').css('left', evt.x - 120)
}
}
}
const yScale = evt.y > 10 && evt.y < (document.body.clientHeight - 10)
if (yScale) {
$('#panel').css('top', evt.y - 5)
}
}
this.onDrag(drag)
},
onDrag (drag) {
const up = () => {
document.removeEventListener('mousemove', drag)
document.removeEventListener('mouseup', up)
}
// 监听鼠标移动事件,移动过程中不断改变被拖拽元素的位移
document.addEventListener('mousemove', drag)
// 监听鼠标松开事件,当鼠标松开时,取消元素位移改变
document.addEventListener('mouseup', up)
},
}
}