कोणीय 2 रूट परिवर्तन पर शीर्ष पर स्क्रॉल करें


295

अपने कोणीय 2 ऐप में जब मैं किसी पृष्ठ को नीचे स्क्रॉल करता हूं और पृष्ठ के निचले भाग में लिंक पर क्लिक करता हूं, तो यह मार्ग बदल देता है और मुझे अगले पृष्ठ पर ले जाता है, लेकिन यह पृष्ठ के शीर्ष पर स्क्रॉल नहीं करता है। परिणामस्वरूप, यदि पहला पृष्ठ लंबा है और 2 पृष्ठ में कुछ सामग्री है, तो यह धारणा देता है कि 2 पृष्ठ में सामग्री का अभाव है। चूंकि सामग्री केवल तभी दिखाई देती है जब उपयोगकर्ता पृष्ठ के शीर्ष पर स्क्रॉल करता है।

मैं घटक के ngInit में पृष्ठ के शीर्ष पर विंडो स्क्रॉल कर सकता हूं, लेकिन क्या कोई बेहतर समाधान है जो स्वचालित रूप से मेरे ऐप के सभी मार्गों को संभाल सकता है?


20
कोणीय 6.1 के बाद से हम उत्सुकता से लोड किए गए मॉड्यूल पर या सिर्फ app.module में {स्क्रॉलप्लस रेस्ट्रिशन: 'सक्षम'} का उपयोग कर सकते हैं और इसे सभी मार्गों पर लागू किया जाएगा। RouterModule.forRoot(appRoutes, { scrollPositionRestoration: 'enabled' })
मानवल

मुइतो ओरिग्रादो सुआ सोलुको फुकियोनो परफ्यूमेंटमेंट पैरा मीम :)
राफेल गोडोई

एक व्यक्ति ने फ़ोकस का उल्लेख नहीं किया? यह एक्सेसिबिलिटी / स्क्रीन रीडर्स को ठीक से सपोर्ट करने के लिए पहले से कहीं अधिक महत्वपूर्ण है और यदि आप बिना फोकस पर ध्यान दिए बस ऊपर स्क्रॉल करते हैं तो अगली टैब कीपर स्क्रीन के निचले हिस्से में जा सकती है।
साइमन_वेअर

जवाबों:


385

आप अपने मुख्य घटक पर मार्ग परिवर्तन श्रोता को पंजीकृत कर सकते हैं और मार्ग परिवर्तन पर शीर्ष पर स्क्रॉल कर सकते हैं।

import { Component, OnInit } from '@angular/core';
import { Router, NavigationEnd } from '@angular/router';

@Component({
    selector: 'my-app',
    template: '<ng-content></ng-content>',
})
export class MyAppComponent implements OnInit {
    constructor(private router: Router) { }

    ngOnInit() {
        this.router.events.subscribe((evt) => {
            if (!(evt instanceof NavigationEnd)) {
                return;
            }
            window.scrollTo(0, 0)
        });
    }
}

11
window.scrollTo(0, 0)की तुलना में अधिक संक्षिप्त है document.body.scrollTop = 0;, और अधिक पठनीय IMO है।
मार्क ई। हासे

10
क्या किसी ने देखा, कि इसे लागू करने के बाद भी, समस्या Iphone के सफारी ब्राउज़र में बनी हुई है। कोई विचार?
rgk

1
@mehaase लगता है कि आपका उत्तर सबसे अच्छा है। window.body.scrollTop फ़ायरफ़ॉक्स डेस्कटॉप पर मेरे लिए काम नहीं करता है। इसलिए धन्यवाद !
केर्केनले

3
यह मेरे लिए काम करता है, लेकिन यह डिफ़ॉल्ट "बैक" बटन व्यवहार को तोड़ देता है। पीछे जाकर पिछली स्क्रॉल स्थिति को याद रखना चाहिए।
जैककिश

6
ये काम किया !! हालाँकि मैंने शीर्ष पर सहज चिकनी स्क्रॉल करने के $("body").animate({ scrollTop: 0 }, 1000);बजाय जोड़ाwindow.scrollTo(0, 0)
Manubhargav

360

कोणीय 6.1 और बाद में :

कोणीय 6.1 (2018-07-25 को जारी) ने "राउटर स्क्रॉल पोजिशन रिस्टोरेशन" नामक एक सुविधा के माध्यम से इस मुद्दे को संभालने के लिए अंतर्निहित समर्थन जोड़ा। जैसा कि आधिकारिक कोणीय ब्लॉग में वर्णित है , आपको बस इस तरह से राउटर कॉन्फ़िगरेशन में सक्षम करने की आवश्यकता है:

