Scrollable Panel snap to elements on Scroll

别等时光非礼了梦想. 提交于 2020-03-02 07:51:30

问题


Is there a way inside a scrollable div to snap to elements as the user scrolls.

For example if we have CSS such as

.container {
    height: 300px;
    width: 200px;
    overflow: auto
}
li {
    height: 40px;
    width: 100 % ;
}

and HTML as

<div class="container">
    <li>
        test
    </li>
    <li>
        test
    </li>
    <li>
        test
    </li>
    <li>
        test
    </li>
    <li>
        test
    </li>
    <li>
        test
    </li>
    <li>
        test
    </li>
    <li>
        test
    </li>
    <li>
        test
    </li>
    <li>
        test
    </li>
    <li>
        test
    </li>
    <li>
        test
    </li>
    <li>
        test
    </li>
</div>

So from that the container should have a vertical scroll bar. When the user scrolls I would like it so that when they stop scrolling the final scroll position snaps the container scroll position to the nearest div at shown. This might be difficult as browsers like safari offer momentum as well, so it would have to be an event on scroll end.

Any ideas if this is possible, and how.

Marvellous


回答1:


You can use setTimeout. This should work

var snap_timer;
var scroll_from_mouse = true;

function snapList(){
  var snapped = false;
  var i = 0;
  while(!snapped && i < $('.container li').size()){
    var itop = $('.container li').eq(i).position().top;
    var iheight = $('.container li').eq(i).outerHeight();
    if(itop < iheight && itop > 0){ 
      scroll_from_mouse = false;
      snapped = true;
      var new_scroll_top = 0;
      if(iheight - itop > iheight / 2)
        new_scroll_top = $('.container').scrollTop() + itop;
      else if(i > 1)
        new_scroll_top = $('.container').scrollTop() - ($('.container li').eq(i-1).outerHeight() - itop);
      else
        new_scroll_top = 0;
      $('.container').scrollTop(new_scroll_top);
    }
    i++;
  }
};

$(function(){
  $('.container').scroll(function(){
    clearTimeout(snap_timer);
    if(scroll_from_mouse) snap_timer = setTimeout(snapList, 200);
    scroll_from_mouse = true;
  });
});



回答2:


You can use CSS Scroll Snap.

However, the feature is now deprecated, so if you want to consider a cross-browser vanilla javascript re-implementation of the native CSS Scroll Snap spec, as already answered here: How to emulate CSS Scroll Snap Points in Chrome?, you can use this library I wrote.

The main reason to use this instead of the native css solution is that it works in all modern browsers and has a customizable configuration to allow custom timing in transitions and scrolling detection.

The library re-implements the css snapping feature using vanilla javascript easing functions, and works using the values of the container element's scrollTop/scrollLeft properties and the scroll Event Listener

Here is an example that shows how to use it:

import ScrollSnap from 'scroll-snap'

const snapConfig = {
  scrollSnapDestination: '90% 0%', // scroll-snap-destination css property, as defined here: https://developer.mozilla.org/en-US/docs/Web/CSS/scroll-snap-destination
  scrollTimeout: 100, // time in ms after which scrolling is considered finished
  scrollTime: 300 // time in ms for the smooth snap
}

function callback () {
  console.log('called when snap animation ends')
}

const element = document.getElementById('container')
const snapObject = new ScrollSnap(element, snapConfig)

snapObject.bind(callback)

// unbind the element
// snapObject.unbind();

You can see a working demo here



来源:https://stackoverflow.com/questions/6800404/scrollable-panel-snap-to-elements-on-scroll

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!