wyyl/public/vendor/vue/batch_select.js

100 lines
3.9 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// 自 https://blog.wy310.cn/2020/12/17/vue-drag-batch-select/ 修改
Vue.directive('batch-select', {
// 当被绑定的元素插入到 DOM 中时……
// inserted: (el, binding) => {}
componentUpdated: (el, binding) => {
// 设置被绑定元素el即上述的box的position为relative目的是让蓝色半透明遮罩area相对其定位
el.style.position = 'relative';
// 记录el在视窗中的位置elPos
const { x, y } = el.getBoundingClientRect()
const elPos = { x, y }
// 获取该指令调用者传递过来的参数className / selectArr 是选中的 index 要放的数组
// v-batch-select="{ className: '.el-checkbox', selectArr: [] }"
// 表示要使用鼠标框选类名为'.el-checkbox'的元素
const optionClassName = binding.value.className
const options = [].slice.call(el.querySelectorAll(optionClassName))
// 获取被框选对象们的x、y、width、height
const optionsXYWH = []
options.forEach(v => {
const obj = v.getBoundingClientRect()
optionsXYWH.push({
x: obj.x - elPos.x,
y: obj.y - elPos.y,
w: obj.width,
h: obj.height
})
})
// 创建一个div作为area区域注意定位是absolutevisibility初始值是hidden
const area = document.createElement('div')
area.style = 'position: absolute; border: 1px solid #409eff; background-color: rgba(64, 158, 255, 0.1); z-index: 10; visibility: hidden;'
area.className = 'area'
area.innerHTML = ''
el.appendChild(area)
el.onmousedown = (e) => {
// 获取鼠标按下时相对box的坐标
const startX = e.clientX - elPos.x
const startY = e.clientY - elPos.y
// 判断鼠标按下后是否发生移动的标识
let hasMove = false
document.onmousemove = (e) => {
hasMove = true
binding.value.setSelectStatus(true)
// 显示area
area.style.visibility = 'visible'
// 获取鼠标移动过程中指针的实时位置
const endX = e.clientX - elPos.x
const endY = e.clientY - elPos.y
// 这里使用绝对值是为了兼容鼠标从各个方向框选的情况
const width = Math.abs(endX - startX)
const height = Math.abs(endY - startY)
// 根据初始位置和实时位置计算出area的left、top、width、height
const left = Math.min(startX, endX)
const top = Math.min(startY, endY)
// 实时绘制
area.style.left = `${left}px`
area.style.top = `${top}px`
area.style.width = `${width}px`
area.style.height = `${height}px`
const areaTop = parseInt(top)
const areaRight = parseInt(left) + parseInt(width)
const areaBottom = parseInt(top) + parseInt(height)
const areaLeft = parseInt(left)
binding.value.selectImageIndex.length = 0
optionsXYWH.forEach((v, i) => {
const optionTop = v.y
const optionRight = v.x + v.w
const optionBottom = v.y + v.h
const optionLeft = v.x
if (!(areaTop > optionBottom || areaRight < optionLeft || areaBottom < optionTop || areaLeft > optionRight)) {
// 该指令的调用者可以监听到selectIdxs的变化
binding.value.selectImageIndex.push(i)
}
})
}
document.onmouseup = (e) => {
document.onmousemove = document.onmouseup = null
if (hasMove) {
// 鼠标抬起时,如果之前发生过移动,则执行碰撞检测
const { left, top, width, height } = area.style
setTimeout(() => {
binding.value.setSelectStatus(false)
}, 100);
}
// 恢复以下数据
hasMove = false
area.style.visibility = 'hidden'
area.style.left = 0
area.style.top = 0
area.style.width = 0
area.style.height = 0
return false
}
}
},
// update: (el, binding) => {}
})