RouterModule.forRoot(routes, {scrollPositionRestoration: 'enabled'})

इसके अलावा, ब्लॉग में कहा गया है कि "उम्मीद है कि यह भविष्य की प्रमुख रिलीज में डिफ़ॉल्ट हो जाएगा"। अब तक ऐसा नहीं हुआ है (एंगुलर 8.2 के रूप में), लेकिन आखिरकार आपको अपने कोड में कुछ भी करने की आवश्यकता नहीं होगी, और यह सिर्फ बॉक्स से सही तरीके से काम करेगा।

आप इस सुविधा के बारे में अधिक विवरण देख सकते हैं और आधिकारिक डॉक्स में इस व्यवहार को कैसे अनुकूलित कर सकते हैं ।

कोणीय 6.0 और पूर्ववर्ती :

जबकि @ GuilhermeMeireles का उत्कृष्ट उत्तर मूल समस्या को ठीक करता है, यह एक नया परिचय देता है, जब आप सामान्य व्यवहार को तोड़ते हैं, जब आप वापस या आगे (ब्राउज़र बटन के साथ या कोड में स्थान के माध्यम से) नेविगेट करते हैं। अपेक्षित व्यवहार यह है कि जब आप पृष्ठ पर वापस नेविगेट करते हैं, तो इसे उसी स्थान तक नीचे स्क्रॉल किया जाना चाहिए जब आप लिंक पर क्लिक करते थे, लेकिन हर पृष्ठ पर पहुंचने पर शीर्ष पर स्क्रॉल करना स्पष्ट रूप से इस अपेक्षा को तोड़ता है।

नीचे दिया गया कोड स्थान के PopStateEvent अनुक्रम की सदस्यता लेने और इस तरह के एक घटना का एक परिणाम के रूप में स्क्रॉल-टू-टॉप तर्क को छोड़ कर इस तरह के नेविगेशन का पता लगाने के लिए तर्क का विस्तार करता है।

यदि आप जिस पृष्ठ से वापस नेविगेट करते हैं वह पूरे व्यूपोर्ट को कवर करने के लिए काफी लंबा है, तो स्क्रॉल स्थिति स्वचालित रूप से पुनर्स्थापित हो जाती है, लेकिन @JordanNelson के रूप में सही ढंग से बताया गया है, यदि पृष्ठ छोटा है तो आपको मूल y स्क्रॉल स्थिति का ट्रैक रखने और इसे पुनर्स्थापित करने की आवश्यकता है स्पष्ट रूप से जब आप पृष्ठ पर वापस जाते हैं। कोड का अपडेट किया गया संस्करण इस मामले को भी कवर करता है, हमेशा स्क्रॉल स्थिति को स्पष्ट रूप से बहाल करके।

import { Component, OnInit } from '@angular/core';
import { Router, NavigationStart, NavigationEnd } from '@angular/router';
import { Location, PopStateEvent } from "@angular/common";

@Component({
    selector: 'my-app',
    template: '<ng-content></ng-content>',
})
export class MyAppComponent implements OnInit {

    private lastPoppedUrl: string;
    private yScrollStack: number[] = [];

    constructor(private router: Router, private location: Location) { }

    ngOnInit() {
        this.location.subscribe((ev:PopStateEvent) => {
            this.lastPoppedUrl = ev.url;
        });
        this.router.events.subscribe((ev:any) => {
            if (ev instanceof NavigationStart) {
                if (ev.url != this.lastPoppedUrl)
                    this.yScrollStack.push(window.scrollY);
            } else if (ev instanceof NavigationEnd) {
                if (ev.url == this.lastPoppedUrl) {
                    this.lastPoppedUrl = undefined;
                    window.scrollTo(0, this.yScrollStack.pop());
                } else
                    window.scrollTo(0, 0);
            }
        });
    }
}

2
यह या तो सीधे ऐप कंपोनेंट में जाना चाहिए, या इसमें इस्तेमाल होने वाले एक भी कंपोनेंट में (और इसलिए पूरे ऐप द्वारा शेयर किया जाता है)। उदाहरण के लिए, मैंने इसे एक शीर्ष नेविगेशन बार घटक में शामिल किया है। आपको अपने सभी घटकों में शामिल नहीं करना चाहिए।
फर्नांडो एचेवरिया

3
आप ऐसा कर सकते हैं और यह कोड को अन्य, गैर-ब्राउज़र, प्लेटफार्मों के साथ अधिक व्यापक रूप से संगत बना देगा। कार्यान्वयन विवरणों के लिए stackoverflow.com/q/34177221/2858481 देखें ।
फर्नांडो इचेवरिया

