标签:fixed 显示 rom path template 行操作 max v-model lse
在刚刚重构完的项目中使用到了element ui框架,踩了不少坑也学到了不少的东西。其中比较麻烦的是它的dialog弹窗组件是无法移动拖拽的,然而客户又强烈的要求一定要有这个功能,所以就自己写了个可拖拽的弹窗组件。虽然拖拽起来不是很流畅,但是也算是满足要求了。
主要的实现原理还是获取鼠标在div中的位置,获取位置后设置div的left和top来达到div跟随鼠标移动的效果。因为写的是vue,所以利用了vue的自定义指令来操作dom。
老实说,我经常被吐槽没有审美,设计的样式总是被喷。好在这次是dialog弹窗,网上有大把的参考样式。我大体参考了layer的弹窗做出了一个山寨弹窗。
html代码``` <template> <div class="m_showBox" :class="skin"> <div class="showBox_mask"></div> <div class="loading_wrap" v-if="buttonstatus === 1"></div> <div class="pop_box" id="pox-box" v-drag> <p class="pop_box_title"> {{title || "提示"}} <span class="pop_box_close" @click="cancel"></span> </p> <div class="pop_box_content"> <slot></slot> </div> <div class="pop_box_bottom"> <a href="javascript:;" class="cancel_btn" @click="cancel">{{canceltext || "取消"}}</a> <a href="javascript:;" class="confirm_btn" v-if="type === ‘confirm‘" :class="{widths: buttonstatus === 1}" @click="confirm"> <svg viewBox="25 25 50 50" class="u-circular" v-if="buttonstatus === 1"> <circle cx="50" cy="50" r="20" fill="none" class="path"></circle> </svg> <span :class="{‘marginLeft‘: buttonstatus === 1}">{{confirmtext || ‘确定‘}}</span> </a> </div> </div> </div> </template> ```
css代码太长放到github上了vueDrag.vue
效果图:
属性 | 描述 |
---|---|
skin | 用于控制弹窗的宽度(small, middle, large) |
title | 弹窗标题 |
type | 弹窗类型 |
confirmtext | 确认键文案 |
canceltext | 取消键文案 |
buttonstatus | 控制按钮加载效果 |
通过传入的props值来设置弹窗的样式和文案。
confirm和cancel自定义事件
定义自定义按钮事件,使用$emit触发。
通过vue自定义指令获取绑定的元素,在对DOM进行操作。关于更多vue自定义指令用法,移步自定义指令
事件 | 描述 |
---|---|
onmousedown | 鼠标按钮被按下。 |
onmousemove | 鼠标被移动。 |
onmouseup/td> | 鼠标按键被松开。 |
directives: {
drag: {
inserted: function (el, binding, vnode) {
vnode = vnode.elm;
el.onmousedown = ((event) => {
if (event.target.className !== "pop_box_title") {
return;
}
//获取鼠标在盒子中的位置
let mouseX = event.clientX - vnode.offsetLeft;
let mouseY = event.clientY - vnode.offsetTop;
//绑定移动和停止函数
document.onmousemove = ((event) => {
let left, top;
//获取新的鼠标位置对应下的盒子应该在的位置
left = event.clientX - mouseX;
top = event.clientY - mouseY;
//获取div在页面中X轴的最小最大位置
let minX = vnode.offsetWidth / 2;
let maxX = (window.innerWidth - vnode.offsetWidth / 2) - 10//去掉滚动条的宽度
if (left <= minX) {
left = minX;
} else if (left >= maxX) {
left = maxX;
}
//获取div在页面中Y轴的最大最小位置
let minY = vnode.offsetHeight / 2;
let maxY = (window.innerHeight - vnode.offsetHeight / 2);
if (top <= minY) {
top = minY;
} else if (top >= maxY) {
top = maxY;
}
//赋值移动
vnode.style.left = left + 'px';
vnode.style.top = top + 'px';
});
document.onmouseup = (() => {
document.onmousemove = document.onmouseup = null;
});
});
window.onresize = (() =>{
vnode.style.left = "50%";
vnode.style.top = "50%";
});
}
}
}
1、给弹窗绑定onmousedown事件,获取到鼠标在弹窗中的位置(以弹窗左上角为原点)。
2、document绑定onmousemove事件,获取当前的鼠标位置,当前鼠标位置减去鼠标在弹窗的相当位置即可得到此时弹窗应该处于的位置。然后在通过style设置弹窗的位置。
3、鼠标松开解绑document的鼠标事件。
注意点:
使用import引入
``` import vDrag from "./dragDiv.vue" ```控制弹窗的显示隐藏通过v-if绑定data里的数据即可。
``` <transition name="el-fade-in"> <v-drag v-if="isShow" :tilte="title" :type="type" @confirm="confirmSubmit" @cancel="cancel" :buttonstatus="buttonstatus"> <el-form label-width="100px"> <el-form-item label="用户名称:"> <el-input placeholder="请输入用户名" v-model="username"></el-input> </el-form-item> <el-form-item label="密码:"> <el-input placeholder="请输入密码" v-model="password"></el-input> </el-form-item> </el-form> </v-drag> </transition> ``` 关于这个组件我觉得还有很多优化的地方,望各位大佬给出意见。
原文地址:https://segmentfault.com/a/1190000017300044
标签:fixed 显示 rom path template 行操作 max v-model lse
原文地址:https://www.cnblogs.com/datiangou/p/10121682.html