前言
国内目前的低代码平台,前端部分普遍采取拖拽式
完成页面的布局。本次记录一个前端组件的拖拽案例。
Html 5 版
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
*{
padding: 0px;
margin: 0px;
}
.box{
width: 300px;
height: 30px;
background: pink;
position: absolute;
left: 0;
top: 0;
}
.box:hover{
cursor: move; /** 鼠标悬停 鼠标样式修改 **/
}
</style>
</head>
<body>
<div class="box" id="moveElement">我可以移动</div>
<script>
window.onload = function(){
// 获取元素节点
let moveElement = document.getElementById('moveElement');
// 给元素注册鼠标按下事件
moveElement.onmousedown = function(e){
//兼容 e || window.event 现在都可以
let event = e || window.event;
// 获取鼠标按下去的那一个点距离边框顶部和左侧的距离
let point_x=event.offsetX;
let point_y=event.offsetY;
// 鼠标移动(小方块在文档上移动,给文档注册一个是移动事件)
document.onmousemove = function(ent){
let evt = ent || window.event;
// 获取鼠标移动的坐标位置
let ele_left= evt.clientX - point_x;
let ele_top= evt.clientY - point_y;
// ----冗余代码---
// if(ele_left<=0){
// // 设置水平方向的最小值
// ele_left = 0
// }else if(ele_left >= window.innerWidth - moveElement.offsetWidth){
// // 设置水平方向的最大值
// ele_left = window.innerWidth - moveElement.offsetWidth
// }
// if(ele_top<=0){
// // 设置垂直方向的最小值
// ele_top = 0
// }else if(ele_top >= window.innerHeight - moveElement.offsetHeight){
// // 设置垂直方向的最大值
// ele_top = window.innerHeight - moveElement.offsetHeight
// }
// 优化为下面的
ele_left = Math.min(Math.max(0,ele_left), window.innerWidth - moveElement.offsetWidth)
ele_top= Math.min(Math.max(0,ele_top), window.innerHeight - moveElement.offsetHeight)
moveElement.style.left = ele_left + 'px';
moveElement.style.top = ele_top + 'px'
}
// 抬起停止移动
document.onmouseup = function(event){
console.log("抬起停止移动" )
// 移除移动和抬起事件
this.onmouseup = null;
this.onmousemove = null;
//修复低版本的ie可能出现的bug
if(typeof moveElement.releaseCapture!='undefined'){
moveElement.releaseCapture();
}
}
// 解决有些时候,在鼠标松开的时候,元素仍然可以拖动-使用的是第二种方式
document.ondragstart = function(ev) {
ev.preventDefault();
}
document.ondragend = function(ev) {
ev.preventDefault();
}
}
}
</script>
</body>
</html>
VUE 版
<template>
<!-- <h1>拖拽式</h1> -->
<div class="draggable"
:style="{top: posY + 'px', left: posX + 'px'}"
@click="clickthis"
@mousedown="start"
@mousemove="moving"
@mouseup="stop"
>可拖拽式 div</div>
</template>
<script>
export default{
data() {
return {
dragging: false, // 是否正在拖拽
offsetX: 0, // 鼠标按下时距离元素左上角的偏移
offsetY: 0, // 鼠标按下时距禋元素左上角的偏移
posX: 0, // 元素左上角相对于父元素的位置
posY: 0 // 元素左上角相对于父元素的位置
};
},
methods: {
clickthis(e){
console.log("点击事件");
},
start(e) {
console.log("开始拖拽");
this.dragging = true;
this.offsetX = e.clientX - this.posX;
this.offsetY = e.clientY - this.posY;
},
moving(e){
console.log("拖拽移动");
if (this.dragging) {
let posX = e.clientX - this.offsetX;
let posY = e.clientY - this.offsetY;
if (posX > 0 && posY > 0) {
this.posX = posX;
this.posY = posY;
}
}
},
stop(e){
console.log("结束拖拽");
this.dragging = false;
}
}
}
</script>
<style scoped>
.draggable {
position: absolute;
cursor: move;
border: 1px solid #ccc;
padding: 10px;
background-color: #f0f0f0;
transition: transform 0.3s;
}
.draggable.dragging {
transform: scale(1.1);
}
</style>
效果展示
核心思想
采取前端页面的鼠标动作onmouseup
、onmousedown
、onmousemove
,监听按住组件拖拽时,组件的位置变动点,在对应的监听逻辑中,每当位置变更,则获取移动后的定位点,重新设定组件或标签的位置。