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

5 篇文章 0 订阅
2 篇文章 0 订阅

效果:点击观看

布局:

      <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
          }
        }
      }
    }
  })

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值