Подтвердить что ты не робот

Гладкая прокрутка angular2

У меня возникли проблемы с получением плавной службы прокрутки для работы в angular 2. Существуют ли какие-либо службы для плавной прокрутки или простой прокрутки якоря, которые могут работать до тех пор, пока команда angular 2 не получит $anchorScroll angular2 эквивалентная работа?

До сих пор я только что пробовал:

Настройка * ngFor инкрементный id цикла для родительского div

[attr.id]="'point' + i"

Вызов прокрутки по кнопке с пропущенным идентификатором

<button 
     type="button" 
     class="btn btn-lg btn-default " 
     (click)="smoothScroll('point'+i)">
           Scroll to point
</button>

И в связанном компоненте я пытаюсь реализовать простую функцию прокрутки js

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 / 100);
        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(this.win.scrollTo(0, leapY), timer * speed);
                leapY += step; if (leapY > stopY) leapY = stopY; timer++;
            } return;
        }
        for (var i = startY; i > stopY; i -= step) {
            setTimeout(this.win.scrollTo(0,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;
}

Я также пытаюсь предоставить доступ к окну для this._win.scrollTo, который поступает из службы поставщика окна.

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_ }),
];

** РЕДАКТИРОВАТЬ --------------------- **

Я изменил this.win.scrollTo на this.win.window.scrollTo, и теперь я получаю эффект, похожий на angular1.x $anchorscroll, где свиток является быстрым, а не плавным переходом, но свиток не гладкий, и я получаю следующую ошибку исключения.

Ошибка исключения

UPDATE

Я больше не получаю эту ошибку, узнав, что angular2 выполняет setTimeout немного по-другому, но прокрутка по-прежнему мгновенная, а не гладкая прокрутка.

Я изменил

  setTimeout(this.win.scrollTo(0, leapY), timer * speed);

к

 setTimeout(() => this.win.scrollTo(0, leapY), timer * speed);
4b9b3361

Ответ 1

Хорошо, немного поцарапав голову, вот решение, которое, похоже, работает нормально.

Как и раньше, я объявил свой условный идентификатор и кнопку с вызовом функции scrollTo при нажатии.

Теперь в решении есть только два файла - это служба, которая поможет вернуть окно документа и компонент шаблона. Ничего не изменилось в службе окна из вышеприведенного состояния, но я включу его снова ради хорошего ответа.

window.service.ts: выкрикивайте https://gist.github.com/lokanx/cc022ee0b8999cd3b7f5 за помощь в этой части

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)

Я создал плунжер, чтобы показать этот пример: Plunk Example

Ответ 2

в объекте window есть метод scrollTo(). Если вы настроите поведение на "гладкое", страница будет обрабатывать гладкую прокрутку. пример (перейдите к началу страницы):

 window.scrollTo({ left: 0, top: 0, behavior: 'smooth' });

Ответ 3

Более простой способ добиться этого - использовать polyfill: http://iamdustan.com/smoothscroll/

  • Установите его как: npm install smoothscroll- polyfill
  • Импортируйте его в файл polyfill.ts как: require ('smoothscroll- polyfill'). polyfill();
  • Теперь вы можете использовать параметр поведения scrollIntoView как:

    (document.querySelector('#' + anchor)). scrollIntoView ({поведение: 'smooth'});

Ответ 4

Если вам нужен очень простой переход на якорь, который работает после маршрутизации и внутри маршрутизированных представлений, вы также можете использовать ng2-simple-page-scroll.

<a simplePageScroll href="#myanchor">Go there</a>

Или сразу после маршрутизации:

<a simplePageScroll [routerLink]="['Home']" href="#myanchor">Go there</a>

Он выполняет простой мгновенный скачок, но он работает.

Ответ 5

Для тех, кто все еще ищет поиск плавного прокрутки @alex-j, отлично работает для меня в Angular 2.0 - но мне пришлось изменить сервис Window на следующее: -

import { Injectable } from '@angular/core';

function _window() : any {
    // return the global native browser window object
    return window;
}

@Injectable()
export class WindowRef {
    get nativeWindow() : any {
        return _window();
    }
}

