背景介绍
项目当中弹框的地方比较多,应用户反馈,弹框的填写可能需要参考前面的页面,所以需要将弹框变为可拖动,尽量能看后面的内容。
比如在表格录入新增行的时候要参考下前面行的数据:
怎么做
计划写一个minxin的文件,混入到elementui的dialog中,在他的钩子函数中对dialog添加拖动事件,从而实现。
先上整体代码
编写minxin文件
export default ElementUI => {
ElementUI.Dialog.mixins[ElementUI.Dialog.mixins.length] = {
mounted() {
let el = this.$el; // dialog的dom
const dialogHeaderEl = el.querySelector(".el-dialog__header"); // dialog的头部,用来拖动
const dragDom = el.querySelector(".el-dialog"); // 用来获取位置
// 先增加一点拖动样式
dialogHeaderEl.style.cssText += ";cursor:move;";
// 获取原有属性 ie dom元素.currentStyle 火狐谷歌 window.getComputedStyle(dom元素, null);
const sty = (function () {
if (window.document.currentStyle) {
return (dom, attr) => dom.currentStyle[attr];
} else {
return (dom, attr) => getComputedStyle(dom, false)[attr];
}
})();
// 添加拖动事件
dialogHeaderEl.onmousedown = e => {
// 注:需要对offsetTop,clientWidth,scrollTop等位置相关属性有了解
// 鼠标按下,计算当前元素距离可视区的距离
const disX = e.clientX - dialogHeaderEl.offsetLeft; // 相对dialog左上角的横向位置
const disY = e.clientY - dialogHeaderEl.offsetTop; // 相对dialog左上角的纵向位置
const screenWidth = document.body.clientWidth; // 可视区域宽度
const screenHeight = document.documentElement.clientHeight; // 可视区域高度(应为body高度,可某些环境下无法获取)
const dragDomWidth = dragDom.offsetWidth; // 对话框宽度
const dragDomheight = dragDom.offsetHeight; // 对话框高度
const minDragDomLeft = dragDom.offsetLeft; // 最小的left拖动距离 保证dialog全部能看见
const maxDragDomLeft = screenWidth - dragDom.offsetLeft - dragDomWidth - 30; // 最大的left拖动距离 多减30避免横向滚动条
const minDragDomTop = dragDom.offsetTop; // 最小的top拖动距离 保证dialog全部能看见
const maxDragDomTop = screenHeight - dragDom.offsetTop - dragDomheight; // 最大的top拖动距离
// 如果弹窗高度太高,禁止拖动
if (dragDomheight > document.documentElement.clientHeight) {
dialogHeaderEl.style.cursor = "default";
return;
}
// 获取dom的原有属性,获取到的值带px 正则匹配替换
let styL = sty(dragDom, "left");
let styT = sty(dragDom, "top");
styL = +styL.replace(/\px/g, "");
styT = +styT.replace(/\px/g, "");
document.onmousemove = function (e) {
// 通过事件委托,计算移动的距离 disx和disy是相对dialog左上角的距离
let left = e.clientX - disX;
let top = e.clientY - disY;
// 计算移动位置 边界处理 保证dialog一直在可视区域
if (-left > minDragDomLeft) {
left = -minDragDomLeft;
} else if (left > maxDragDomLeft) {
left = maxDragDomLeft;
}
if (-top > minDragDomTop) {
top = -minDragDomTop;
} else if (top > maxDragDomTop) {
top = maxDragDomTop;
}
// 移动当前元素
dragDom.style.cssText += `;left:${left + styL}px;top:${top + styT}px;`;
};
// 最后移除事件
document.onmouseup = function (e) {
document.onmousemove = null;
document.onmouseup = null;
};
return false;
};
},
beforeDestroy() {
// 销毁组件移除事件
this.$el.querySelector(".el-dialog__header").onmousedown = null;
}
};
};
在main.js中引入文件并使用
import ElementUI from "element-ui";
import dragDialog from "./mixins/dragDialog";
import "element-ui/lib/theme-chalk/index.css";
dragDialog(ElementUI); // 全局弹窗可以拖动
Vue.use(ElementUI);
主要位置说明
1.怎么直接在elementUI中混入
export default ElementUI => {
// 关键点
ElementUI.Dialog.mixins[ElementUI.Dialog.mixins.length] = {
// 这里写内容
}
2.添加拖动事件要有边界处理
要保证dialog永远在可视区域内部,具体为下面这段代码。
注:需要对offsetTop,clientTop,scrollTopd等有了解
// 计算移动位置 边界处理 保证dialog一直在可视区域
if (-left > minDragDomLeft) {
left = -minDragDomLeft;
} else if (left > maxDragDomLeft) {
left = maxDragDomLeft;
}
if (-top > minDragDomTop) {
top = -minDragDomTop;
} else if (top > maxDragDomTop) {
top = maxDragDomTop;
}
3.最后要移除事件
4.要看后面的内容,对应dialog的灰色蒙层就要覆盖
.v-modal {
background: transparent !important;
}
最终效果
dialog可拖动且一直在可视范围内