html+js+css实现一个圆形滑块

html+js+css实现一个圆形滑块,可以拖动,可以点击,先看效果再讲原理,最后附上源码:

产品经理设计了这样一个需求,通过拖动圆形滑块实现时间的设置功能,虽然看着有点复杂,但是确实有点复杂。

实现思路

需求分析:

  • 一个圆盘,一个滑块;

  • 以圆盘为圆心,点击圆盘任意位置或者拖动滑块,滑块会移动到指定位置;

  • 同步保存滑块的值

实现逻辑:

获取鼠标点击或者移动的位置到圆盘圆心水平x和垂直y的距离;

然后使用Math.atan2函数根据x和y计算出这个点到圆心这条线和x轴的角度angle,angle的范围为 -π 到 π;

当点击的位置位于x轴上方时,angle小于零,位于x轴下方时,angle大于零

最后根据这个angle,就可以获取一个相对于这个圆形360°的百分比,配合设置的最大值和最小值计算出当前滑块的值。

代码实现

这里就不说太多废话了,直接把完整代码放下面,注释很清楚😉

html 复制代码
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
  <style>
    #container{
      width: 200px;
      height: 200px;
      border-radius: 100px;
      background: aqua;
      margin: 50px;
    }
    #bar{
      width: 20px;
      height: 20px;
      background: red;
      border-radius: 10px;
      pointer-events: none;
      text-align: center;
      font-size: 12px;
      line-height: 20px;
      color: white;
    }
  </style>
</head>
<body>
<div id="container">
  <!--    <div class="track"></div>-->
  <div id="bar"></div>
</div>

<script>
  // 滑块容器
  const slider = document.getElementById('container')
  // 滑块
  const bar = document.getElementById('bar')
  // 滑动轨道半径
  const radius = 100

  // 滑块的值,以及最小和最大
  let value = 50, min = 0, max = 100
  // 当前是否正在拖动
  let isDragging = false
  // 鼠标按下事件
  slider.addEventListener('mousedown', (event) => {
    event.preventDefault();
    // 开始拖动
    isDragging = true;
    // 监听鼠标移动事件
    slider.addEventListener('mousemove', handleMouseMove);
    // 鼠标松开事件
    slider.addEventListener('mouseup', endDrag);
    // 鼠标移出区域
    slider.addEventListener('mouseleave', endDrag);
  })

  // 处理鼠标移动事件
  const handleMouseMove = (event) => {

    if (isDragging) {
      updateValue(event)
    }
  }

  // 更新滑块数值
  const updateValue = event => {
    // 获取容器中心点
    const centerX = slider.offsetWidth / 2;
    const centerY = slider.offsetHeight / 2;
    // 鼠标位置到中心x和y方向的距离
    const deltaX = event.offsetX - centerX
    const deltaY = event.offsetY - centerY
    // 根据距离计算鼠标到中心点的角度,Math.atan2返回值为 -π 到 π ,导致滑动的位置时从圆形的最右端开始滑动的,所以用 + Math.PI/2处理一些初始位置
    let angle = Math.atan2(deltaY, deltaX) + Math.PI/2
    // 转换为角度 0-360
    let newValue = ((angle * 180) / Math.PI + 360) % 360;
    // 将360分段
    newValue = Math.round(newValue/3.6)*3.6
    // 根据百分比计算滑块的值
    newValue = (newValue / 360) * (max - min) + min;
    if (newValue <= min) {
      newValue = max;
    } else if (newValue > max) {
      newValue = max;
    }

    value = newValue.toFixed(0)
    bar.innerText = value
    // 更新滑块位置
    updatePosition()
  }

  // 鼠标点击时也更新滑块的值
  slider.addEventListener('click', updateValue);
  // 更新滑块位置
  const updatePosition = () => {
    // 根据值计算角度,然后计算出滑块的位置
    let angle = ((value - min) / (max - min)) * 360 - 90;
    const x = Math.cos((angle * Math.PI) / 180) * radius + 90;
    const y = Math.sin((angle * Math.PI) / 180) * radius + 90;

    bar.style.transform = `translate(${x}px, ${y}px)`
  }
  // 根据默认值更新滑块位置
  bar.innerText = value
  updatePosition()
  // 结束拖动
  const endDrag = () => {
    isDragging = false;
    // 移除相关监听事件
    slider.removeEventListener('mousemove', handleMouseMove);
    slider.removeEventListener('mouseup', endDrag);
    slider.removeEventListener('mouseleave', endDrag);
  }


</script>
</body>
</html>

大家有任何问题都可以在评论区留言交流,相互学习!

相关推荐
Myli_ing27 分钟前
HTML的自动定义倒计时,这个配色存一下
前端·javascript·html
I_Am_Me_1 小时前
【JavaEE进阶】 JavaScript
开发语言·javascript·ecmascript
℘团子এ1 小时前
vue3中如何上传文件到腾讯云的桶(cosbrowser)
前端·javascript·腾讯云
学习前端的小z1 小时前
【前端】深入理解 JavaScript 逻辑运算符的优先级与短路求值机制
开发语言·前端·javascript
前端百草阁2 小时前
【TS简单上手,快速入门教程】————适合零基础
javascript·typescript
彭世瑜2 小时前
ts: TypeScript跳过检查/忽略类型检查
前端·javascript·typescript
FØund4042 小时前
antd form.setFieldsValue问题总结
前端·react.js·typescript·html
Backstroke fish2 小时前
Token刷新机制
前端·javascript·vue.js·typescript·vue
zwjapple2 小时前
typescript里面正则的使用
开发语言·javascript·正则表达式
小五Five2 小时前
TypeScript项目中Axios的封装
开发语言·前端·javascript