/**
* 拖拽指令
* 使用方式:
* v-move="{ moveDomClass: 'el-dialog', moveOrigin: 'el-dialog__header', moveOut: false, moveOpen:true,notMoveOrigin }"
* moveDomClass:需要拖拽的节点类名,默认为v-move绑定的节点。
* moveOrigin:节点可拖拽的区域类名,默认为v-move绑定的节点。
* moveOut:拖拽的节点是否可以托出视口。默认false,不能
* moveStop: 默认为空,若是把 moveStop 改成 true 那么节点就拖拽不动了
* notMoveOrigin: 默认为空 ,若设置 那么就会排除 el-dialog__header 内同类名的节点,点击它是不能启动拖拽的
*/
/**节流 */
const rafThrottle = (callBack?) => {
let locked = false
return function(...args) {
if (locked) return
locked = true
window.requestAnimationFrame(_ => {
callBack.apply(this, args)
locked = false
})
}
}
/** 获取偏移距离 */
function getMoveSpace(moveDom, moveOut, space, type) {
if (!moveOut) {
const width = moveDom.clientWidth
const height = moveDom.clientHeight
const { clientWidth, clientHeight } = document.body
if (space < 0) return 0
if (type === 'y' && space + height > clientHeight) return clientHeight - height
if (type === 'x' && space + width > clientWidth) return clientWidth - width
}
return space
}
export default {
inserted: (el, binding, vnode) => {
el.bindValue = binding.value
const { moveDomClass, moveOrigin, moveOut, notMoveOrigin } = binding.value
let moveDom = el
let moveOriginDom = el
let notMoveOriginDom
let offsetX, offsetY
if (moveDomClass) moveDom = el.querySelector(`.${moveDomClass}`)
if (moveOrigin) moveOriginDom = el.querySelector(`.${moveOrigin}`)
if (notMoveOrigin) notMoveOriginDom = el.querySelector(`.${notMoveOrigin}`)
moveOriginDom?.style?.setProperty?.('cursor', 'grab')
const userSelect = document.body.style['user-select']
// 鼠标按下
function onmousedown(e) {
if (!moveOriginDom?.contains?.(e.target) || notMoveOriginDom?.contains(e.target)) return
const parentRect = moveDom.getBoundingClientRect()
offsetX = e.pageX - parentRect.left
offsetY = e.pageY - parentRect.top
// 绑定鼠标移动
window.addEventListener('mousemove', onmousemove)
}
// 鼠标松开
function onmouseup(e) {
// 移除鼠标移动
window.removeEventListener('mousemove', onmousemove)
document.body.style.setProperty('user-select', userSelect || 'auto')
}
// 鼠标移动
const onmousemove = rafThrottle(e => {
if (el.bindValue?.moveStop) {
window.removeEventListener('mousemove', onmousemove)
return
}
const { pageX, pageY } = e
const { clientWidth, clientHeight } = document.body
const moveX = pageX - offsetX
const moveY = pageY - offsetY
// 移出屏幕
if (pageX < 0 || pageY < 0 || pageX > clientWidth || pageY > clientHeight) return
document.body.style.setProperty('user-select', 'none')
moveDom.style.setProperty('margin', 0)
moveDom.style.setProperty('left', `${getMoveSpace(moveDom, moveOut, moveX, 'x')}px`)
moveDom.style.setProperty('top', `${getMoveSpace(moveDom, moveOut, moveY, 'y')}px`)
moveDom.style.setProperty('position', 'fixed')
})
// 绑定鼠标按下
moveDom.addEventListener('mousedown', onmousedown)
// 绑定鼠标松开
window.addEventListener('mouseup', onmouseup)
},
update: (el, binding, vnode) => {
el.bindValue = binding.value
},
}
使用方式:
<template>
<el-dialog
v-move="{ moveDomClass: 'el-dialog', moveOrigin: 'el-dialog__header', notMoveOrigin: 'el-dialog__headerbtn', moveOut: false, moveOpen: moveOpen }"
class="sg-dialog publicity-original__dialog"
title="查看原文-处罚结果信息公开内容"
visible
:close-on-click-modal="false"
@close="cancel"
:modal="false"
>
<div>
{{ publicityContentInitText }}
</div>
</el-dialog>
</template>