可拖拽指令
该文章用于封装一个指令用于对一个元素(div)进行不同方向的拖拽
dragX.js
代码如下:
export default (el, binding) => {// 默认参数let defaultOpts = {dragDirection: 'n, e, s, w, ne, se, sw, nw, all',dragContainerId: '', //dragBarClass: '', // 类选择器resizeEdge: 10,dirctDom: true,canDrag:true,canResize:true,};let isMove = false;binding.value = binding.value || {};let cfg = Object.assign({}, defaultOpts, binding.value);// 获取目标元素 resize方向function getDirection(e) {let elTar = e.currentTarget;let dir = '';let rect = elTar.getBoundingClientRect();let win = elTar.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 direction of directions) {let handle = direction.replace(/(^\s*)|(\s*$)/g, '');if (handle === 'all' || handle === dir) {return dir;}}}return '';}// 设置约束范围function setConstraint(data) {if (cfg.dragContainerId) {let constraintDom = document.querySelector("#" + cfg.dragContainerId);let constraintRect = constraintDom.getBoundingClientRect();if (data.left <= 0) data.left = 0;if (data.top <= 0) data.top = 0;if (data.top + data.height+data.borderTop+data.borderBottom >= constraintRect.height) data.top = constraintRect.height - data.height-data.borderTop-data.borderBottom;if (data.left + data.width+data.borderLeft+data.borderRight > constraintRect.width) data.left = constraintRect.width - data.width-data.borderLeft-data.borderRight;}}el.onmousemove = function (e) {if (cfg.dragBarClass.length > 0 && e.target.classList.contains(cfg.dragBarClass)&&cfg.canDrag) {el.style.cursor = 'move';return;}let dir = getDirection(e);if (dir !== '') {el.style.cursor = dir + '-resize'; return;}el.style.cursor = '';}el.onmouseleave = function () {el.style.cursor = '';}el.onmousedown = function (e) {isMove = false;if (cfg.dragBarClass.length > 0 && e.target.classList.contains(cfg.dragBarClass)) {isMove = true;document.body.style.cursor = 'move';}const style = window.getComputedStyle(el);const getStyleNumValue = key => parseInt(style.getPropertyValue(key), 10);const rect = el.getBoundingClientRect();const data = {width: getStyleNumValue("width"),height: getStyleNumValue("height"),left: getStyleNumValue("left"),top: getStyleNumValue("top"),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};const dir = getDirection(e);if (dir === '' && !isMove) return;// 创建遮罩const mask = document.createElement("div");mask.style.cssText = "position:absolute;top:0;bottom:0;left:0;right:0;";document.body.appendChild(mask);document.onmousemove = function (edom) {// === 方向调整映射 ===const resizeActions = {e() {data.width = edom.pageX - data.startX + data.borderLeft + data.borderRight;},s() {data.height = edom.pageY - data.startY + data.borderBottom + data.borderTop;},n() {const deltheight = data.startY + data.borderBottom + data.borderTop - edom.pageY;data.height += deltheight;data.top -= deltheight;data.startY -= deltheight;},w() {const deltwidth = data.startX + data.borderLeft + data.borderRight - edom.pageX;data.width += deltwidth;data.left -= deltwidth;data.startX -= deltwidth;}};// 遍历执行对应方向Object.keys(resizeActions).forEach(key => {if (dir.includes(key)) {resizeActions[key]();}});// === 拖拽处理 ===if (isMove && cfg.canDrag) {const deltX = edom.pageX - data.startX - data.deltX;const deltY = edom.pageY - data.startY - data.deltY;const newLeft = (parseInt(getStyleNumValue("left") || '0', 10)) + deltX;const newTop = (parseInt(getStyleNumValue("top") || '0', 10)) + deltY;data.left = newLeft;data.top = newTop;data.startX += deltX;data.startY += deltY;setConstraint(data);}// === DOM 更新 ===unpdateDom(el, cfg, data)// 自定义事件通知el.dispatchEvent(new CustomEvent('bindUpdate', { detail: data }));};document.onmouseup = function () {document.body.style.cursor = '';document.onmousemove = null;document.onmouseup = null;isMove = false;if (mask.parentNode) {document.body.removeChild(mask);}};document.body.style.cursor = dir + '-resize';};
}
function unpdateDom(el, cfg, data) {if (cfg.dirctDom) {Object.assign(el.style, {width: cfg.canResize ? data.width + "px" : el.style.width,height: cfg.canResize ? data.height + "px" : el.style.height,left: cfg.canDrag ? data.left + "px" : el.style.left,top: cfg.canDrag ? data.top + "px" : el.style.top});
}
}
父组件使用的时候
<material-tree class="left" ref="materialTree" v-dragx="dragColumn" @bindUpdate="dragColumnUpdate":treeData="treeData" :menuList="menuList" @nodeClick="handleNodeClick" @operate="handleOperate"></material-tree>
dragColumnUpdate() {this.$refs.materialTree.style.height = '100%';},