On scroll down, scroll 100vh to the bottom

2019-02-15 19:28发布

问题:

I want to achieve the same effect at http://www.squaredot.eu/#Intro

So if I scroll down, the body must scroll 100vh to the bottom. And also if scroll up, the body must scroll 100vh up. I tried something, but it didn't work out.

HTML:

<!DOCTYPE html>
<html>
<head>
    <title> Log In </title>
    <link href="main.css" rel="stylesheet" type="text/css">
</head>
    <body>
        <div id="e1"></div>
        <div id="e2"></div>
        <div id="e3"></div>
        <div id="e4"></div>
        <div id="e5"></div>
    </body>
</html>

CSS:

body, html {
  height: 100%;
  margin: 0;
  padding: 0;
}

#e1 {
    width: 100%;
    height: 100vh;
    background-color: red;
}

#e2 {
    width: 100%;
    height: 100vh;
    background-color: green;
}

#e3 {
    width: 100%;
    height: 100vh;
    background-color: yellow;
}

#e4 {
    width: 100%;
    height: 100vh;
    background-color: blue;
}

#e5 {
    width: 100%;
    height: 100vh;
    background-color: orange;
}

JAVASCRIPT

document.addEventListener('scroll', function(e) {
    var currScroll = document.body.scrollTop;
    document.body.scrollTop = calc(~"currScroll + 100vh");
 }

);

回答1:

One solution could be using transform from CSS (like the website you linked is doing).

Add this as css:

body {
    transform: translate3d(0px, 0px, 0px);
    transition: all 700ms ease;
}

And this as javascript

var pageHeight = window.innerHeight;

document.addEventListener('scroll', function(){
  document.body.scrollTop = 0;
});

document.addEventListener('wheel', function(e) {
  //console.log(e.deltaY);
  if(e.deltaY > 0) {
    scrollDown();
  } else {
    scrollUp();
  }
 }
);

function scrollDown() {
  document.body.style.transform = 'translate3d(0px, -'+ pageHeight + 'px, 0px)';
}

function scrollUp() {
  document.body.style.transform = 'translate3d(0px, 0px, 0px)';
}

It only works for element 1 and 2 but it's a start, and you can learn how to implement the other steps!

Working example here: https://jsbin.com/titaremevi/edit?css,js,output


UPDATE:

This is the fully working solution:

var pageHeight = window.innerHeight;
var isAnimating = false;
document.body.style.transform = 'translate3d(0px,0px,0px)';

document.addEventListener('scroll', function(e){
  document.body.scrollTop = 0;
});
document.addEventListener('wheel', wheelListener);

function wheelListener(e) {
  if(e.deltaY > 0) {
    scrollPage(-pageHeight);
  } else {
    scrollPage(+pageHeight);
  }
}

function scrollPage(scrollSize) {
  if(isAnimating){
    return;
  }
  isAnimating = true;
  var yPos = getNewYPos(scrollSize);
  document.body.style.transform = 'translate3d(0px,'+ yPos + ',0px)';
}

function getNewYPos(add){
  var oldYPos = document.body.style.transform.split(',')[1];
  oldYPos = parseInt(oldYPos.replace(/px/,''));
  var newYPos = oldYPos + add;
  if(newYPos > 0){
    isAnimating = false;
  }
  return Math.min(0, newYPos) + 'px';
}


document.body.addEventListener('transitionend', function(){
  setTimeout(function(){ isAnimating = false; }, 500);
  document.addEventListener('wheel', wheelListener);
})

You can see it working here: https://jsbin.com/foxigobano/1/edit?js,output



回答2:

What I would do is cancel the default scroll behaviour and, then, use wheel to simulate it.

The main challenge here is to transform vh to px. I have used one of the elements with set vh for the conversion. It ends up being useless, but it is prepared in case you want to change the size of the scroll.

Working version:

// Cancel default scroll.
document.addEventListener('scoll', function(e) {
  e.preventDefault();
});


