📒 背景
最近项目中需要制作一个拖拽弹窗的交互(如下图展示),今天分享一下这个组件功能。希望能抛砖引玉,给大家带来启发。
🔍需求功能
1.点击打开,控制弹窗标题名称;
2.拖拽在浏览器范围内移动;
3.点击×可关闭;
👣设计开发
先说一下我的开发环境版本:
node: v11.3.0
npm: 6.4.1
vue:2.5.11
如果不是以上版本也没关系,今日分享的思路,相信你可以自己造出来~
首先是弹框,用html+css画出来,vue中控制显示隐藏v-show或v-if:
<div v-if="visible" class="my_dialog" id="dialogbig">
<div class="my_dialog_box" id="my_dialog_box" v-drag >
<div class="my_dialog_title">
{{showTitle}}
<span class="my_dialog_close" @click="cancel"></span>
</div>
<!-- 内容 -->
<div class="my_dialog_content" id="content_box" >
<slot></slot>
</div>
</div>
</div>
然后是其中v-drag绑定directives自定义指令:
directives: {
drag: {
inserted: function (el, binding, vnode) {
vnode = vnode.elm
let boxdom = document.getElementById('dialogbig');
let bigdom = document.getElementById('my_dialog_box');
el.onmousedown = ((event) => {
if (event.target.className !== "my_dialog_title") {
return
}
// (clientX, clientY)点击位置距离当前可视区域的坐标(x,y)
// offsetLeft, offsetTop 距离上层或父级的左边距和上边距
// 获取鼠标在弹窗中的位置
let mouseX = event.clientX - vnode.offsetLeft
let mouseY = event.clientY - vnode.offsetTop
let initClientX = event.clientX;
// 绑定移动和停止函数
document.onmousemove = ((event) => {
let left, top
// 获取新的鼠标位置(event.clientX, event.clientY)
// 弹窗应该在的位置(left, top)
left = event.clientX - mouseX
top = event.clientY - mouseY
let changeLeft;
changeLeft = event.clientX - initClientX;
let offsetLeft = boxdom.offsetLeft;
// offsetWidth、offsetHeight 当前元素的宽度
// innerWidth、innerHeight 浏览器可视区的宽度和高度
// 获取弹窗在页面中距X轴的最小、最大 位置
let minX = -vnode.offsetWidth / 2 + bigdom.offsetWidth
let maxX = window.innerWidth + vnode.offsetWidth / 2 - bigdom.offsetWidth
if (left <= minX) {
left = minX
} else if (left >= maxX) {
left = maxX
}
// 获取弹窗在页面中距Y轴的最小、最大 位置
let minY = vnode.offsetHeight / 2
let maxY =window.innerHeight + vnode.offsetHeight / 2 - bigdom.offsetHeight
if (top <= minY) {
top = minY
} else if (top >= maxY) {
top = maxY
}
// 赋值移动
vnode.style.left = left + 'px'
vnode.style.top = top + 'px'
//boxdom.style.left = offsetLeft + changeLeft +'px'
/* boxdom.style.top = top + 'px'*/
})
document.onmouseup = (() => {
document.onmousemove = document.onmouseup = null
})
})
window.onresize = (() => {
vnode.style.left = "50%"
vnode.style.top = "50%"
})
}
},
}
其他页面调用:
<button @click="isShow = true">打开</button>
<dragDialog :visible="isShow" :showTitle="title" @confirm="onConfirm" @cancel="onCancel">
<div class="text">我是弹框里的内容,可以随便放哦</div>
</dragDialog>
更多逻辑代码欢迎体验组件--mycomponentsvue
npm install mycomponentsvue@0.0.18
import mycomponents from 'mycomponentsvue'
Vue.use(mycomponents)
<dragDialog :visible="isShow" :showTitle="title" @confirm="onConfirm" @cancel="onCancel">
<div class="text">我是弹框里的内容,可以随便放哦</div>
</dragDialog>
本组件只用于学习交流哈!所以名字起的比较随意!~
🚀写在最后
如果本文中有bug、逻辑错误,或者您有更好的优化方案欢迎评论联系我哦!~关注我持续分享日常工作中的组件设计和学习分享,一起进步加油!