在实际开发中,很可能会遇到开发可拖拽组件的需求,目的是应对某些弹框组件会遮盖某些重要信息/可操作面板,通过可拖拽的形式可以将上层的弹框组件移动到其他位置,从而不影响整个系统的操作。下面,我们分两步走,开发一个可拖拽的弹框组件,最终效果如下图所示,
Step-1:原生JS开发可拖拽弹框
第一步,基于原生JS开发一个简陋版本的可拖拽弹框,基本效果贴在本部分最后,先看一下完整的示例代码吧,
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>可拖拽弹框</title>
<style>
*,
html,
body {
padding: 0;
margin: 0;
box-sizing: border-box;
}
body {
background-color: #000;
}
.box {
position: absolute;
top: 15px;
left: 200px;
width: 400px;
height: 300px;
background-color: rgba(255, 255, 255, 0.3);
border: 1px solid #fff;
}
</style>
</head>
<body>
<div class="box" id="box"></div>
</body>
<script>
let boxPos = {
x: null,
y: null
}
let startPos = {
x: null,
y: null
}
let isMove = false;
const box = document.getElementById("box");
box.addEventListener("mousedown", (e) => {
const { clientX, clientY } = e;
//获取元素的当前位置
boxPos = {
x: box.offsetLeft,
y: box.offsetTop,
};
startPos = {
x: clientX,
y: clientY
}
isMove = true;
document.body.style.cursor = "move";
document.addEventListener("mousemove", (e) => {
if (!isMove) return;
const { clientX, clientY } = e;
const [offsetX, offsetY] = [clientX - startPos.x, clientY - startPos.y];
box.style.left = `${boxPos.x + offsetX}px`
box.style.top = `${boxPos.y + offsetY}px`
})
document.addEventListener("mouseup", () => {
isMove = false;
document.body.style.cursor = "default";
})
})
</script>
</html>
基本效果如下,PS:直接使用了黑色背景,弹框也没有做美化,因为我们的重点工作在后面的组件式开发。
Step-2:Vue可拖拽弹框组件
完整的示例代码如下,直接引入InfoBox.vue组件即可使用,
<template>
<div v-if="show" ref="infoBox" class="info-box" :style="styleObject">
<div class="nav" @mousedown.stop="mouseDownHandler">
<span class="title">{{ title }}</span>
<span class="iconfont close" @click="show = false"></span>
</div>
<div class="body">
<slot name="content"></slot>
</div>
</div>
</template>
<script>
export default {
name: "InfoBox",
props: {
width: {
type: String,
required: false,
default: "400px",
},
height: {
type: String,
required: false,
default: "300px",
},
title: {
type: String,
required: false,
default: '点位详情'
}
},
data() {
return {
styleObject: {
width: "400px",
height: "300px"
},
show: true,
isMove:false,
}
},
mounted() {
this.styleObject = {
height: this.$props.height,
width: this.$props.width,
}
},
methods: {
mouseDownHandler(e) {
const currentPosition = {x:this.$refs.infoBox.offsetLeft,y:this.$refs.infoBox.offsetTop};
const startPosition = {x:e.clientX,y:e.clientY};//获取当前点击位置
console.log(currentPosition,startPosition);
this.isMove = true;
//注册鼠标移动事件
document.addEventListener("mousemove",(event_move)=>{
if(!this.isMove) return;
const offsetX = event_move.clientX - startPosition.x,
offsetY = event_move.clientY - startPosition.y;
console.log(offsetX,offsetY)
//修改弹框位置
this.$refs.infoBox.style.left = `${currentPosition.x + offsetX}px`;
this.$refs.infoBox.style.top = `${currentPosition.y + offsetY}px`;
})
//注册鼠标抬起事件
document.addEventListener("mouseup",()=>{
this.isMove = false;
})
},
mousemoveHandler() {
},
mouseUpHandler() {
}
}
}
</script>
<style lang="less" scoped>
.info-box {
// .box-size(400px,300px);
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
background-color: @base-box-bgColor;
border: 1px solid #3374ac;
z-index: 999999;
.nav {
padding: 5px 10px;
height: 35px;
background: @base-bg-color;
.flex-layout('row');
justify-content: space-between;
.title {
user-select: none; //禁止选中标题文字
padding: 0px 5px;
font-family: "AliMaMa";
font-style: italic;
font-size: 18px;
color: #cee9f5;
background-image: linear-gradient(to top, #00C6FF, #8AFFD2);
/* 线性渐变背景,方向向上 */
-webkit-background-clip: text;
/* 背景被裁剪成文字的前景色 */
-webkit-text-fill-color: transparent;
/* 文字填充颜色变透明 */
}
.close {
font-size: 20px;
cursor: pointer;
&:hover {
color: rgb(0, 201, 252);
}
}
}
}
</style>
使用示例如下,
<!--
* @Description:
* @Author: Xwd
* @Date: 2023-02-15 22:26:06
* @LastEditors: Xwd
* @LastEditTime: 2023-02-18 21:08:26
-->
<template>
<div id="app">
<InfoBox/>
<router-view/>
</div>
</template>
<script>
//导入可拖拽弹框组件
import InfoBox from '@/layout/common/InfoBox.vue'
export default {
name:"App",
components:{
InfoBox
}
}
</script>
<style lang="less">
#app {
font-family: Avenir, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
.box-size(100vw,100vh);
}
</style>
本文转载自: https://blog.csdn.net/weixin_43524214/article/details/129104717
版权归原作者 是席木木啊 所有, 如有侵权,请联系我们删除。
版权归原作者 是席木木啊 所有, 如有侵权,请联系我们删除。