// Use wheel event to simulate scroll.
document.addEventListener('wheel', function(e) {
   e.preventDefault();
  // #e1 is 100vh, get height in pixels for conversion rate.
  var pxPerVh = document.querySelector('#e1').offsetHeight / 100;
  
  console.log('s', document.querySelector('#e1').offsetHeight, pxPerVh);
  
  // Current scroll.
  var currScroll = document.body.scrollTop;
  
  // Modify scroll 100 vh
  if (e.wheelDelta < 0) { // scroll up
    var newScroll = currScroll - 100 * pxPerVh;
  } else if (e.wheelDelta > 0) { // scroll down
    var newScroll = currScroll + 100 * pxPerVh;
  } else { // no scroll
    var newScroll = 0;
  }
 
 console.log('p', e.wheelDelta, currScroll, newScroll);
  document.body.scrollTop = newScroll;
});
body, html {
  height: 100%;
  margin: 0;
  padding: 0;
}

#e1 {
    width: 100%;
    height: 100vh;
    background-color: red;
}

#e2 {
    width: 100%;
    height: 100vh;
    background-color: green;
}

#e3 {
    width: 100%;
    height: 100vh;
    background-color: yellow;
}

#e4 {
    width: 100%;
    height: 100vh;
    background-color: blue;
}

#e5 {
    width: 100%;
    height: 100vh;
    background-color: orange;
}
<!DOCTYPE html>
<html>
<head>
    <title> Log In </title>
</head>
    <body>
        <div id="e1"></div>
        <div id="e2"></div>
        <div id="e3"></div>
        <div id="e4"></div>
        <div id="e5"></div>
    </body>
</html>

Now, while this is what you asked, I feel this is not what you really want. I understand that you want to scroll to the next div. For that, I would reuse that logic and register to what #eX I scrolled last time and use document.querySelector('#eX').scrollTop to set up the scroll of the body. That'd solve, for example, the issue of having 1-5 pixels from the previous box when scrolling.

As you have already realised about this issue on the comments, adding the new solution:

// Define range of divs
var currentDiv = 1;
var minDiv;
var maxDiv;
var extraPixel = 0;

var divs = document.querySelectorAll('div[id^="e"]');
for (var i = 0; i < divs.length; i++) {
  var id = parseInt(divs[i].id.slice(1), 10);
  // Check min div
  if (!minDiv) minDiv = id;
  if (minDiv > id) minDiv = id;
  // Check max div
  if (!maxDiv) maxDiv = id;
  if (maxDiv < id) maxDiv = id;
}


// Cancel default scroll.
document.addEventListener('scoll', function(e) {
  e.preventDefault();
});

// Use wheel event to simulate scroll.
document.addEventListener('wheel', function(e) {
   e.preventDefault();

   // Current scroll.
  var currScroll = document.body.scrollTop;
  
  // Decide next element.
  if (e.wheelDelta < 0) { // scroll up
    currentDiv--;
    if (currentDiv < minDiv) currentDiv = minDiv;
  } else if (e.wheelDelta > 0) { // scroll down
    currentDiv++;
    if (currentDiv > maxDiv) currentDiv = maxDiv;
  }

  console.log(currentDiv);

  // Check if there's a next/previous div.
  var goToDiv = document.querySelector('#e' + currentDiv);
  if (goToDiv) {
    var newScroll = goToDiv.offsetTop;
  }
  
  document.body.scrollTop = newScroll;
});
body, html {
  height: 100%;
  margin: 0;
  padding: 0;
}

div {
  margin: 0;
  padding: 0;
}

#e1 {
    width: 100%;
    height: 100vh;
    background-color: red;
}

#e2 {
    width: 100%;
    height: 100vh;
    background-color: green;
}

#e3 {
    width: 100%;
    height: 100vh;
    background-color: yellow;
}

#e4 {
    width: 100%;
    height: 100vh;
    background-color: blue;
}

#e5 {
    width: 100%;
    height: 100vh;
    background-color: orange;
}
<!DOCTYPE html>
<html>
<head>
    <title> Log In </title>
</head>
    <body>
        <div id="e1"></div>
        <div id="e2"></div>
        <div id="e3"></div>
        <div id="e4"></div>
        <div id="e5"></div>
    </body>
</html>