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

html+js+css实现一个圆形滑块,可以拖动,可以点击,先看效果再讲原理,最后附上源码:
html+js+css实现一个圆形滑块_第1张图片
产品经理设计了这样一个需求,通过拖动圆形滑块实现时间的设置功能,虽然看着有点复杂,但是确实有点复杂。

实现思路

需求分析:

  • 一个圆盘,一个滑块;

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

  • 同步保存滑块的值

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

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

当点击的位置位于x轴上方时,angle小于零,位于x轴下方时,angle大于零
html+js+css实现一个圆形滑块_第2张图片
最后根据这个angle,就可以获取一个相对于这个圆形360°的百分比,配合设置的最大值和最小值计算出当前滑块的值。

代码实现

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

DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Titletitle>
  <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 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>

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

你可能感兴趣的:(html,js,css,javascript,html,css,圆形,滑块)