3
यदि आप आधुनिक ब्राउज़रों में बैक / फॉरवर्ड बटन को क्लिक और होल्ड करते हैं, तो एक मेनू दिखाई देता है जो आपको अपने पिछले / अगले एक के अलावा अन्य स्थानों पर नेविगेट करने देता है। यदि आप ऐसा करते हैं तो यह समाधान टूट जाता है। यह अधिकांश के लिए एक किनारे का मामला है, लेकिन ध्यान देने योग्य है।
adamdport


1
क्या नेस्टेड तत्वों के लिए "राउटर स्क्रॉल पोजिशन रिस्टोरेशन" को सक्षम करने का एक तरीका है या यह केवल इसके लिए काम करता है body?
10

61

कोणीय 6.1 से, अब आप परेशानी से बच सकते हैं और दूसरे पैरामीटर के रूप में extraOptionsअपने पास RouterModule.forRoot()कर सकते हैं और scrollPositionRestoration: enabledजब भी मार्ग में परिवर्तन होता है, तो शीर्ष पर स्क्रॉल करने के लिए कोणीय को बता सकते हैं ।

डिफ़ॉल्ट रूप से आपको यह मिलेगा app-routing.module.ts:

const routes: Routes = [
  {
    path: '...'
    component: ...
  },
  ...
];

@NgModule({
  imports: [
    RouterModule.forRoot(routes, {
      scrollPositionRestoration: 'enabled', // Add options right here
    })
  ],
  exports: [RouterModule]
})
export class AppRoutingModule { }

कोणीय आधिकारिक डॉक्स


3
भले ही ऊपर का उत्तर अधिक वर्णनात्मक हो लेकिन मुझे यह पसंद है कि इस उत्तर ने मुझे बताया कि वास्तव में यह कहाँ जाना है
ryanovas

32

आप इस अधिक स्पष्ट रूप से अवलोकनीय filterविधि का लाभ उठाकर लिख सकते हैं :

this.router.events.filter(event => event instanceof NavigationEnd).subscribe(() => {
      this.window.scrollTo(0, 0);
});

यदि आप कोणीय सामग्री 2 sidenav का उपयोग करते समय शीर्ष पर स्क्रॉल करने में समस्या हो रही है तो इससे मदद मिलेगी। विंडो या डॉक्यूमेंट बॉडी में स्क्रॉलबार नहीं होगा इसलिए आपको sidenavकंटेंट कंटेनर प्राप्त करने और उस तत्व को स्क्रॉल करने की आवश्यकता है , अन्यथा विंडो को डिफ़ॉल्ट रूप से स्क्रॉल करने का प्रयास करें।

this.router.events.filter(event => event instanceof NavigationEnd)
  .subscribe(() => {
      const contentContainer = document.querySelector('.mat-sidenav-content') || this.window;
      contentContainer.scrollTo(0, 0);
});

इसके अलावा, कोणीय CDK v6.x में अब एक स्क्रॉलिंग पैकेज है जो स्क्रॉलिंग को संभालने में मदद कर सकता है।


2
महान! मेरे लिए जो काम किया -document.querySelector('.mat-sidenav-content .content-div').scrollTop = 0;
आमिर टुगी

Mtpultz & @AmirTugi पर एक अच्छा गीत ... अभी इसी से निपटना है, और आपने मेरे लिए इसका पालन-पोषण किया है, महाराज! संभवतः अनिवार्य रूप से मेरी खुद की साइड नेवी को रोल करना समाप्त कर देगा क्योंकि md-toolbar की पोजिशन 2 पर अच्छी नहीं खेलती है: फिक्स्ड (शीर्ष पर)। जब तक आप लोगों के विचार हैं .... ????
टिम हरकर

हो सकता है मेरा जवाब मिल गया हो ... stackoverflow.com/a/40396105/3389046
टिम हरकर

16

यदि आपके पास सर्वर साइड रेंडरिंग है, तो आपको सावधान रहना चाहिए windowsकि सर्वर पर कोड का उपयोग न करें, जहां वह चर मौजूद नहीं है। यह कोड को तोड़ने में परिणाम होगा।

export class AppComponent implements OnInit {
  routerSubscription: Subscription;

  constructor(private router: Router,
              @Inject(PLATFORM_ID) private platformId: any) {}

