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

在 Uniapp 中,内置组件的样式和行为是可以进行修改的。如果要修改 Slider 组件的样式和行为,可以使用以下方法: 1. 使用 scoped 样式来修改 Slider 组件的样式。在组件所在的页面或组件的样式中,使用 scoped 样式来定义 Slider 组件的样式,例如: ```css <template> <view> <slider class="my-slider" /> </view> </template> <style scoped> .my-slider { background-color: #f00; } </style> ``` 这样,Slider 组件的背景色就会变成红色。需要注意的是,scoped 样式只会对当前组件生效,不会影响其他组件和页面。 2. 使用 props 属性来修改 Slider 组件的属性。Slider 组件有多个属性可以进行修改,例如 value、min、max 等。可以在组件中使用 props 属性来修改这些属性,例如: ```vue <template> <view> <slider :value="50" :min="0" :max="100" /> </view> </template> ``` 这样,Slider 组件的初始值就会变成 50,最小值为 0,最大值为 100。 3. 使用事件来修改 Slider 组件的行为。Slider 组件有多个事件可以进行监听,例如 change、changing 等。可以在组件中使用 @change/@changing 等事件来监听 Slider 组件的变化,例如: ```vue <template> <view> <slider :value="50" @changing="handleChange" /> </view> </template> <script> export default { methods: { handleChange(e) { console.log(e.detail.value); }, }, }; </script> ``` 这样,每次 Slider 组件的值发生变化时,就会调用 handleChange 方法并输出当前的值。 通过以上方法,就可以对 Slider 组件进行样式和行为的修改。需要注意的是,如果要对其他内置组件进行修改,也可以使用类似的方法。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值