在错误的时间调用动画回调

时间:2016-09-20 01:08:20

标签: javascript css animation

我正在尝试对自定义卷轴进行反弹效果。 (我正在使用translate3d滚动。)我终于能够实现它了,但现在唯一的问题是,如果你继续滚动越界(尝试双滚动并继续这样做直到它卡住) ,然后它将保持在界限之外,直到你向下滚动(或向上,取决于它被卡住的位置)。

像这样:http://imgur.com/SHAe1E4(由于某种原因,stackoverflow不允许我添加gif。)代码:JSFiddle

问题:

如何使用JavaScript和CSS制作滚动跳出效果?

其余部分是可选的。

无法工作的原因:

我认为它的原因是:有一个动画回调事件。因此,如果动画没有发生,即变换没有改变,那么动画回调就不会触发。

因此,当它一直滚动到顶部或底部,然后再次滚动,(在动画完成之前,因此动画回调不会被调用,因为转换值没有改变)动画回调将没有被调用,因此它不会滚动(反弹)回到边界。

我尝试了什么:

我尝试检查滚动位置是否发生了变化,如果它没有调用动画回调函数,但它没有给出所需的结果。当你尝试一次滚出越界时,它会产生“口吃”效果,并且不会一直向外滚动,它会在中途停止并向后滚动。像这样:http://imgur.com/a/xHYle JSFiddle

每当滚动位置没有改变时,我也尝试将变换值改变0.1,因此将调用动画回调。问题是,如果你滚出界限,它会等待半秒钟才会反弹 因此,当滚动位置没有改变时,我将动画持续时间设置为较短的时间,但如果您反复滚动超出范围,即,当它超出界限时向上或向下滚动,则等待一秒钟,然后反弹回来。 JSFiddle

console.clear();

var innerWrapper = document.getElementById('innerWrapper');
var scrollBar = document.getElementById('scrollbar');
var scrollBarThumb = scrollBar.firstElementChild;

var scrollPosition = 0;
var scrolledToBottom = innerWrapper.scrollHeight - innerWrapper.parentElement.offsetHeight;

scrollBarThumb.style.height = (innerWrapper.offsetHeight * innerWrapper.offsetHeight / innerWrapper.scrollHeight) + 'px';

innerWrapper.addEventListener('mousewheel', handleScroll);
innerWrapper.addEventListener('DOMMouseScroll', handleScroll);
innerWrapper.addEventListener('transitionend', bounceBack);

innerWrapper.style.transform = 'translate3d(0px, 0px, 0px)';

function handleScroll(e) {
  // Prevent parents from scrolling
  e.preventDefault();
  var direction = (e.detail < 0 || e.wheelDelta > 0) ? 1 : -1; // 1 = scroll down, -1 = scroll

  scrollPosition += direction * 100; // Cannot use `deltaY`, because not all browsers support it.
  scrollPosition = clamp(scrollPosition, -scrolledToBottom - 40, 40); // 40 = bounce amount

  var scrollThumbPosition = (scrollPosition * scrollBarThumb.offsetHeight / innerWrapper.parentElement.offsetHeight);
  scrollThumbPosition = clamp(scrollThumbPosition, -scrolledToBottom, 0);

  innerWrapper.style.transform = 'translate3d(0px, ' + scrollPosition + 'px, 0px)';
  scrollBarThumb.style.transform = 'translate3d(0px, ' + -scrollThumbPosition + 'px, 0px)';
}

function bounceBack(e) {
  // Scrolling stopped too high?
  if (scrollPosition > 0) {
    scrollPosition = 0;
    // Scrolling stopped too low?
  } else if (scrollPosition < -scrolledToBottom) {
    scrollPosition = -scrolledToBottom;
    // Scrolling stopped in viewport (i.e. not out of bounds)?
  } else {
    return;
  }

  // Bounce back with shorter animation
  innerWrapper.style.transitionDuration = '100ms';
  innerWrapper.style.transform = 'translate3d(0px, ' + (scrollPosition) + 'px, 0px)';


  // Need a 'pause' for the transform to finish with shorter animation
  setTimeout(function() {
    // Set animation time back to original
    innerWrapper.style.transitionDuration = '500ms';
  });
}