Все реквизиты этого блога http://juristr.com/blog/2016/09/ng2-get-window-ref/ - теперь у меня есть плавная служба прокрутки, которую я могу позвонить из любого места:)

Ответ 6

Я использую этот код.

        var dis = distance  ;
        var interval = setInterval(() => {
            this.document.body.scrollTop = dis;
             dis=dis-5 ;
             if (dis<10){
                 clearInterval(interval);
             }
        }, 5);

Ответ 7

Благодаря принятому ответу я смог реализовать плавный "прокрутка вверх". Прокрутка к вершине на самом деле даже проще, чем прокрутка к определенному целевому элементу, поскольку мы всегда прокручиваем до 0-позиции. Вот код:

scrollTo(yPoint: number, duration: number) {
    setTimeout(() => {
        window.scrollTo(0, yPoint)
    }, duration);
    return;
}

smoothScrollToTop() {
    let startY = this.currentYPosition();
    let stopY = 0; // window top
    let distance = stopY > startY ? stopY - startY : startY - stopY;
    if (distance < 100) {
        window.scrollTo(0, stopY);
        return;
    }
    let speed = Math.round(distance / 100);
    let step = speed;
    speed = Math.max(9, speed); //min 9 otherwise it won't look smooth
    let leapY = stopY > startY ? startY + step : startY - step;
    let timer = 0;
    if (stopY > startY) {
        for (let i = startY; i < stopY; i += step) {
            // since setTimeout is asynchronous, the for-loop will will fire all scrolls
            // nearly simoultaniously. Therefore, we need to multiply the speed with
            // a counter which lets the scrolls start with a growing offset which lets the
            // setTimeout wait for a growing time till it scrolls there
            // that way, we prevent the window to scroll instantly to the target Yposition
            this.scrollTo(leapY, timer * speed);
            leapY += step; if (leapY > stopY) leapY = stopY; timer++;
        }
        return;
    } else {
        for (let i = startY; i > stopY; i -= step) {
            this.scrollTo(leapY, timer * speed);
            leapY -= step; if (leapY < stopY) leapY = stopY; timer++;
        }
    }
}

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;
}

Если вы хотите, вы можете позволить своей кнопке "Прокрутка к началу" динамически отображаться при прокрутке пользователя:

@HostListener('window:scroll', ['$event'])
onWindowScroll(event) {
    this.onScrollFadeInOutScrollToTopButton();
}

shouldShowScrollToTop: boolean = false;

onScrollFadeInOutScrollToTopButton() {
    this.shouldShowScrollToTop = (window.pageYOffset >= window.screen.height/2);
}

И HTML для кнопки "Прокрутка вверх":

<div class="back-to-top">
<button *ngIf="shouldShowScrollToTop" [@fadeInOutTrigger]="animateButtonEntryState" class="mat-primary" md-fab (click)="smoothScrollToTop()">^</button>

Как вы можете видеть, эта кнопка также имеет триггер анимации. Вы можете подумать об использовании значка для кнопки, и в идеале ваша кнопка должна иметь стиль position:fixed;.

Ответ 8

Существует другой подход, который следует учитывать: с помощью jQuery.

Возможно, это не так элегантно, как родные решения, но очень просто и отлично работает.

В вашем index.html вы должны добавить это в конец тела:

<script
src="https://code.jquery.com/jquery-3.1.1.min.js"
integrity="sha256-hVVnYaiADRTO2PzUGmuLJr8BLUSjGIZsDYGmIJLv2b8="
crossorigin="anonymous"></script>

<script>
  $(document).on("click", "a[href*='#']:not([href='#'])", function() {
    if (location.pathname.replace(/^\//,'') == this.pathname.replace(/^\//,'') && location.hostname == this.hostname) {
      var target = $(this.hash);
      target = target.length ? target : $('[name=' + this.hash.slice(1) +']');
      if (target.length) {
          $('html, body').animate({
          scrollTop: target.offset().top - 100
          }, 1000);
          return false;
      }
    }
  });

</script>

И теперь вы можете использовать простую навигацию <a href("#section")> следующим образом:

<a href="#section2">Link</a>

Он также работает с маршрутизацией:

<a class="btn" role="button" routerLink="/contact" fragment="contact_form">Contact us!</a>