简体   繁体   中英

angular: auto scroll of elements

I am trying to figure out a way to get items in a list scroll up smoothly, with an animation effect if possible.

Here's how my list of items looks like: https://plnkr.co/edit/nRhpyO71eHOaQTzOElFe?p=preview

<button (click)="prev()">Prev</button>
<button (click)="next()">Next</button>
<button (click)="autoplay()">Auto play</button>
<div>
  Current: {{current}}
</div>

<div class="wrapper">

  <mat-card *ngFor="let item of [0, 1, 2,3,4,5,6,7,8,9]"
  class="item" id="'item'+item"
  [ngClass]="item == current ? 'active' : ''"
   >
   This is item {{item}}
  </mat-card>

</div>

component -

export class CardOverviewExample {

  constructor(private elRef:ElementRef) {

  }

  current: number = 0;

  autoplay() {
    if (this.current < 9) {
     next();
    } else {
      this.current = 0;
    }
    setTimeout(() => this.autoplay(), 2000);
  }

  next() {
    this.current = this.current + 1;
    setTimeout(() => this.scrollCurrentIntoView);
  }
  prev() {
    this.current = this.current - 1;
    setTimeout(() => this.scrollCurrentIntoView);
  }
  scrollCurrentIntoView() {

    let id = '#item' + current;
    let el = this.elRef.nativeElement.querySelector(id);
    console.log("el: ", el);
    el.nativeElement.scrollIntoView({behavior: "smooth", block: "start", inline: "start"});
  }
}

There's both a manual mode of moving to the next element and there's automatic mode where the next item becomes active in a few seconds. The requirement is to have the current active element always at the top, but still scrolling of the list if the user wishes to do so and select another item from the list.

I tried using scrollIntoView with behaviour:smooth. Although it works, it's sometimes flashy and I am looking for alternatives. (Note: scrollIntoView isn't working in the plunker example but it works in my app).

I tried the solution suggested at https://stackoverflow.com/a/45367387/1893487 - to simulate a slow scrolling I tried setting the scrollTop value to different increments over 2s. This works but it's still not smooth. Sometimes I dont see angular change detector showing intermediate states.

I am wondering if there are any possibilities of using CSS translateY transform to achieve scrolling, as this is supposed to be more efficient too. Suggestions for alternate mechanisms to implement scrolling is appreciated.

You could use a little JS

function currentYPosition() {
// Firefox, Chrome, Opera, Safari
if (self.pageYOffset) return self.pageYOffset;
// Internet Explorer 6 - standards mode
if (document.documentElement && document.documentElement.scrollTop)
    return document.documentElement.scrollTop;
// Internet Explorer 6, 7 and 8
if (document.body.scrollTop) return document.body.scrollTop;
return 0;
};

function elmYPosition(eID) {
    var elm = document.getElementById(eID);
    var y = elm.offsetTop;
    var node = elm;
    while (node.offsetParent && node.offsetParent != document.body) {
        node = node.offsetParent;
        y += node.offsetTop;
    } return y;
};

function smoothScroll(eID) {
    var startY = currentYPosition();
    var stopY = elmYPosition(eID);
    var distance = stopY > startY ? stopY - startY : startY - stopY;
    if (distance < 100) {
        scrollTo(0, stopY); return;
    }
    var speed = Math.round(distance / 75);
    if (speed >= 20) speed = 20;
    var step = Math.round(distance / 25);
    var leapY = stopY > startY ? startY + step : startY - step;
    var timer = 0;
    if (stopY > startY) {
        for ( var i=startY; i<stopY; i+=step ) {
            setTimeout("window.scrollTo(0, "+leapY+")", timer * speed);
            leapY += step; if (leapY > stopY) leapY = stopY; timer++;
        } return;
    }
    for ( var i=startY; i>stopY; i-=step ) {
        setTimeout("window.scrollTo(0, "+leapY+")", timer * speed);
        leapY -= step; if (leapY < stopY) leapY = stopY; timer++;
    }
    return false;
};

and then change scroll into view like this

scrollCurrentIntoView() {

let id = '#item' + current;
let el = this.elRef.nativeElement.querySelector(id);
console.log("el: ", el);
smoothScroll(el);

}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM