欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

JS手写slider组件(缩放拖拽)

程序员文章站 2022-04-21 21:38:26
...

效果:点击观看

布局:

      <div id='box' className='drag-bar-box'>
        <div id='drag' className='drag-bar'>
          <div id='scaleleft' className='drag-block-left'></div>
          <div id='scaleright' className='drag-block-right'></div>
        </div>
      </div>

样式:

.drag-bar-box {
  position: relative;
  width: calc(100% - 44px);
  height: 16px;
  margin-left: 44px;
  border: 1px solid #D9D9D9;
  border-radius: 3px;
}
.drag-bar-box > .drag-bar {
  position: relative;
  width: 100%;
  height: 100%;
  cursor: move;
  background: #F5F7FA;
}
.drag-bar-box > .drag-bar .drag-block-left,
.drag-bar-box > .drag-bar .drag-block-right {
  position: absolute;
  bottom: -1px;
  width: 6px;
  height: 16px;
  background: #fff;
  border: 1px solid #C1C9D5;
  overflow: hidden;
  cursor: w-resize;
}
.drag-bar-box > .drag-bar .drag-block-left {
  left: -1px;
}
.drag-bar-box > .drag-bar .drag-block-right {
  right: -1px;
}

js:

  useEffect(() => {
    drag()
    function drag () {
      const box = document.getElementById('box')
      const drag = document.getElementById('drag')
      const scaleRight = document.getElementById('scaleright')
      const scaleleft = document.getElementById('scaleleft')
      dragTool(drag)
      scaleRightTool(drag, scaleRight, box)
      scaleLeftTool(drag, scaleleft, box)

      function computedTime () {
        // 滑块范围的总宽度
        const boxWidth = box.offsetWidth - 2 // 1230
        // 灰色区域的宽度
        const dragWidth = drag.style.width // 75.8721%
        // 灰色区域距离左边的距离
        const dragLeft = drag.offsetLeft // 203

        let lineTotalTime = lineEndTime - lineStartTime
        // 滑块所在的位置代表的结束、开始时间 parseInt改为Math.ceil(避免计算相差1s导致时序图小绿点丢失问题)
        let dragStartTime = Math.ceil(
          lineStartTime + lineTotalTime * (dragLeft / boxWidth)
        )
        let dragEndTime = Math.ceil(
          dragStartTime + lineTotalTime * (dragWidth.split('%')[0] / 100)
        )
        props.updataTime({
          startTime: dragStartTime,
          endTime: dragEndTime
        })
      }
      // 拖拽方法
      function dragTool (node) {
        drag.onmousedown = function (ev) {
          // 浏览器兼容处理
          let e = ev || window.event
          // 鼠标按下记录相对位置
          // 水平方向都距离 = 当前鼠标左边的距离 - 被拖拽元素距离左边的距离
          let offsetX = e.clientX - node.offsetLeft
          // 垂直方向都距离 = 当前鼠标都上边的距离 - 被拖拽元素距离距离的距离
          let offsetY = e.clientY - node.offsetTop

          // 鼠标移动和被拖拽的元素是相对的 这里是鼠标拖拽的物体在整个页面上移动 所以
          // move加在document上
          document.onmousemove = function (ev) {
            // 当前鼠标的事件对象
            let e = ev || window.event
            // 定义 currentLeft  = 当前鼠标位置 - 距离左边的距离
            let currentLeft = e.clientX - offsetX
            // 定义 currentTop = 当前鼠标上边位置 - 距离上边的距离
            let currentTop = e.clientY - offsetY
            // 限制左出界 最左是 0
            if (currentLeft <= 0) {
              currentLeft = 0
            }
            // 当前窗口的宽 浏览器兼容
            const boxWidth = box.offsetWidth - 2
            // 限制右边出界 如果大于当前窗口的宽 那么就让它等于当前窗口的宽减去当前元素的offsetWidth 也就是留在原地
            if (currentLeft >= boxWidth - drag.offsetWidth) {
              currentLeft = boxWidth - drag.offsetWidth
            }
            // 设置上出界 最上边是 0
            if (currentTop <= 0) {
              currentTop = 0
            }
            // 当前窗口的高 浏览器兼容
            // 限制下边出界 如果大于当前窗口的高 减去 本身的高 那么就让它等于 当前窗口的高减去本身的高
            if (currentTop >= 0) {
              currentTop = 0
            }
            // 当前被拖拽元素的 left 值 等于上面计算出的 currentLeft
            node.style.left = (currentLeft / boxWidth) * 100 + '%'
            setOldLeft(currentLeftCopy)
            setCurrentLeftCopy((currentLeft / boxWidth) * 100)
            // dragShadow.style.left = (currentLeft / boxWidth) * 100 + '%'
          }
        }
        // 监听点击时,设置新旧left为同一个值,防止调用接口
        document.onclick = function () {
          setOldLeft(currentLeftCopy)
          setCurrentLeftCopy(currentLeftCopy)
        }
        // 鼠标弹起取消拖拽 这里添加到 node 元素对象也可以的
        document.onmouseup = function () {
          document.onmousemove = null
          if (oldLeft !== currentLeftCopy) {
            computedTime()
          }
        }
        document.onmouseleave = function () {
          document.onmousemove = null
          if (oldLeft !== currentLeftCopy) {
            computedTime()
          }
        }
      }

      // 右边缩放
      function scaleRightTool (drag, scaleRight, box) {
        scaleRight.onmousedown = function (e) {
          // 阻止冒泡 避免缩放触发移动事件
          e.stopPropagation()
          // 取消事件的默认动作
          e.preventDefault()
          // 定义position
          let position = {
            w: drag.offsetWidth, // 被缩放元素的offsetWidth
            h: drag.offsetHeight, // 被缩放元素的offsetHeight
            x: e.clientX, // 当前窗口鼠标指针的水平坐标
            y: e.clientY // 当前窗口鼠标指针的垂直坐标
          }
          document.onmousemove = function (ev) {
            ev.preventDefault()
            // 设置最大缩放为30*30 Math.max取最大值
            let boxRealWidth = box.offsetWidth - 2
            const minvalue =
              type === 'det'
                ? boxRealWidth *
                  (hourToMs[detWindowText] / (lineEndTime - lineStartTime))
                : 10
            let w = Math.max(minvalue, ev.clientX - position.x + position.w)

            w =
              w >= boxRealWidth - drag.offsetLeft
                ? boxRealWidth - drag.offsetLeft
                : w
            drag.style.width = (w / boxRealWidth) * 100 + '%'
          }
          // 鼠标离开和抬起取消缩放
          document.onmouseup = function () {
            document.onmousemove = null
            document.onmouseup = null
            computedTime()
          }
          document.onmouseleave = function () {
            document.onmousemove = null
            document.onmouseup = null
          }
        }
      }
      // // 缩放-左边div
      function scaleLeftTool (drag, scaleleft, box) {
        scaleleft.onmousedown = function (e) {
          // 阻止冒泡 避免缩放触发移动事件
          e.stopPropagation()
          // 取消事件的默认动作
          e.preventDefault()
          // 定义position
          let position = {
            w: drag.offsetWidth, // 被缩放元素的offsetWidth
            h: drag.offsetHeight, // 被缩放元素的offsetHeight
            x: e.clientX, // 当前窗口鼠标指针的水平坐标
            y: e.clientY, // 当前窗口鼠标指针的垂直坐标
            r: drag.style.left.split('%')[0]
          }
          document.onmousemove = function (ev) {
            ev.preventDefault()
            // 设置最大缩放为70 Math.max取最大值
            let boxRealWidth = box.offsetWidth - 2
            const minvalue =
              type === 'det'
                ? boxRealWidth *
                  (hourToMs[detWindowText] / (lineEndTime - lineStartTime))
                : 10
            let w = Math.max(minvalue, position.x - ev.clientX + position.w)
            // 挪动的距离
            // ev.clientX:鼠标距离屏幕左边缘的距离拖动时一直在变的
            // drag.offsetLeft 被缩放元素距离它的父级元素左边的距离 只能获取不能设置
            let copyw = position.x - ev.clientX
            // 设置left Math.max取最大值

            let l = Math.max(
              minvalue,
              (position.r / 100) * boxRealWidth - copyw
            )
            w = w >= boxRealWidth ? boxRealWidth : w

            drag.style.width = (w / boxRealWidth) * 100 + '%'
            l =
              drag.offsetLeft + drag.offsetWidth >= boxRealWidth
                ? boxRealWidth - w
                : l
            drag.style.left = (l / boxRealWidth) * 100 + '%'
            setOldLeft(currentLeftCopy)
            setCurrentLeftCopy((l / boxRealWidth) * 100)
          }
          // 鼠标离开和抬起取消缩放
          document.onmouseup = function () {
            document.onmousemove = null
            document.onmouseup = null
            computedTime()
          }
          document.onmouseleave = function () {
            document.onmousemove = null
            document.onmouseup = null
          }
        }
      }
    }
  })