首页 > 解决方案 > 试图让这种行为更流畅、更自然

问题描述

我的实现, http: //kodhus.com/kodnest/land/PpNFTgp

我很好奇,因为由于某种原因我无法弄清楚这一点,如何让我的 JavaScript 让我的滑块表现得更自然和更流畅,如果有人知道,如何或可以让它感觉自由。我很乐意理解。

JavaScript:

const thumb = document.querySelector('.thumb');
const thumbIndicator = document.querySelector('.thumb .thumb-indicator');
const sliderContainer = document.querySelector('.slider-container');
const trackProgress = document.querySelector('.track-progress');
const sliderContainerStart = sliderContainer.offsetLeft;
const sliderContainerWidth = sliderContainer.offsetWidth;
var translate;
var dragging = false;
var percentage = 14;

document.addEventListener('mousedown', function(e) {
  if (e.target.classList.contains('thumb-indicator')) {
    dragging = true;
    thumbIndicator.classList.add('focus');  
  }
});

document.addEventListener('mousemove', function(e) {

  if (dragging) {
      console.log('moving', e)
    if (e.clientX < sliderContainerStart) {
      translate = 0;
    } else if (e.clientX > sliderContainerWidth + sliderContainerStart) {
      translate = sliderContainerWidth;
    } else {
      translate =  e.clientX - sliderContainer.offsetLeft;  
    }
    
    thumb.style.transform = 'translate(-50%) translate(' + translate + 'px)';
    trackProgress.style.transform = 'scaleX(' + translate / sliderContainerWidth +  ')'
  }
});

function setPercentage() {
   thumb.style.transform = 'translate(-50%) translate(' + percentage/100 * sliderContainerWidth + 'px)';
  trackProgress.style.transform = 'scaleX(' + percentage/100 +  ')';
}

function init() {
 setPercentage(); 
}

init();

document.addEventListener('mouseup', function(e) {
  dragging = false;
  thumbIndicator.classList.remove('focus');
});

编辑:有没有一种方法可以让每一个缓慢的动作平滑自然地增加一个?

是否有可能表现得好像,就像当一个人单击进度条以便它跳到那里一样?

标签: javascripthtmlcss

解决方案


kodhus 网站在我的浏览器中非常不稳定,所以我无法判断您的代码是否缺乏响应能力,或者它是否是网站本身。我觉得你的代码有点复杂:translatewidth/height不必要地混合;当该信息始终存储在类列表中时,无需使用dragging布尔值。以下滑块运行良好,并且有一些我在您的滑块中没有看到的注意事项:

  • 单击.thumb元素时停止传播
  • 如果窗口失去焦点,拖动停止
  • pointer-events: none;应用于滑块的每个部分,但.thumb元素

let applySliderFeel = (slider, valueChangeCallback=()=>{}) => {

  // Now `thumb`, `bar` and `slider` are the elements that concern us
  let [ thumb, bar ] = [ '.thumb', '.bar' ].map(v => slider.querySelector(v));
  
  let changed = amt => {
    thumb.style.left = `${amt * 100}%`;
    bar.style.width = `${amt * 100}%`;
    valueChangeCallback(amt);
  };
  
  // Pressing down on `thumb` activates dragging
  thumb.addEventListener('mousedown', evt => {
    thumb.classList.add('active');
    evt.preventDefault();
    evt.stopPropagation();
  });
  
  // Releasing the mouse button (anywhere) deactivates dragging
  document.addEventListener('mouseup', evt => thumb.classList.remove('active'));
  
  // If the window loses focus dragging also stops - this can be a very
  // nice quality of life improvement!
  window.addEventListener('blur', evt => thumb.classList.remove('active'));
  
  // Now we have to act when the mouse moves...
  document.addEventListener('mousemove', evt => {
    
    // If the drag isn't active do nothing!
    if (!thumb.classList.contains('active')) return;
    
    // Compute `xRelSlider`, which is the mouse position relative to the
    // left side of the slider bar. Note that *client*X is compatible with
    // getBounding*Client*Rect, and using these two values we can quickly
    // get the relative x position.
    let { width, left } = slider.getBoundingClientRect();
    
    // Consider mouse x, subtract left offset of slider, and subtract half
    // the width of the thumb (so drags position the center of the thumb,
    // not its left side):
    let xRelSlider = evt.clientX - left - (thumb.getBoundingClientRect().width >> 1);
    
    // Clamp `xRelSlider` between 0 and the slider's width
    if (xRelSlider < 0) xRelSlider = 0;
    if (xRelSlider > width) xRelSlider = width;
    
    // Apply styling (using percents is more robust!)
    changed(xRelSlider / width);
    
    evt.preventDefault();
    evt.stopPropagation();
    
  });
  
  slider.addEventListener('mousedown', evt => {
    
    let { width, left } = slider.getBoundingClientRect();
    
    // Clicking the slider also activates a drag
    thumb.classList.add('active');
    
    // Consider mouse x, subtract left offset of slider, and subtract half
    // the width of the thumb (so drags position the center of the thumb,
    // not its left side):
    let xRelSlider = evt.clientX - left - (thumb.getBoundingClientRect().width >> 1);
    
    // Apply styling (using percents is more robust!)
    changed(xRelSlider / width);
    
    evt.preventDefault();
    evt.stopPropagation();
    
  });
  
  changed(0);
  
};

let valElem = document.querySelector('.value');
applySliderFeel(document.querySelector('.slider'), amt => valElem.innerHTML = amt.toFixed(3));
.slider {
  position: absolute;
  width: 80%; height: 4px; background-color: rgba(0, 0, 0, 0.3);
  left: 10%; top: 50%; margin-top: -2px;
}
.slider > .bar {
  position: absolute;
  left: 0; top: 0; width: 0; height: 100%;
  background-color: #000;
  pointer-events: none;
}
.slider > .thumb {
  position: absolute;
  width: 20px; height: 20px; background-color: #000; border-radius: 100%;
  left: 0; top: 50%; margin-top: -10px;
}
.slider > .thumb.active {
  box-shadow: 0 0 0 5px rgba(0, 0, 0, 0.5);
}
<div class="slider">
  <div class="bar"></div>
  <div class="thumb"></div>
</div>
<div class="value"></div>


推荐阅读