This article is published by the Cloud + community

A recent active page required a draw that could be swiped left and right, so the transform property of CSS was combined with JS to simulate the effect of infinite scrolling.

First effect:

The demo address: kiroroyoyo. Making. IO/cardTransfo…

The implementation process

1. Structure and style

Structure: the card is divided into two rows before and after, and 10 div nodes are inserted into each column in order to make left and right displacement effect.

Style: Set each column to be exactly in the middle (or near the middle), as shown below.

A. Initial position of front row (cardFrond) relative to viewport (left:-255.5%;) :

B. Initial position of the backFrond relative to the viewport (left:-228.3%;) :

2. Infinite rolling principle

Because the stop position here is fixed, the front row is always centered with the current card relative to the viewport, and the back row is always centered with two cards relative to the viewport, and each card is the same, when the card list moves forward or right to a target position, the list is reset to its original position to continue scrolling. The following picture takes the front-row card as an example:

So when scrolling stops, the list style is uniformly set to transform: translateX(0). However, for the user, this operation is not perceptive and they think that they have slid to a new position.

3. Sliding process realization

A. Target displacement and frame displacement

In order to achieve the slow effect of sliding to the stopping position, when the user slides the screen left and right, the sliding distance will be recorded, and the target displacement position of the card should be calculated. The target displacement position is regular, because there are 10 cards evenly divided width, the position must be an integer multiple of (100%/10), such as -40%, -30%… 40%, in order to ensure that the target position and the initial position coincide.

Target shift code snippet

onDocumentMouseUp : function(e){
    // Move is not set for click events
    if (!this.fingerTouch)
      return;
    this.moveDirect = this.lon > 0 ? 1 : - 1;
    this.transNum = this.lon/10 + this.moveDirect;
    this.lon = Math.round(this.transNum) * 10;
    this.fingerTouch = false;   
}
Copy the code

After the target displacement is recorded, each frame will keep approaching the target displacement with a certain frame displacement, so that it still has a slow effect of sliding to the target position when the finger leaves the screen. At this point, it is necessary to judge whether the current position is greater than 40% or less than -40%. If the limit value is exceeded, it is necessary to reset the target displacement and frame displacement to make them within the limit value.

animate: function(){
    this.prePos += (this.lon - this.prePos) * 0.1;
    if (this.prePos > 40) {
      this.lon = this.lon - 40;
      this.prePos = this.prePos - 40;
    }else if (this.prePos < - 40) {
      this.lon = this.lon + 40;
      this.prePos = this.prePos + 40;
    }
    // Determine whether the target position is reached
    if (Math.abs(this.prePos - this.lon) < 0.01 && Math.abs(this.lon) > 0.01 && (!this.fingerTouch))
    {
        this.ani_move = false;
        this.prePos = 0;
        this.frondCard.style = "transform: translateX("+ this.prePos +"%)";
        this.backCard.style = "transform: translateX("+ this.prePos +"%)";
    }else{
        this.frondCard.style = "transform: translateX("+ this.prePos +"%)";
        this.backCard.style = "transform: translateX("+ (-this.prePos) +"%)";
        requestAnimationFrame(this.animate.bind(this)); }},Copy the code

B. Continuous sliding judgment

When the user slides a second time before the last slide animation ends, the following operations need to be performed:

1). To judge the sliding time when the last sliding finger has left the screen but the animation is not over, two flags need to be recorded, one is ani_move to record whether the animation is still in progress, and fingerTouch to record whether the finger stays on the screen.

2). Determine whether the second slide is in a different direction from the first. If it is in a different direction, reset the last frame displacement to 0. In order to avoid the last frame shift too much affect the direction of movement.

1) and 2) Code snippets:

if( this.ani_move && this.fingerTouch == false) {
    // Check whether there are different directions
    if (((e.clientX - prex) > 0 ? 1: - 1) = = -this.moveDirect ) {
        this.lon = 0;
        this.prePos = 0;
        this.moveDirect = -this.moveDirect; }}Copy the code

3). Cancel the animation playback and displacement reset on the second slide

// There is no need to start the animation again and reset the target displacement if the last animation did not end
if( this.ani_move && this.fingerTouch == false) {}else {
    this.lon = 0;
     cardAnimate.animate();
}
Copy the code

Write in the last

Currently, the slide effect can only be used when the cards are in the same position, because they need to be in the same position. Use CSS Transform to scroll indefinitely to avoid rearranging the page by changing the DOM node.

The following image shows chrome CPU6x decelerations without triggering layout, with an FPS of around 60.

Code Address:

Github.com/kiroroyoyo/…

This article has been published by Tencent Cloud + community authorized by the author