前端js、javascript 鼠标 框选 文件 功能

一、DEMO

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>selection</title>
  <style>
    * {
      padding: 0px;
      margin: 0px;
      list-style: none;
    }
    html,body { height: 100%; width: 100%; overflow: hidden; }
    #root {
      height: 100%;
      background: #000;
      overflow-y: auto;
      overflow-x: hidden;
    }
    ul li {
      margin: 10px;
      border: #ccc solid 1px;
      display: inline-block;
      width: 200px;
      height: 200px;
      text-align: center;
      line-height: 200px;
      color: #fff;
    }
    /* 框选盒子样式 */
    .tempDiv {
      border:1px dashed #fff;
      background:#fff;
      position:absolute;
      width:0;
      height:0;
      opacity:0.5;
      pointer-events: none;
    }
  </style>
  <script  src="selection.js"></script>
</head>
<body>
  <div id="root">
    <ul class="oul">
    </ul>
  </div>
  <script>
    // 创建 元素
    const oul = document.querySelector('.oul')
    const map = new Map()
    Array(50).fill().forEach((item, index) => {
      const oli = document.createElement('li')
      const key = index + 1
      oli.setAttribute('data-id', key)
      oli.classList.add('target-node')
      oli.innerText = key
      map.set(key + '', oli)
      oul.appendChild(oli)
    })
    // 调用函数
    selection({
      root: document.querySelector('#root'), // 盒子
      target: '.target-node', // 框选元素类名
      dataId: 'data-id', // 框选元素 data-xxx
      callBack: (ids) => { // 框选元素回调 优先 dataId || Element
        ids.forEach(id => {
          const oli = map.get(id)
          oli.style.borderColor = 'red'
        })
      }
    })
  </script>
</body>
</html>

二、selection.js

// 默认配置
const defaults = {
  root: document,
  target: '.target-node',
  dataId: 'data-id'
}

// 事件阻止
function clearEventBubble(evt) { 
  if (evt.stopPropagation) 
    evt.stopPropagation(); 
  else 
    evt.cancelBubble = true; 
  if (evt.preventDefault) 
    evt.preventDefault(); 
  else 
    evt.returnValue = false; 
}

// ---------------- 关键算法 ---------------------
function computed (pos, option) {
  const Rect = option.root.getBoundingClientRect()
  const targetList = Array.from(document.querySelectorAll(option.target))
  const {x,y,w,h} = pos
  let ids = []
  const scrollTop = option.root.scrollTop
  const scrollLeft = option.root.scrollLeft
  targetList.forEach(node => {
    const nodeRect = node.getBoundingClientRect()
    let sleft = nodeRect.left + scrollLeft - Rect.left + node.offsetWidth
    let sTop = nodeRect.top + scrollTop - Rect.top + node.offsetHeight
    let offsetLeft = nodeRect.left - Rect.left + scrollLeft
    let offsetTop = nodeRect.top - Rect.top + scrollTop
    if (sleft > x && sTop > y && offsetLeft < x + w && offsetTop < y + h) {
      ids.push(node.getAttribute(option.dataId) || node)
      return true
    } else {
      return false
    }
  })
  option.callBack && option.callBack(ids)
}
const selection = function (option = {}) {
  for (let key in defaults) {
    if (!option.hasOwnProperty(key)) {
      option[key] = defaults[key]
    }
  }
  const Root = option.root
  Root.onmousedown = function (e) {
    if (e.button !== 0) return false
    const Rect = Root.getBoundingClientRect()
    var posx = e.clientX - Rect.left + Root.scrollLeft
    var posy = e.clientY - Rect.top + Root.scrollTop
    var div = document.createElement('div')
    div.className = 'tempDiv'
    div.style.left = posx + 'px'
    div.style.top = posy + 'px'
    Root.style.position = 'relative'
    Root.appendChild(div);
    clearEventBubble(e)
    Root.onmousemove = function(ev){
      const clientX = ev.clientX - Rect.left
      const clientY = ev.clientY - Rect.top
      const left = Math.min(clientX + Root.scrollLeft, posx)
      const top = Math.min(posy, clientY + Root.scrollTop)
      const width =  Math.abs(posx - clientX + Root.scrollLeft)
      const height = Math.abs(posy - clientY - Root.scrollTop)
      div.style.left = left+ 'px'
      div.style.top = top + 'px'
      div.style.width = width + 'px'
      div.style.height = height + 'px'
      if (width < 5 && height < 5 ) return false
      computed({
        x: left,
        y: top,
        w: width,
        h: height
      }, option)
      clearEventBubble(ev)
    }
    document.onmouseup = function(){
      Array.from(document.querySelectorAll('.tempDiv')).forEach(node => {
        node.remove()
      })
      Root.style.position = ''
      Root.onmousemove = null
      document.onmouseup = null
    }
  }
}

// export default selection

三、CSS

.tempDiv {
      border:1px dashed #fff;
      background:#fff;
      position:absolute;
      width:0;
      height:0;
      opacity:0.5;
      pointer-events: none;
    }

四、使用 

selection({
      root: document.querySelector('#root'), // 盒子
      target: '.target-node', // 框选元素类名
      dataId: 'data-id', // 框选元素 data-xxx
      callBack: (ids) => { // 框选元素回调 优先 dataId || Element
        ids.forEach(id => {
          const oli = map.get(id)
          oli.style.borderColor = 'red'
        })
      }
    })

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值