Vue.directive(‘dragx’,{
inserted:function(el,binding,vnode,oldVnode){
// 默认参数
let defaultOpts = {
//可以拉伸 w向左 n向上 e向右 s向下 ne右上 sw左下 se右下 nw左上 all就代表全部
dragDirection:‘n, e, s, w, ne, se, sw, nw, all’,
dragContainerId:’’, //在哪个容器内可以移动 需要填ID
dragBarClass:’’, // 类选择器 希望按哪里进行拖拽就把那个类名字填上
resizeEdge:10,
canDrag:true,//是否可以移动 默认可以
canResize:true,//是否可以改变大小 默认可以
minWidth:0,//最小宽度
minHeight:0,//最小高度
maxWidth:0,//最大拉伸至多少时会恢复最小宽度 默认0 即不恢复
maxHeight:0,//最大拉伸至多少时会恢复最小高度
previousId:’’,//绑定元素的上一个id
nextId:’’,//绑定元素的下一个id 一般填这个 如果他是第一个元素 则填上一个的id
scrollDiv:false,//是否是滚动悬浮元素 默认不是
clickId:’’,//点击哪个按钮会让他回到原来位置
leftDrag:true,
rightDrag:true,
topDrag:true,
bottomDrag:true
};
let isMove = false;
binding.value = binding.value || {};
let cfg = Object.assign({},defaultOpts,binding.value);
let stickStartPos = {mouseX:0,mouseY:0,x:0,y:0,w:0,h:0};
let divHeight = el.offsetHeight;//初始的高度 保证悬浮之后不变形
let divWidth = el.offsetWidth;//初始的宽度 保证悬浮之后不变形
let scroll = true;//保证滚动的判断方法只执行一次
let scrollBox = true;//保证盒子在不悬浮的时候 不会出现拖动拉伸图标
let drag = el.parentNode;//绑定盒子的父元素
let clickBox;
let scrollTop;
if(cfg.scrollDiv){
// 给当前元素绑定个私有变量,方便在unbind中可以解除事件监听
el.vueClickOutside = handleScroll;
//绑定滚动事件监听
window.addEventListener(‘scroll’,handleScroll,true);
scrollBox = false;
scrollTop = el.getBoundingClientRect().top - drag.getBoundingClientRect().top;
}
//滚动
function handleScroll(){
let constraintDom;
if(cfg.previousId !== ‘’ && cfg.nextId === ‘’){
constraintDom = document.querySelector("#" + cfg.previousId);
if(constraintDom.offsetHeight > constraintDom.getBoundingClientRect().top && el.getBoundingClientRect().top >= 0 && constraintDom.getBoundingClientRect().bottom - drag.getBoundingClientRect().top > 0){
el.style.position = ‘static’;
scrollBox = false;
el.style.width = divWidth + ‘px’;
el.style.height = divHeight + ‘px’;
scroll = true;
}
}
if(cfg.nextId !== ‘’){
constraintDom = document.querySelector("#" + cfg.nextId);
if(constraintDom.getBoundingClientRect().top - drag.getBoundingClientRect().top > 0){
el.style.position = ‘static’;
el.style.width = divWidth + ‘px’;
el.style.height = divHeight + ‘px’;
scroll = true;
scrollBox = false;
}
}
if(el.getBoundingClientRect().top - drag.getBoundingClientRect().top < 0 && scroll){
let box = document.querySelector("#" + cfg.dragContainerId);
let constraintRect = box.getBoundingClientRect();
el.style.position = ‘absolute’;
el.style.left = constraintRect.width - (divWidth + 10) + ‘px’;
el.style.top = constraintRect.height - (divHeight + 10) + ‘px’;
scrollBox = true;
el.style.width = divWidth + ‘px’;
el.style.height = divHeight + ‘px’;
scroll = false;
clickBox = document.querySelector("#" + cfg.clickId);
clickBox.addEventListener(‘click’,function(){
if(el.style.position === ‘absolute’){
drag.scrollTop = scrollTop;
}
el.style.position = ‘static’;
el.style.width = divWidth + ‘px’;
el.style.height = divHeight + ‘px’;
scroll = true;
scrollBox = false;
},{once:true});
}
}
//获取可以移动的最大范围
function calcResizeLimitation(data){
let minw = cfg.minWidth;
let minh = cfg.minHeight;
let width = data.width;
let height = data.height;
let bottom = data.bottom;
let top = data.top;
let left = data.left;
let right = data.right;
let parentLim = 0;
let limits = {
minLeft:parentLim,
maxLeft:left + (width - minw),
minRight:parentLim,
maxRight:right + (width - minw),
minTop:parentLim,
maxTop:top + (height - minh),
minBottom:parentLim,
maxBottom:bottom + (height - minh)
};
return limits;
}
// 获取目标元素 resize方向
function getDirection(e){
let el = e.currentTarget;
let dir = ‘’;
let rect = el.getBoundingClientRect();
let win = el.ownerDocument.defaultView;
let offset = {
top:rect.top + win.pageYOffset,
left:rect.left + win.pageXOffset,
right:rect.right + win.pageXOffset,
bottom:rect.bottom + win.pageYOffset
}
if(e.pageY > offset.top && e.pageY < offset.top + cfg.resizeEdge){
dir += ‘n’;
}else if(e.pageY < offset.bottom && e.pageY > offset.bottom - cfg.resizeEdge){
dir += ‘s’;
}
if(e.pageX > offset.left && e.pageX < offset.left + cfg.resizeEdge){
dir += ‘w’;
}else if(e.pageX < offset.right && e.pageX > offset.right - cfg.resizeEdge){
dir += ‘e’;
}
if(binding.value){
let directions = cfg.dragDirection.split(’,’);
for(let i = 0; i < directions.length; i++){
let handle = directions[i].replace(/(^\s*)|(\s*$)/g,’’);
if(handle === ‘all’ || handle === dir){
return dir;
}
}
}
return ‘’;
}
//解决拖动会选中文字的问题
document.onselectstart = function(){
return false;
};
el.onmousemove = function(e){
if(cfg.dragBarClass.length > 0 && e.target.classList.contains(cfg.dragBarClass) && cfg.canDrag && scrollBox){
el.style.cursor = ‘move’;
return;
}
let dir = getDirection(e);
if(dir !== ‘’ && cfg.canResize && scrollBox){
el.style.cursor = dir + ‘-resize’;
return;
}
el.style.cursor = ‘’;
}
el.onmouseleave = function(e){
el.style.cursor = ‘’;
}
el.onmousedown = function(e){
let content = document.querySelector("#" + cfg.dragContainerId);
let dragDiv = el;
dragDiv.startX = e.clientX - dragDiv.offsetLeft;
dragDiv.startY = e.clientY - dragDiv.offsetTop;
isMove = false;
if(cfg.dragBarClass.length > 0 && e.target.classList.contains(cfg.dragBarClass) && cfg.canDrag && scrollBox){
isMove = true;
document.body.style.cursor = ‘move’;
}
let style = window.getComputedStyle(el);
function getStyleNumValue(key){
return parseInt(style.getPropertyValue(key),10);
}
let rect = el.getBoundingClientRect();
let data = {
dragWidthMax:false,
dragHeightMax:false,
width:getStyleNumValue("width"),
height:getStyleNumValue("height"),
left:getStyleNumValue("left"),
top:getStyleNumValue("top"),
right:getStyleNumValue("right"),
bottom:getStyleNumValue("bottom"),
borderLeft:getStyleNumValue("border-left-width"),
borderTop:getStyleNumValue("border-top-width"),
borderRight:getStyleNumValue("border-right-width"),
borderBottom:getStyleNumValue("border-bottom-width"),
deltX:e.pageX - rect.left,
deltY:e.pageY - rect.top,
startX:rect.left,
startY:rect.top
};
let dragLeft = data.left;
let dragTop = data.top;
//在鼠标按下的时候进行赋值
stickStartPos.mouseX = typeof e.pageX !== 'undefined' ? e.pageX : e.touches[0].pageX;
stickStartPos.mouseY = typeof e.pageY !== 'undefined' ? e.pageY : e.touches[0].pageY;
stickStartPos.left = data.left;
stickStartPos.right = data.right;
stickStartPos.top = data.top;
stickStartPos.bottom = data.bottom;
let limits = calcResizeLimitation(data);
let dir = getDirection(e);
if(dir === '' && !isMove) return;
// 创建遮罩
let mask = document.createElement("div");
mask.style.cssText = "position:absolute;top:0px;bottom:0px;left:0px;right:0px;";
document.body.appendChild(mask);
document.onmousemove = function(edom){
let pageX = typeof edom.pageX !== 'undefined' ? edom.pageX : edom.touches[0].pageX;
let pageY = typeof edom.pageY !== 'undefined' ? edom.pageY : edom.touches[0].pageY;
let delta = {
x:(stickStartPos.mouseX - pageX) / 1,
y:(stickStartPos.mouseY - pageY) / 1
};
let newTop = stickStartPos.top - delta.y;
let newBottom = stickStartPos.bottom + delta.y;
let newLeft = stickStartPos.left - delta.x;
let newRight = stickStartPos.right + delta.x;
let constraintDom = document.querySelector("#" + cfg.dragContainerId);
let constraintRect = constraintDom.getBoundingClientRect();
if(cfg.canResize && scrollBox){
if(dir.indexOf("w") > -1 && cfg.leftDrag){
if(limits.minLeft !== null && newLeft < limits.minLeft){
newLeft = limits.minLeft;
}else if(limits.maxLeft !== null && limits.maxLeft < newLeft){
newLeft = limits.maxLeft;
}
data.left = newLeft;
data.width = constraintRect.width - data.left - data.right - data.borderLeft - data.borderRight;
if(data.width > cfg.maxWidth && cfg.maxWidth > 0){
data.width = cfg.minWidth;
data.left = dragLeft;
data.dragWidthMax = true;
cfg.leftDrag = false;
}
el.style.left = data.left + 'px';
el.style.width = data.width + 'px';
}
if(dir.indexOf("n") > -1 && cfg.topDrag){
if(limits.minTop !== null && newTop < limits.minTop){
newTop = limits.minTop;
}else if(limits.maxTop !== null && limits.maxTop < newTop){
newTop = limits.maxTop;
}
data.top = newTop;
data.height = constraintRect.height - data.top - data.bottom - data.borderTop - data.borderBottom;
if(data.height > cfg.maxHeight && cfg.maxHeight > 0){
data.height = cfg.minHeight;
data.top = dragTop;
data.dragHeightMax = true;
cfg.topDrag = false;
}
el.style.top = data.top + 'px';
el.style.height = data.height + 'px';
}
if(dir.indexOf("s") > -1 && cfg.bottomDrag){
if(limits.minBottom !== null && newBottom < limits.minBottom){
newBottom = limits.minBottom;
}else if(limits.maxBottom !== null && limits.maxBottom < newBottom){
newBottom = limits.maxBottom;
}
data.bottom = newBottom;
data.height = constraintRect.height - data.top - data.bottom - data.borderTop - data.borderBottom;
if(data.height > cfg.maxHeight && cfg.maxHeight > 0){
data.height = cfg.minHeight;
data.dragHeightMax = true;
cfg.bottomDrag = false;
}
el.style.height = data.height + 'px';
}
if(dir.indexOf("e") > -1 && cfg.rightDrag){
if(limits.minRight !== null && newRight < limits.minRight){
newRight = limits.minRight;
}else if(limits.maxRight !== null && limits.maxRight < newRight){
newRight = limits.maxRight;
}
data.right = newRight;
data.width = constraintRect.width - data.left - data.right - data.borderLeft - data.borderRight;
if(data.width > cfg.maxWidth && cfg.maxWidth > 0){
data.width = cfg.minWidth;
data.dragWidthMax = true;
cfg.rightDrag = false;
}
el.style.width = data.width + 'px';
}
}
// 处理组件 移动
if(isMove && cfg.canDrag && scrollBox){
dragDiv.style.left = edom.clientX - dragDiv.startX + "px";
dragDiv.style.top = edom.clientY - dragDiv.startY + "px";
data.left = edom.clientX - dragDiv.startX;
data.top = edom.clientY - dragDiv.startY;
if(edom.clientX - dragDiv.startX <= 0){
data.left = 0;
dragDiv.style.left = 0 + "px";
}
if(edom.clientY - dragDiv.startY <= 0){
data.top = 0;
dragDiv.style.top = 0 + "px";
}
if(edom.clientX - dragDiv.startX >= content.offsetWidth - dragDiv.offsetWidth){
data.left = content.offsetWidth - dragDiv.offsetWidth;
dragDiv.style.left = content.offsetWidth - dragDiv.offsetWidth + "px";
}
if(edom.clientY - dragDiv.startY >= content.offsetHeight - dragDiv.offsetHeight){
data.top = content.offsetHeight - (dragDiv.offsetHeight + 2);
dragDiv.style.top = content.offsetHeight - (dragDiv.offsetHeight + 2) + "px";
}
}
el.dispatchEvent(new CustomEvent('bindUpdate',{detail:data}));
}
document.onmouseup = function(e){
document.body.style.cursor = '';
document.onmousemove = null;
document.onmouseup = null;
isMove = false;
cfg.leftDrag = true;
cfg.rightDrag = true;
cfg.topDrag = true;
cfg.bottomDrag = true;
document.body.removeChild(mask);
}
document.body.style.cursor = dir + '-resize';
}
},
unbind:function(el,binding,vnode,oldVnode){
window.removeEventListener('scroll',el.__vueClickOutside__,true);
delete el.__vueClickOutside__;
}
});