所需效果如下:
代码如下:
<template>
<div class="move-container">
<div v-move:[params]="shuffle" :move-x="false" class="avatar">头像</div>
<div v-move:[params2]="shuffle" class="nickname">昵称</div>
</div>
</template>
<script>
import { ref } from 'vue';
export default {
directives: {
move: {
mounted(el, binding) {
const dragBox = el; //获取当前元素
const boundary = binding.arg?.boundary ?? false; // 控制是否不能超出边界
const callback =
binding.value ??
(() => {
return null;
});
const canMoveX = el.getAttribute('move-x') !== false;
const canMoveY = el.getAttribute('move-y') !== false;
dragBox.style.position = 'absolute';
const pdom = dragBox.parentNode;
boundary && (pdom.style.position = 'relative');
// 父元素宽高
const pw = pdom.offsetWidth;
const ph = pdom.offsetHeight;
// 本身宽高
const sw = dragBox.offsetWidth;
const sh = dragBox.offsetHeight * 2; // 在控制父边界情况下避免元素超出范围
// 计算得到最大移动距离
const maxw = pw - sw + dragBox.offsetLeft;
const maxh = ph - sh + dragBox.offsetHeight;
const minw = 0;
const minh = 0;
dragBox.onmousedown = (e) => {
// 阻止默认事件,避免元素选中
e.preventDefault();
dragBox.style.cursor = 'move';
//算出鼠标当前相对元素的位置
const disX = e.x - dragBox.offsetLeft;
const disY = e.y - dragBox.offsetTop;
document.onmousemove = (e2) => {
//用鼠标的位置减去鼠标相对元素的位置,得到元素的位置
let left = e2.clientX - disX;
let top = e2.clientY - disY;
// 相对于父元素的移动百分比
let percentX = 0;
let percentY = 0;
// 当传入true代表控制边界
if (boundary) {
left = left > maxw ? maxw : left < minw ? minw : left;
top = top > maxh ? maxh : top < minh ? minh : top;
// 计算移动百分比
percentX = Number(((left / maxw) * 100).toFixed(2));
percentY = Number(((top / maxh) * 100).toFixed(2));
}
//移动当前元素
canMoveX && (dragBox.style.left = left + 'px');
canMoveY && (dragBox.style.top = top + 'px');
callback({ left, top, percentX, percentY }, binding.arg?.type);
};
document.onmouseup = () => {
//鼠标弹起来的时候不再移动
document.onmousemove = null;
document.onmouseup = null;
dragBox.style.cursor = 'default';
};
};
},
},
},
setup() {
const boundary = ref(true);
const type = ref('avatar');
const params = {
boundary: false,
type: 'avatar',
};
const params2 = {
boundary: true,
type: 'nickname',
};
const shuffle = (e, type) => {
console.log('e,', e);
console.log('type,', type);
};
return {
shuffle,
boundary,
type,
params,
params2,
};
},
};
</script>
<style lang="less" scoped>
.move-container {
position: relative;
width: 375px;
height: 667px;
margin-left: 100px;
margin-top: 100px;
background: #eee;
.avatar {
width: 38px;
height: 38px;
border: 1px solid red;
background: pink;
position: absolute;
}
.nickname {
width: 48px;
font-size: 24px;
color: blue;
}
}
</style>