// 自 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区域，注意定位是absolute，visibility初始值是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) => {}
})