Recently has been busy in the company fry the page of the contest, finally gave him to the line yesterday. A seemingly simple page, do just know the hardships among them, hidden pit. Writing the page logic directly using jquery is a lot more complicated than you might think. In terms of layout, functionality, and logic, there are things to be learned.

Click to view the page I launched yesterday

This article focuses on the implementation of seamless scrolling.

When I first started learning JS, I really felt that seamless scrolling was a magical feature. What’s going on behind the scenes? Why is it that there are only a few beepers and it doesn’t end there? Later, after understanding the principle, I found that it was realized through some smoke and mirrors.

The principle of

Let’s say the four elements that need seamless scrolling are six Li. items in a single UL. items. We will control the scrolling of ul.items in container.wrap. The HTML code is as follows:

Ul. items represents the UL element with className items, and the same applies elsewhere


       
Copy the code

Our goal is horizontal scrolling, so we need li.items to be arranged horizontally. Common ways to achieve this are using float: left or display: inline-block. We know that controlling the movement of elements on the page is nothing more than controlling the left, top, translateX, translateY of elements, and also controlling the scrolling distance scrollTop, scrollLeft. The choice of layout also affects the choice of JS control properties.

This example chooses to use the display: inline-block layout and controls the scrollLeft value of UL.items to scroll the entire UL. Note the following points in the layout:

  1. The parts that are outside the container need to be hidden. Note that the hiding is for ul.items. Note the difference with float: left layout.

    .items { overflow: hidden; }Copy the code
  2. The contents of ul.items cannot be folded, so

    .items { white-space: nowrap; }Copy the code
  3. It needs to be adapted to the mobile end, so the width of The Li. item will inevitably decrease as the width of the configuration becomes smaller.

    @media (max-width: 780px) { .item { width: 190px; } } @media (max-width: 580px) { .item { width: 160px; }}Copy the code
  4. The HTML layout is designed to eliminate gaps between display: inline-block elements.

So what’s the trick to seamless rolling? It would have been more intuitive to use pictures to describe it, but HERE I want to take a break and use words to tell you about it, I hope you can understand it.

We have children 123456, scroll left one by one, copy one, and it becomes 123456123456. If we pull the position of the whole thing back to the first 1 (the original position) when the whole thing moves to the second 1, because the overflow: hidden of div.items is in the middle, we cannot identify the change with our naked eyes, we will feel that we are always moving to the left and will never stop.

Expression ability is limited, if you do not understand the code to understand it, or leave a message to me

Function implementation

When it comes to motion, the most common approach is to use setTimeout or setInterval, but HTML5 provides a more high-performance method called requestAnimationFrame.

For performance, requestAnimationFrame > setTimeout > setInterval. Specific reason everybody can seek relevant data to understand. The minimum fixed time value of setTimeout is 100/60. Therefore, when we implement motion, we often declare the following from performance and compatibility considerations:

var lastTime = 0,
    nextFrame = window.requestAnimationFrame       ||
                window.webkitRequestAnimationFrame ||
                window.mozRequestAnimationFrame    ||
                window.msRequestAnimationFrame     ||
                function(callback) {
                    var currTime = + new Date,
                        delay = Math.max(1000/60, 1000/60 - (currTime - lastTime));
                    lastTime = currTime + delay;
                    return setTimeout(callback, delay);
                },
    cancelFrame = window.cancelAnimationFrame               ||
                  window.webkitCancelAnimationFrame         ||
                  window.webkitCancelRequestAnimationFrame  ||
                  window.mozCancelRequestAnimationFrame     ||
                  window.msCancelRequestAnimationFrame      ||
                  clearTimeout;Copy the code

We need to know where we’re going to scroll back to 0, which is exactly the total length of all the children before we copied them. But the width of the child element will change as the device width changes, so with the layout, we need to do the following:

Var itemW = 240; if ($items.children().eq(0).width() == 190) { itemW = 190; } if ($items.children().eq(0).width() == 160) { itemW = 160; } var target = itemW * $items.children().length;Copy the code

To achieve the illusion, one element needs to be copied

$items.html( $items.html() + $items.html() );Copy the code

I’m going to define a function of motion, where the motion is constant, so it’s a little bit easier, just keep going plus 1. If you need to move faster, add more

var timer = null; function adAni() { timer = nextFrame(function() { scrollX += 1; If (scrollX >= target) {scrollX = 0; } $items.scrollLeft(scrollX); adAni(); }); } // Run this function to achieve seamless scrolling. adAni();Copy the code

This allows seamless scrolling. But there are other requirements. For example, when you mouseover, you need to stop scrolling and then restart scrolling when you leave. Due to changing requirements, you also need to be able to slide items. Ul on the mobile side and continue scrolling after releasing your fingers. So we need a function to distinguish PC from mobile. By the difference in UA.

function isMobile() { return /(iphone|ipad|ipod|ios|android|mobile|blackberry|iemobile|mqqbrowser|juc|fennec|wosbrowser|browserng|Webos|symbian|windo ws phone)/i.test(navigator.userAgent); }Copy the code

On the PC side, the mouse stops when it is moved in and continues to scroll when it is removed

if (! isMobile()) { $items.on('mouseover', function() { cancelFrame(timer); }).on('mouseout', function() { adAni(); }); }Copy the code

On the mobile end, you can slide left and right, stop the automatic scrolling when sliding, and continue the automatic scrolling after releasing. The sliding event on the mobile side is mainly realized through TouchStart, TouchMove and Touchend, similar to mousedown, Mousemove and Mouseup on the PC side.

var sX, sL;
$items.on('touchstart', function(e) {
    cancelFrame(timer);
    sX = e.originalEvent.changedTouches[0].pageX;
    sL = $items.scrollLeft();
}).on('touchmove', function(e) {
    var dis = e.originalEvent.changedTouches[0].pageX - sX;
    var nowX = sL - dis;
    if (nowX > target) {
        nowX = 0;
    }
    $items.scrollLeft(nowX);
}).on('touchend', function(e) {
    scrollX = $items.scrollLeft();
    if (scrollX >= target) {
        scrollX = 0;
    }
    adAni();
})Copy the code

So at this point, we’re pretty much done. Although this is a simple little example, it also contains some common functions such as using requestAnimationFrame to implement motion, sliding events on the mobile side, etc. Here is a summary to share with you, have questions welcome to discuss.

Since the SegmentFault article does not support the Codepen demo, you can check out the link provided at the beginning of this article, or check out the original blog post on my personal blog.

Codepen. IO/yangbo5207 /…

If you have any questions, please leave a message to me on the official account. You can search isreact on wechat and find me ^_^. I need your attention.