  ngOnInit() {
    if (isPlatformBrowser(this.platformId)) {
      this.routerSubscription = this.router.events
        .filter(event => event instanceof NavigationEnd)
        .subscribe(event => {
          window.scrollTo(0, 0);
        });
    }
  }

  ngOnDestroy() {
    this.routerSubscription.unsubscribe();
  }
}

isPlatformBrowserएक फ़ंक्शन का उपयोग यह जांचने के लिए किया जाता है कि वर्तमान प्लेटफ़ॉर्म जहां ऐप प्रदान किया गया है वह ब्राउज़र है या नहीं। हम इसे इंजेक्शन देते हैं platformId

चर के अस्तित्व की जांच करना भी संभव है windows, इस तरह सुरक्षित होना:

if (typeof window != 'undefined')

1
क्या आपको डी विधि में पैरामीटर के रूप PLATFORM_IDमें इंजेक्ट करने constructorऔर यह मान देने की आवश्यकता नहीं है isPlatformBrowser?
पौल क्रुजित

1
@PierreDuc हाँ, उत्तर गलत है। isPlatformBrowserएक समारोह है और हमेशा सत्य होगा। मैंने इसे अभी संपादित किया है।
लजार लुजुबेनोविक

धन्यवाद! यह अभी सही है! बस एपीआई सत्यापित करें: github.com/angular/angular/blob/…
Raptor

13

बस क्लिक कार्रवाई के साथ यह आसान है

अपने मुख्य घटक में html संदर्भ #scrollContainer बनाते हैं

<div class="main-container" #scrollContainer>
    <router-outlet (activate)="onActivate($event, scrollContainer)"></router-outlet>
</div>

मुख्य घटक में .ts

onActivate(e, scrollContainer) {
    scrollContainer.scrollTop = 0;
}

स्क्रॉल किए जाने वाला तत्व scrollContainerपहले नोड में नहीं हो सकता है , आपको ऑब्जेक्ट में थोड़ी खुदाई करने की आवश्यकता हो सकती है, मेरे लिए यह वास्तव में काम करता हैscrollContainer .scrollable._elementRef.nativeElement.scrollTop = 0
बायरन लोपेज

13

कोणीय ने हाल ही में एक नई सुविधा शुरू की है, अंदर कोणीय मार्ग मॉड्यूल नीचे की तरह परिवर्तन करते हैं