function clamp(val, min, max) {
  if (typeof min !== 'number') min = 0;
  if (typeof max !== 'number') max = 1;
  return Math.min(Math.max(val, min), max);
}
#outerWrapper {
  height: 400px;
  overflow: hidden;
  display: flex;
  background-color: black;
}
#innerWrapper {
  transform: translate3d(0px, 0px, 0px);
  transition-property: transform;
  transition-duration: 500ms;
  transition-timing-function: ease;
}
#content {
  background-image: url("http://images.freeimages.com/images/premium/previews/3037/30376024-beautiful-flower-portrait.jpg");
  width: 400px;
}
#scrollbar {
  height: 100%;
  width: 50px;
  background-color: orange;
}
#scrollbar_thumb {
  background-color: yellow;
  border: 2px solid blue;
  box-sizing: border-box;
  transform: translate3d(0px, 0px, 0px);
  transition-property: transform;
  transition-duration: 500ms;
  transition-timing-function: ease;
}
<div id="outerWrapper">
  <div id="innerWrapper">
    <div id="content">
      Lorem ipsum dolor sit amet consectetuer laoreet faucibus id ut et. Consequat Ut tellus enim ante nulla molestie vitae sem interdum turpis. Fames ridiculus cursus pellentesque Vestibulum justo sem lorem neque accumsan nulla. Lacinia Suspendisse vitae libero
      sem et laoreet risus Sed condimentum Cras. Nunc massa mauris tempor dolor pulvinar justo neque dui ipsum vitae. Lacinia dui cursus pellentesque Vestibulum justo sem lorem neque accumsan nulla. Lacinia Suspendisse vitae libero sem et laoreet risus
      Sed condimentum Cras. Nunc massa mauris tempor dolor pulvinar justo neque dui ipsum vitae. Lacinia dui scelerisque Sed convallis nonummy orci Vestibulum orci tempusLorem ipsum dolor sit amet consectetuer laoreet faucibus id ut et. Consequat Ut tellus
      enim ante nulla molestie vitae sem interdum turpis. Fames ridiculus cursus pellentesque Vestibulum justo sem lorem neque accumsan nulla. Lacinia Suspendisse vitae libero sem et laoreet risus Sed condimentum Cras. Nunc massa mauris tempor dolor pulvinar
      justo neque dui ipsum vitae. Lacinia dui scelerisque Sed convallis nonummy orci Vestibulum orci tempusLorem ipsum dolor sit amet consectetuer laoreet faucibus id ut et. Consequat Ut tellus enim ante nulla molestie vitae sem interdum turpis. Fames
      ridiculus cursus pellentesque Vestibulum justo sem lorem neque accumsan nulla. Lacinia Suspendisse vitae libero sem et laoreet risus Sed condimentum Cras. Nunc massa mauris tempor dolor pulvinar justo neque dui ipsum vitae. Lacinia dui scelerisque
      Sed convallis nonummy orci Vestibulum orci tempusLorem ipsum dolor sit amet consectetuer laoreet faucibus id ut et. Consequat Ut tellus enim ante nulla molestie vitae sem interdum turpis. Fames ridiculus cursus pellentesque Vestibulum justo sem
      lorem neque accumsan nulla. Lacinia Suspendisse vitae libero sem et laoreet risus Sed condimentum Cras. Nunc massa mauris tempor dolor Lorem ipsum dolor sit amet consectetuer laoreet faucibus id ut et. Consequat Ut tellus enim ante nulla molestie
      vitae sem interdum turpis. Fames ridiculus cursus pellentesque Vestibulum justo sem lorem neque accumsan nulla. Lacinia Suspendisse vitae libero sem et laoreet risus Sed condimentum Cras. Nunc massa mauris tempor dolor pulvinar justo neque dui ipsum
      vitae. Lacinia dui scelerisque Sed convallis nonummy orci Vestibulum orci tempusLorem ipsum dolor sit amet consectetuer laoreet faucibus id ut et. Consequat Ut tellus enim ante nulla molestie vitae sem interdum turpis. Fames ridiculus cursus pellentesque
      Vestibulum justo sem lorem neque accumsan nulla. Lacinia Suspendisse vitae libero sem et laoreet risus Sed condimentum Cras. Nunc massa mauris tempor dolor pulvinar justo neque dui ipsum vitae. Lacinia dui scelerisque Sed convallis nonummy orci
      Vestibulum orci tempusLorem ipsum dolor sit amet consectetuer laoreet faucibus id ut et. Consequat Ut tellus enim ante nulla molestie vitae sem interdum turpis. Fames ridiculus cursus pellentesque Vestibulum justo sem lorem neque accumsan nulla.
      Lacinia Suspendisse vitae libero sem et laoreet risus Sed condimentum Cras. Nunc massa mauris tempor dolor pulvinar justo neque dui ipsum vitae. Lacinia dui scelerisque Sed convallis nonummy orci Vestibulum orci tempusLorem ipsum dolor sit amet
      consectetuer laoreet faucibus id ut et. Consequat Ut tellus enim ante nulla molestie vitae sem interdum turpis. Fames ridiculus cursus pellentesque Vestibulum justo sem lorem neque accumsan nulla. Lacinia Suspendisse vitae libero sem et laoreet
      risus Sed condimentum Cras. Nunc massa mauris tempor dolor pulvinar justo neque dui ipsum vitae. Lacinia dui scelerisque Sed convallis nonummy orci Vestibulum orci tempusLorem ipsum dolor sit amet consectetuer laoreet faucibus id ut et. Consequat
      Ut tellus enim ante nulla molestie vitae sem interdum turpis. Fames ridiculus cursus pellentesque Vestibulum justo sem lorem neque accumsan nulla. Lacinia Suspendisse vitae libero sem et laoreet risus Sed condimentum Cras. Nunc massa mauris tempor
      dolor
    </div>
  </div>
  <div id="scrollbar">
    <div id="scrollbar_thumb"></div>
  </div>
</div>

1 个答案:

答案 0 :(得分:1)

我可能会使用z组件在每个轮子事件之间进行细微差别,以便触发转换。 fiddle

var i = 0;
// onmousewheel
.. el.style.transform = `translate3d(0, 40px, ${i^=1}px)` 

// ontransitionend
.. el.style.transform = `translate3d(0, 0, -1px)`

如果上述方法过于棘手,我们可能会进行昂贵的查询以查找当前翻译的内容。然后将它与bounceAmount(例如你的情况下为40)进行比较,如果它们几乎相同(diff。&lt; Number.EPSILON),则直接调用bounceBack()

var m = getComputedStyle(el).transform.match(/,\s*([^,]*?)\s*\)/)
m ? m[1] : 0 // current translation y

更新

如果要求内容立即反弹,我们可以在动作开始时简单地禁用onwheel,然后在整个动作完成后重新启用它。这不再需要z组件技巧。 fiddle