主要内容有以下几点:
-
精确定位计算:
- 考虑了滑块本身的宽度(20px)
- 计算实际可滑动的宽度时减去了滑块宽度
- 添加了滑块中心点位置的计算
- 考虑了wrapper的padding值(10px)
-
进度条调整:
- 添加了
left: 10px确保进度条从正确位置开始 - 宽度计算也考虑了实际可滑动范围
- 添加了
-
性能优化:
- 使用
requestAnimationFrame优化动画性能 - 保持代码在高频率更新时的流畅性
- 使用
-
实时响应:
- 确保使用
input事件进行实时更新
- 确保使用
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Custom Slider</title>
<style>
.slider-wrapper {
position: relative;
margin-top: 40px;
padding: 0 10px;
}
input[type='range'] {
appearance: none;
-webkit-appearance: none;
width: 100%;
height: 10px;
border-radius: 5px;
background: #ebecf1;
outline: none;
margin: 0;
}
input[type='range']::-webkit-slider-thumb {
-webkit-appearance: none;
width: 20px;
height: 20px;
border-radius: 50%;
background: #2492fc;
border: 3px solid #fff;
box-shadow: 0 4px 8px rgba(36, 146, 252, 0.2);
cursor: grab;
position: relative;
z-index: 2;
}
.slider-number {
position: absolute;
background: #2492fc;
color: white;
padding: 4px 8px;
border-radius: 4px;
font-size: 14px;
transform: translateX(-50%);
top: -35px;
}
.slider-number:after {
content: '';
position: absolute;
bottom: -5px;
left: 50%;
transform: translateX(-50%);
width: 0;
height: 0;
border-left: 5px solid transparent;
border-right: 5px solid transparent;
border-top: 5px solid #2492fc;
}
.slider-progress {
position: absolute;
height: 10px;
background: #2492fc;
border-radius: 5px;
top: 50%;
transform: translateY(-50%);
z-index: 1;
pointer-events: none;
left: 10px;
}
</style>
</head>
<body>
<div class="slider-wrapper">
<div class="slider-number">0</div>
<div class="slider-progress"></div>
<input type="range" min="0" max="550" value="0" step="1" />
</div>
<script>
const sliderWrapper = document.querySelector('.slider-wrapper')
const sliderNum = document.querySelector('.slider-number')
const input = document.querySelector('input')
const progress = document.querySelector('.slider-progress')
// 使用 requestAnimationFrame 优化性能
function updateSlider(value) {
requestAnimationFrame(() => {
// 更新数字显示
sliderNum.textContent = value
// 计算滑块位置的百分比
const percent = (value - input.min) / (input.max - input.min)
// 计算实际可滑动的宽度(减去滑块的宽度)
const thumbWidth = 20 // 滑块宽度
const trackWidth = input.offsetWidth - thumbWidth
// 计算滑块中心点位置
const thumbPosition = percent * trackWidth + thumbWidth / 2 + 10
// 更新数字标签位置,确保对齐滑块中心
sliderNum.style.left = `${thumbPosition}px`
// 更新进度条宽度
progress.style.width = `${percent * trackWidth}px`
})
}
// 使用 input 事件而不是 change 事件,确保实时更新
input.addEventListener('input', (e) => {
updateSlider(e.target.value)
})
// 初始化
updateSlider(input.value)
// 处理窗口大小改变
window.addEventListener('resize', () => {
updateSlider(input.value)
})
</script>
</body>
</html>