@NgModule({
  imports: [RouterModule.forRoot(routes,{
    scrollPositionRestoration: 'top'
  })],

12

सबसे अच्छा उत्तर एंगुलर गिटहब चर्चा में रहता है ( बदलते मार्ग नए पृष्ठ में शीर्ष पर स्क्रॉल नहीं करता है )।

हो सकता है कि आप केवल रूट राउटर परिवर्तनों में ही शीर्ष पर जाना चाहते हैं (बच्चों में नहीं, क्योंकि आप एक टैब में आलसी लोड वाले मार्गों को लोड कर सकते हैं)

app.component.html

<router-outlet (deactivate)="onDeactivate()"></router-outlet>

app.component.ts

onDeactivate() {
  document.body.scrollTop = 0;
  // Alternatively, you can scroll to top by using this other call:
  // window.scrollTo(0, 0)
}

JoniJnm के लिए पूर्ण क्रेडिट ( मूल पोस्ट )



7

कोणीय 6.1 के रूप में, राउटर एक कॉन्फ़िगरेशन विकल्प प्रदान करता है जिसे कहा जाता है scrollPositionRestoration, यह इस परिदृश्य के लिए पूरा करने के लिए डिज़ाइन किया गया है।

imports: [
  RouterModule.forRoot(routes, {
    scrollPositionRestoration: 'enabled'
  }),
  ...
]

4

यदि आपको शीर्ष पर केवल स्क्रॉल पृष्ठ की आवश्यकता है, तो आप ऐसा कर सकते हैं (सबसे अच्छा समाधान नहीं है, लेकिन तेजी से)

document.getElementById('elementId').scrollTop = 0;

4

यहाँ एक समाधान है जो मैं लेकर आया हूँ। मैंने राउटर इवेंट्स के साथ लोकेशनस्ट्रेगी को जोड़ा। किसी उपयोगकर्ता के वर्तमान में ब्राउज़र इतिहास के माध्यम से पता लगाने पर बूलियन सेट करने के लिए LocationStrategy का उपयोग करना। इस तरह, मुझे URL और y- स्क्रॉल डेटा का एक गुच्छा संग्रहीत करने की आवश्यकता नहीं है (जो कि वैसे भी अच्छी तरह से काम नहीं करता है, क्योंकि प्रत्येक डेटा URL पर आधारित है)। यह उस किनारे के मामले को भी हल करता है जब कोई उपयोगकर्ता किसी ब्राउज़र पर बैक या फॉरवर्ड बटन को होल्ड करने का निर्णय लेता है और केवल एक के बजाय कई पेजों को वापस या फॉरवर्ड करता है।

PS मैंने केवल IE, क्रोम, फ़ायरफ़ॉक्स, सफारी और ओपेरा (इस पोस्ट के रूप में) के नवीनतम संस्करण पर परीक्षण किया है।

उम्मीद है की यह मदद करेगा।

export class AppComponent implements OnInit {
  isPopState = false;

  constructor(private router: Router, private locStrat: LocationStrategy) { }

  ngOnInit(): void {
    this.locStrat.onPopState(() => {
      this.isPopState = true;
    });

    this.router.events.subscribe(event => {
      // Scroll to top if accessing a page, not via browser history stack
      if (event instanceof NavigationEnd && !this.isPopState) {
        window.scrollTo(0, 0);
        this.isPopState = false;
      }

      // Ensures that isPopState is reset
      if (event instanceof NavigationEnd) {
        this.isPopState = false;
      }
    });
  }
}

4

यह समाधान @ फर्नांडोएचेवरिया और @ गुइलहर्मेइरेलेस के समाधान पर आधारित है, लेकिन यह अधिक संक्षिप्त है और पॉपस्टैट तंत्र के साथ काम करता है जो कोणीय राउटर प्रदान करता है। यह कई लगातार नेविगेट के स्क्रॉल स्तर को संग्रहीत और पुनर्स्थापित करने की अनुमति देता है।

हम मानचित्र में प्रत्येक नेविगेशन स्थिति के लिए स्क्रॉल स्थिति संग्रहीत करते हैं scrollLevels। एक बार वहाँ एक popstate घटना, राज्य है कि के बारे में पुनर्स्थापित करने के लिए कोणीय रूटर द्वारा आपूर्ति की है की आईडी है: event.restoredState.navigationId। इसके बाद उस राज्य का अंतिम स्क्रॉल स्तर प्राप्त करने के लिए इसका उपयोग किया जाता है scrollLevels

यदि मार्ग के लिए कोई संग्रहीत स्क्रॉल स्तर नहीं है, तो यह शीर्ष पर स्क्रॉल करेगा जैसा कि आप अपेक्षा करेंगे।

import { Component, OnInit } from '@angular/core';
import { Router, NavigationStart, NavigationEnd } from '@angular/router';

@Component({
    selector: 'my-app',
    template: '<ng-content></ng-content>',
})
export class AppComponent implements OnInit {

  constructor(private router: Router) { }

  ngOnInit() {
    const scrollLevels: { [navigationId: number]: number } = {};
    let lastId = 0;
    let restoredId: number;

    this.router.events.subscribe((event: Event) => {

      if (event instanceof NavigationStart) {
        scrollLevels[lastId] = window.scrollY;
        lastId = event.id;
        restoredId = event.restoredState ? event.restoredState.navigationId : undefined;
      }

      if (event instanceof NavigationEnd) {
        if (restoredId) {
          // Optional: Wrap a timeout around the next line to wait for
          // the component to finish loading
          window.scrollTo(0, scrollLevels[restoredId] || 0);
        } else {
          window.scrollTo(0, 0);
        }
      }

    });
  }

}

बहुत बढ़िया। मुझे विंडो के बजाय एक div को स्क्रॉल करने के लिए थोड़ा कस्टम संस्करण बनाना पड़ा, लेकिन यह काम कर गया। एक महत्वपूर्ण अंतर scrollTopबनाम था scrollY
बीबीसिंगर

4

नीचे दिखाए गए अनुसार @Guilherme Meireles द्वारा प्रदान किए गए सही उत्तर के अलावा , आप नीचे दिखाए गए चिकनी स्क्रॉल जोड़कर अपने कार्यान्वयन को ट्विक कर सकते हैं

 import { Component, OnInit } from '@angular/core';
    import { Router, NavigationEnd } from '@angular/router';

    @Component({
        selector: 'my-app',
        template: '<ng-content></ng-content>',
    })
    export class MyAppComponent implements OnInit {
        constructor(private router: Router) { }

        ngOnInit() {
            this.router.events.subscribe((evt) => {
                if (!(evt instanceof NavigationEnd)) {
                    return;
                }
                window.scrollTo(0, 0)
            });
        }
    }

फिर नीचे स्निपेट जोड़ें

 html {
      scroll-behavior: smooth;
    }

आपकी शैलियों के लिए


1

iphone / ios सफारी के लिए आप एक सेटटाइमआउट के साथ रैप कर सकते हैं

setTimeout(function(){
    window.scrollTo(0, 1);
}, 0);

मेरे मामले में यह भी आवश्यक है कि पृष्ठ रैपिंग एलिमेंट सीएसएस को सेट किया जाए; height: 100vh + 1px;
ट्यूबबाई

1

हाय दोस्तों यह मेरे लिए कोणीय 4 में काम करता है। आपको बस राउटर परिवर्तन पर स्क्रॉल करने के लिए माता-पिता का संदर्भ लेना होगा

layout.component.pug

.wrapper(#outlet="")
    router-outlet((activate)='routerActivate($event,outlet)')

layout.component.ts

 public routerActivate(event,outlet){
    outlet.scrollTop = 0;
 }`

1
पग सीखने की जहमत न उठाते हुए अपने आलस्य को क्षमा करें, लेकिन क्या आप HTML में अनुवाद कर सकते हैं?
कोड़ीबगस्टीन

0

@ फ़र्नान्डो एचेवरिया महान! लेकिन यह कोड हैश राउटर या आलसी राउटर में काम नहीं करता है। क्योंकि वे स्थान परिवर्तन को ट्रिगर नहीं करते हैं। यह कोशिश कर सकते हैं:

private lastRouteUrl: string[] = []
  

ngOnInit(): void {
  this.router.events.subscribe((ev) => {
    const len = this.lastRouteUrl.length
    if (ev instanceof NavigationEnd) {
      this.lastRouteUrl.push(ev.url)
      if (len > 1 && ev.url === this.lastRouteUrl[len - 2]) {
        return
      }
      window.scrollTo(0, 0)
    }
  })
}


0

Routerस्वयं का उपयोग उन मुद्दों का कारण होगा जिन्हें आप लगातार ब्राउज़र अनुभव को बनाए रखने के लिए पूरी तरह से दूर नहीं कर सकते हैं। मेरी राय में सबसे अच्छा तरीका सिर्फ एक रिवाज का उपयोग करना है directiveऔर इसे क्लिक पर स्क्रॉल को रीसेट करने देना है। इसके बारे में अच्छी बात यह है कि यदि आप उसी पर हैं जिस पर urlआप क्लिक करते हैं, तो पृष्ठ शीर्ष पर भी वापस स्क्रॉल करेगा। यह सामान्य वेबसाइटों के अनुरूप है। मूल directiveकुछ इस तरह दिख सकता है:

import {Directive, HostListener} from '@angular/core';

@Directive({
    selector: '[linkToTop]'
})
export class LinkToTopDirective {

    @HostListener('click')
    onClick(): void {
        window.scrollTo(0, 0);
    }
}

निम्नलिखित उपयोग के साथ:

<a routerLink="/" linkToTop></a>

यह अधिकांश उपयोग के मामलों के लिए पर्याप्त होगा, लेकिन मैं कुछ मुद्दों की कल्पना कर सकता हूं जो इससे उत्पन्न हो सकते हैं:

  • universalके उपयोग के कारण पर काम नहीं करता हैwindow
  • परिवर्तन का पता लगाने पर छोटे गति का प्रभाव, क्योंकि यह हर क्लिक से चालू होता है
  • इस निर्देश को अक्षम करने का कोई तरीका नहीं है

इन मुद्दों को दूर करना वास्तव में काफी आसान है:

@Directive({
  selector: '[linkToTop]'
})
export class LinkToTopDirective implements OnInit, OnDestroy {

  @Input()
  set linkToTop(active: string | boolean) {
    this.active = typeof active === 'string' ? active.length === 0 : active;
  }

  private active: boolean = true;

  private onClick: EventListener = (event: MouseEvent) => {
    if (this.active) {
      window.scrollTo(0, 0);
    }
  };

  constructor(@Inject(PLATFORM_ID) private readonly platformId: Object,
              private readonly elementRef: ElementRef,
              private readonly ngZone: NgZone
  ) {}

  ngOnDestroy(): void {
    if (isPlatformBrowser(this.platformId)) {
      this.elementRef.nativeElement.removeEventListener('click', this.onClick, false);
    }
  }

  ngOnInit(): void {
    if (isPlatformBrowser(this.platformId)) {
      this.ngZone.runOutsideAngular(() => 
        this.elementRef.nativeElement.addEventListener('click', this.onClick, false)
      );
    }
  }
}

यह अधिकांश उपयोग-मामलों को ध्यान में रखता है, मूल एक के समान उपयोग के साथ, इसे सक्षम / अक्षम करने के लाभ के साथ:

<a routerLink="/" linkToTop></a> <!-- always active -->
<a routerLink="/" [linkToTop]="isActive"> <!-- active when `isActive` is true -->

यदि आप विज्ञापित नहीं होना चाहते हैं तो विज्ञापन न पढ़ें

एक और सुधार यह देखने के लिए किया जा सकता है कि ब्राउज़र passiveघटनाओं का समर्थन करता है या नहीं । यह कोड को थोड़ा और जटिल कर देगा, और थोड़ा अस्पष्ट है यदि आप इन सभी को अपने कस्टम निर्देश / टेम्प्लेट में लागू करना चाहते हैं। इसलिए मैंने एक छोटी सी लाइब्रेरी लिखी जिसका उपयोग आप इन समस्याओं को दूर करने के लिए कर सकते हैं। ऊपर की तरह ही कार्यक्षमता है, और अतिरिक्त passiveघटना के साथ, आप अपने निर्देश को इस में बदल सकते हैं, यदि आप ng-event-optionsपुस्तकालय का उपयोग करते हैं । तर्क click.pnbश्रोता के अंदर है:

@Directive({
    selector: '[linkToTop]'
})
export class LinkToTopDirective {

    @Input()
    set linkToTop(active: string|boolean) {
        this.active = typeof active === 'string' ? active.length === 0 : active;
    }

    private active: boolean = true;

    @HostListener('click.pnb')
    onClick(): void {
      if (this.active) {
        window.scrollTo(0, 0);
      }        
    }
}

0

यह हैश नेविगेशन सहित सभी नेविगेशन परिवर्तनों के लिए मेरे लिए सबसे अच्छा काम करता है

constructor(private route: ActivatedRoute) {}

ngOnInit() {
  this._sub = this.route.fragment.subscribe((hash: string) => {
    if (hash) {
      const cmp = document.getElementById(hash);
      if (cmp) {
        cmp.scrollIntoView();
      }
    } else {
      window.scrollTo(0, 0);
    }
  });
}

0

इस कोड के पीछे मुख्य विचार एक सरणी में संबंधित स्क्रॉल डेटा के साथ सभी विज़िट किए गए यूआरएल को रखना है। जब भी कोई उपयोगकर्ता किसी पृष्ठ (नेविगेशनस्टार्ट) को छोड़ता है तो यह सरणी अपडेट हो जाती है। जब भी कोई उपयोगकर्ता किसी नए पृष्ठ (नेविगेशनईंड) में प्रवेश करता है, तो हम वाई स्थिति को पुनर्स्थापित करने का निर्णय लेते हैं या इस पृष्ठ पर हमें कैसे प्राप्त होते हैं, इस पर निर्भर नहीं करता है। यदि किसी पृष्ठ पर एक रेफ़रेन्स का उपयोग किया गया था, तो हम 0. तक स्क्रॉल करते थे। यदि ब्राउज़र बैक / फॉरवर्ड फीचर्स का उपयोग किया जाता था, तो हम अपने एरे में सेव किए गए Y पर स्क्रॉल करते हैं। मेरी अंग्रेजी के लिए खेद है :)

import { Component, OnInit, OnDestroy } from '@angular/core';
import { Location, PopStateEvent } from '@angular/common';
import { Router, Route, RouterLink, NavigationStart, NavigationEnd, 
    RouterEvent } from '@angular/router';
import { Subscription } from 'rxjs/Subscription';

@Component({
  selector: 'my-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit, OnDestroy {

  private _subscription: Subscription;
  private _scrollHistory: { url: string, y: number }[] = [];
  private _useHistory = false;

  constructor(
    private _router: Router,
    private _location: Location) {
  }

  public ngOnInit() {

    this._subscription = this._router.events.subscribe((event: any) => 
    {
      if (event instanceof NavigationStart) {
        const currentUrl = (this._location.path() !== '') 
           this._location.path() : '/';
        const item = this._scrollHistory.find(x => x.url === currentUrl);
        if (item) {
          item.y = window.scrollY;
        } else {
          this._scrollHistory.push({ url: currentUrl, y: window.scrollY });
        }
        return;
      }
      if (event instanceof NavigationEnd) {
        if (this._useHistory) {
          this._useHistory = false;
          window.scrollTo(0, this._scrollHistory.find(x => x.url === 
          event.url).y);
        } else {
          window.scrollTo(0, 0);
        }
      }
    });

    this._subscription.add(this._location.subscribe((event: PopStateEvent) 
      => { this._useHistory = true;
    }));
  }

  public ngOnDestroy(): void {
    this._subscription.unsubscribe();
  }
}

0

window.scrollTo()कोणीय 5 में मेरे लिए काम नहीं करता है, इसलिए मैंने इसका उपयोग किया document.body.scrollTopहै,

this.router.events.subscribe((evt) => {
   if (evt instanceof NavigationEnd) {
      document.body.scrollTop = 0;
   }
});

0

यदि आप एक ही मार्ग से विभिन्न घटकों को लोड कर रहे हैं तो आप समान चीज़ को प्राप्त करने के लिए ViewportScroller का उपयोग कर सकते हैं।

import { ViewportScroller } from '@angular/common';

constructor(private viewportScroller: ViewportScroller) {}

this.viewportScroller.scrollToPosition([0, 0]);

0

विंडो स्क्रॉल शीर्ष
दोनों window.pageYOffset और document.documentElement.scrollTop सभी मामलों में एक ही परिणाम देता है। IE9 के नीचे window.pageYOffset समर्थित नहीं है।

app.component.ts

import { Component, HostListener, ElementRef } from '@angular/core';

@Component({
  selector: 'my-app',
  templateUrl: './app.component.html',
  styleUrls: [ './app.component.css' ]
})
export class AppComponent  {
  isShow: boolean;
  topPosToStartShowing = 100;

  @HostListener('window:scroll')
  checkScroll() {

    const scrollPosition = window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop || 0;

    console.log('[scroll]', scrollPosition);

    if (scrollPosition >= this.topPosToStartShowing) {
      this.isShow = true;
    } else {
      this.isShow = false;
    }
  }

  gotoTop() {
    window.scroll({ 
      top: 0, 
      left: 10, 
      behavior: 'smooth' 
    });
  }
}

app.component.html

<style>
  p {
  font-family: Lato;
}

button {
  position: fixed;
  bottom: 5px;
  right: 5px;
  font-size: 20px;
  text-align: center;
  border-radius: 5px;
  outline: none;
}
  </style>
<p>
  Lorem ipsum dolor sit, amet consectetur adipisicing elit. Minus, repudiandae quia. Veniam amet fuga, eveniet velit ipsa repudiandae nemo? Sit dolorem itaque laudantium dignissimos, rerum maiores nihil ad voluptates nostrum.
</p>
<p>
  Lorem ipsum dolor sit, amet consectetur adipisicing elit. Minus, repudiandae quia. Veniam amet fuga, eveniet velit ipsa repudiandae nemo? Sit dolorem itaque laudantium dignissimos, rerum maiores nihil ad voluptates nostrum.
</p>
<p>
  Lorem ipsum dolor sit, amet consectetur adipisicing elit. Minus, repudiandae quia. Veniam amet fuga, eveniet velit ipsa repudiandae nemo? Sit dolorem itaque laudantium dignissimos, rerum maiores nihil ad voluptates nostrum.
</p>
<p>
  Lorem ipsum dolor sit, amet consectetur adipisicing elit. Minus, repudiandae quia. Veniam amet fuga, eveniet velit ipsa repudiandae nemo? Sit dolorem itaque laudantium dignissimos, rerum maiores nihil ad voluptates nostrum.
</p>
<p>
  Lorem ipsum dolor sit, amet consectetur adipisicing elit. Minus, repudiandae quia. Veniam amet fuga, eveniet velit ipsa repudiandae nemo? Sit dolorem itaque laudantium dignissimos, rerum maiores nihil ad voluptates nostrum.
</p>
<p>
  Lorem ipsum dolor sit, amet consectetur adipisicing elit. Minus, repudiandae quia. Veniam amet fuga, eveniet velit ipsa repudiandae nemo? Sit dolorem itaque laudantium dignissimos, rerum maiores nihil ad voluptates nostrum.
</p>
<p>
  Lorem ipsum dolor sit, amet consectetur adipisicing elit. Minus, repudiandae quia. Veniam amet fuga, eveniet velit ipsa repudiandae nemo? Sit dolorem itaque laudantium dignissimos, rerum maiores nihil ad voluptates nostrum.
</p>
<p>
  Lorem ipsum dolor sit, amet consectetur adipisicing elit. Minus, repudiandae quia. Veniam amet fuga, eveniet velit ipsa repudiandae nemo? Sit dolorem itaque laudantium dignissimos, rerum maiores nihil ad voluptates nostrum.
</p>

<button *ngIf="isShow" (click)="gotoTop()">👆</button>
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.