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>

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

相关推荐
托尼沙滩裤25 分钟前
【js面试题】js的数据结构
前端·javascript·数据结构
朝阳391 小时前
vue3【实战】来回拖拽放置图片
javascript·vue.js
不如喫茶去1 小时前
VUE自定义新增、复制、删除dom元素
前端·javascript·vue.js
阿垚啊1 小时前
vue事件参数
前端·javascript·vue.js
加仑小铁1 小时前
【区分vue2和vue3下的element UI Dialog 对话框组件,分别详细介绍属性,事件,方法如何使用,并举例】
javascript·vue.js·ui
Simaoya3 小时前
vue判断元素滚动到底部后加载更多
前端·javascript·vue.js
头顶一只喵喵3 小时前
Vue基础知识:Vue3.3出现的defineOptions,如何使用,解决了什么问题?
前端·javascript·vue.js·vue3
掘金安东尼3 小时前
上周前端发生哪些新鲜事儿?#370
前端·javascript·面试
黑色的糖果4 小时前
echarts横向立体3D柱状图
前端·javascript·echarts
茶卡盐佑星_4 小时前
vue3.0所采用的composition Api与vue2.x使用的Option Api有什么区别
前端·javascript·vue.js