Smooth scroll angular2
there is a method in the window
object called scrollTo()
.If you set the behavior to 'smooth' the page will handle the smooth scroll.example (scroll to top of page):
window.scrollTo({ left: 0, top: 0, behavior: 'smooth' });
And with fallback example:
try { window.scrollTo({ left: 0, top: 0, behavior: 'smooth' }); } catch (e) { window.scrollTo(0, 0); }
Alright, after scratching my head a little bit, here is a solution that seems to be working ok.
Same as before, I declared my conditional id and a button with the scrollTo function call when clicked.
Now, there are only two files in the solution is a service that will help return the document window and the template's component. Nothing was changed in the window service from the state above but I will include it again for the sake of a good answer.
window.service.ts : shout out to https://gist.github.com/lokanx/cc022ee0b8999cd3b7f5 for helping with this piece
import {Injectable, Provider} from 'angular2/core';import {window} from 'angular2/src/facade/browser';import {unimplemented} from 'angular2/src/facade/exceptions';function _window(): Window { return window}export abstract class WINDOW { get nativeWindow(): Window { return unimplemented(); }}class WindowRef_ extends WINDOW { constructor() { super(); } get nativeWindow(): Window { return _window(); }}export const WINDOW_PROVIDERS = [ new Provider(WINDOW, { useClass: WindowRef_ }),];
app.component.ts
import { bootstrap } from 'angular2/platform/browser';import { Component } from 'angular2/core';import {WINDOW, WINDOW_PROVIDERS} from './window.service';@Component({ selector: 'my-app', templateUrl: 'app.tpl.html', providers: [WINDOW_PROVIDERS]})class AppComponent { win: Window; private offSet: number; constructor( private _win: WINDOW) { this.win = _win.nativeWindow; } title = 'Ultra Racing'; things = new Array(200); scrollTo(yPoint: number, duration: number) { setTimeout(() => { this.win.window.scrollTo(0, yPoint) }, duration); return; } smoothScroll(eID) { var startY = currentYPosition(); var stopY = elmYPosition(eID); var distance = stopY > startY ? stopY - startY : startY - stopY; if (distance < 100) { this.win.window.scrollTo(0, stopY); return; } var speed = Math.round(distance / 100); if (speed >= 20) speed = 20; var step = Math.round(distance / 100); var leapY = stopY > startY ? startY + step : startY - step; var timer = 0; if (stopY > startY) { for (var i = startY; i < stopY; i += step) { this.scrollTo(leapY, timer * speed); leapY += step; if (leapY > stopY) leapY = stopY; timer++; } return; } for (var i = startY; i > stopY; i -= step) { this.scrollTo(leapY, timer * speed); leapY -= step; if (leapY < stopY) leapY = stopY; timer++; } }}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;}bootstrap(AppComponent)
I created a plunk to show this example working:Plunk Example
The easier way to achieve this is by using this polyfill:http://iamdustan.com/smoothscroll/
- Install it as: npm install smoothscroll-polyfill
- Import it in your polyfill.ts file as: require('smoothscroll-polyfill').polyfill();
Now you can use behavior option of scrollIntoView as:
(document.querySelector('#'+ anchor)).scrollIntoView({ behavior: 'smooth' });