Как использовать привязные ссылки в Angular 6 без обновления страницы? [Дубликат]

Это может быть реализовано с помощью модуля pause :

---
- hosts: server01
  gather_facts: True
  tasks:
    - pause:
        prompt: please enter the name for the target [{{ ansible_hostname }}]
      register: prompt

    - debug:
        msg: "{{ prompt.user_input if prompt.user_input else ansible_hostname }}"

82
задан Stone 19 March 2016 в 13:31
поделиться

21 ответ

Я только что получил эту работу на своем собственном веб-сайте, поэтому я решил, что стоит разместить мое решение здесь.

<a [routerLink]="baseUrlGoesHere" fragment="nameOfYourAnchorGoesHere">Link Text!</a>

<a name="nameOfYourAnchorGoesHere"></a>
<div>They're trying to anchor to me!</div>

И затем в вашем компоненте убедитесь, что вы включили это:

 import { ActivatedRoute } from '@angular/router';

 constructor(private route: ActivatedRoute) { 
     this.route.fragment.subscribe ( f => {
         const element = document.querySelector ( "#" + f )
         if ( element ) element.scrollIntoView ( element )
     });
 }
1
ответ дан a_lovelace 18 August 2018 в 06:54
поделиться
  • 1
    Я думаю, что лучше писать только element.scrollIntoView() или element.scrollIntoView(true). Ваша версия не скомпилировалась для меня (возможно, из-за строгихNullChecks?). – David L. 15 January 2018 в 16:03

Добавляя к ответ Калёяна , эта подписка привязана к маршрутизатору и будет жить до тех пор, пока страница не будет полностью обновлена. При подписке на события маршрутизатора в компоненте обязательно отмените подписку в ngOnDestroy:

import { OnDestroy } from '@angular/core';
import { Router, NavigationEnd } from '@angular/router';
import { Subscription } from "rxjs/Rx";

class MyAppComponent implements OnDestroy {

  private subscription: Subscription;

  constructor(router: Router) {
    this.subscription = router.events.subscribe(s => {
      if (s instanceof NavigationEnd) {
        const tree = router.parseUrl(router.url);
        if (tree.fragment) {
          const element = document.querySelector("#" + tree.fragment);
          if (element) { element.scrollIntoView(element); }
        }
      }
    });
  }

  public ngOnDestroy() {
    this.subscription.unsubscribe();
  }
}
2
ответ дан DBosley 18 August 2018 в 06:54
поделиться
  • 1
    Я думал, что подписки на маршруты событий автоматически срываются. – user 22 April 2018 в 17:06

Простое решение, которое работает для страниц без каких-либо параметров запроса, совместимо с браузером назад / вперед, маршрутизатором и глубокой связью.

<a (click)="jumpToId('anchor1')">Go To Anchor 1</a>


ngOnInit() {

    // If your page is dynamic
    this.yourService.getWhatever()
        .then(
            data => {
            this.componentData = data;
            setTimeout(() => this.jumpToId( window.location.hash.substr(1) ), 100);
        }
    );

    // If your page is static
    // this.jumpToId( window.location.hash.substr(1) )
}

jumpToId( fragment ) {

    // Use the browser to navigate
    window.location.hash = fragment;

    // But also scroll when routing / deep-linking to dynamic page
    // or re-clicking same anchor
    if (fragment) {
        const element = document.querySelector('#' + fragment);
        if (element) element.scrollIntoView();
    }
}

Тайм-аут - это просто позволить странице загружать любую динамическую данные «защищены» с помощью * ngIf. Это также можно использовать для прокрутки до верхней части страницы при изменении маршрута - просто укажите основной якорный тег по умолчанию.

1
ответ дан Graham Hotchkiss 18 August 2018 в 06:54
поделиться

Решения выше не работали для меня ... Это сделало это:

Сначала подготовьте MyAppComponent для автоматической прокрутки в ngAfterViewChecked () ...

import { Component, OnInit, AfterViewChecked } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
import { Subscription } from 'rxjs';

@Component( {
   [...]
} )
export class MyAppComponent implements OnInit, AfterViewChecked {

  private scrollExecuted: boolean = false;

  constructor( private activatedRoute: ActivatedRoute ) {}

  ngAfterViewChecked() {

    if ( !this.scrollExecuted ) {
      let routeFragmentSubscription: Subscription;

      // Automatic scroll
      routeFragmentSubscription =
        this.activatedRoute.fragment
          .subscribe( fragment => {
            if ( fragment ) {
              let element = document.getElementById( fragment );
              if ( element ) {
                element.scrollIntoView();

                this.scrollExecuted = true;

                // Free resources
                setTimeout(
                  () => {
                    console.log( 'routeFragmentSubscription unsubscribe' );
                    routeFragmentSubscription.unsubscribe();
                }, 1000 );

              }
            }
          } );
    }

  }

}

Затем перейдите к my-app-route, отправив prodID hashtag

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

@Component( {
   [...]
} )
export class MyOtherComponent {

  constructor( private router: Router ) {}

  gotoHashtag( prodID: string ) {
    this.router.navigate( [ '/my-app-route' ], { fragment: prodID } );
  }

}
4
ответ дан JavierFuentes 18 August 2018 в 06:54
поделиться
  • 1
    Вниз голосование без комментариев или объяснений ... это не очень хорошая практика ... – JavierFuentes 9 June 2017 в 19:39
  • 2
    Спасибо за голосование в Up, значит, это сработало и для вас ... это решение действительно спасло мой день! – JavierFuentes 11 June 2017 в 12:07
  • 3
    Это сработало для меня! Зачем использовать ngAfterViewChecked вместо ngInit? – Antoine Boisier-Michaud 18 June 2017 в 16:26
  • 4
    Спасибо @ AntoineBoisier-Michaud за ваш положительный отзыв. ng Init не срабатывает всегда в моем проекте ... ngAfterViewChecked делает это. Можете ли вы продвинуть это решение, пожалуйста? Благодарю. – JavierFuentes 18 June 2017 в 18:54

После прочтения всех решений я искал компонент, и я нашел тот, который выполняет именно то, что задал первоначальный вопрос: прокрутка для привязки ссылок. https://www.npmjs.com/package/ng2-scroll-to

Когда вы его устанавливаете, вы используете синтаксис, например:

// app.awesome.component.ts
@Component({
   ...
   template: `...
        <a scrollTo href="#main-section">Scroll to main section</a>
        <button scrollTo scrollTargetSelector="#test-section">Scroll to test section</a>
        <button scrollTo scrollableElementSelector="#container" scrollYTarget="0">Go top</a>
        <!-- Further content here -->
        <div id="container">
            <section id="main-section">Bla bla bla</section>
            <section id="test-section">Bla bla bla</section>
        <div>
   ...`,
})
export class AwesomeComponent {
}

Это сработало очень хорошо для меня.

2
ответ дан John 18 August 2018 в 06:54
поделиться
  • 1
    Используйте колесо, не изобретайте его снова;) – Yogen Rai 11 November 2017 в 09:09
  • 2
    Вы посмотрели код этого компонента? Он выглядит очень хрупким - в проекте также есть 14 открытых проблем, которые включают в себя такие вещи, как элемент, который не существует, задает нуль, а не прокручивает элемент, проблемы с поддержкой браузера. – Drenai 24 January 2018 в 18:00
  • 3
    не работает, когда у вас есть дочерний элемент (дочерний объект имеет привязанные объекты и / или имена привязок) в родительском компоненте, он просто обновляет страницу – Sasha Bond 1 June 2018 в 21:45

Немного поздно, но вот ответ, который я нашел, работает:

<a [routerLink]="['/path']" fragment="test" (click)="onAnchorClick()">Anchor</a>

И в компоненте:

constructor( private route: ActivatedRoute, private router: Router ) {}

  onAnchorClick ( ) {
    this.route.fragment.subscribe ( f => {
      const element = document.querySelector ( "#" + f )
      if ( element ) element.scrollIntoView ( element )
    });
  }

Вышеприведенное не позволяет автоматически перейти к представлению если вы уже приземлились на страницу с якорем, поэтому я использовал решение выше в моем ngInit, чтобы он мог работать и с этим:

ngOnInit() {
    this.router.events.subscribe(s => {
      if (s instanceof NavigationEnd) {
        const tree = this.router.parseUrl(this.router.url);
        if (tree.fragment) {
          const element = document.querySelector("#" + tree.fragment);
          if (element) { element.scrollIntoView(element); }
        }
      }
    });
  }

Обязательно импортируйте Router, ActivatedRoute и NavigationEnd в начало вашего компонента, и все должно быть хорошо.

Источник

15
ответ дан Josh1billion 18 August 2018 в 06:54
поделиться
  • 1
    Работает на меня! Если вы хотите перейти на ту же страницу, на которой вы уже работаете, используйте [routerLink] = & quot; ['.'] & Quot; – Raoul 11 February 2018 в 19:16
  • 2
    & Quot; [ '../ yourPath'] & Quot; тоже работает;) – Maurice 24 June 2018 в 12:26
  • 3
    не могли бы вы объяснить дальше? эта часть document.querySelector ( "#" + f ) дает мне ошибку, потому что она ожидает селектора, а не строки. – Maurice 24 June 2018 в 14:02
  • 4
    @Maurice для меня это работает: element.scrollIntoView() (без передачи element в функцию). Чтобы сделать его гладким, используйте это: element.scrollIntoView({block: "end", behavior: "smooth"}). – Mr. B. 16 July 2018 в 10:22
  • 5

Обновить

Теперь поддерживается

<a [routerLink]="['somepath']" fragment="Test">Jump to 'Test' anchor </a>
this._router.navigate( ['/somepath', id ], {fragment: 'test'});

Добавить код ниже вашего компонента для прокрутки

  import {ActivatedRoute} from '@angular/router'; // <-- do not forget to import

  private fragment: string;

  constructor(private route: ActivatedRoute) { }

  ngOnInit() {
    this.route.fragment.subscribe(fragment => { this.fragment = fragment; });
  }

  ngAfterViewInit(): void {
    try {
      document.querySelector('#' + this.fragment).scrollIntoView();
    } catch (e) { }
  }

Оригинал

Это известная проблема и отслеживается в https://github.com/angular/angular/issues/6595

70
ответ дан M98 18 August 2018 в 06:54
поделиться
  • 1
    @invot переменная со строкой (например, вопрос 123 в вопросе), предполагая, что маршрут маршрута ожидает такой параметр, как { path: 'users/:id', ....} – Günter Zöchbauer 6 September 2016 в 19:30
  • 2
    Если вы хотите прокрутить до якоря, см. Этот пост: github.com/angular/angular/issues/6595 – Pere Pages 11 January 2017 в 16:13
  • 3
    Примечание: это еще не прокрутка – Martín Coll 14 February 2017 в 09:48
  • 4
    Это не прокрутка к якорю ... – shaikhspear 19 February 2017 в 07:15
  • 5
    да, это работает с setTimeout, если я найду лучшее решение, я дам вам знать – Amr Abdulaziz Ibrahim 21 September 2017 в 15:03

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

<div [routerLink]="['somepath']" fragment="Test">
  <a href="#Test">Jump to 'Test' anchor </a>
</div>
1
ответ дан Martin Cremer 18 August 2018 в 06:54
поделиться

Я только что проверил очень полезный плагин, доступный в nmp - ngx-scroll-to , который отлично работает для меня. Однако он предназначен для Angular 4+, но, возможно, кто-то найдет этот ответ полезным.

0
ответ дан mpro 18 August 2018 в 06:54
поделиться

Я пробовал большинство из этих решений, но столкнулся с проблемами, которые уходили и возвращались с другим фрагментом, и это не сработало, поэтому я сделал что-то немного другое, что работает на 100%, и избавляется от уродливого хэша в URL.

tl; dr вот лучший способ, чем то, что я видел до сих пор.

import { Component, OnInit, AfterViewChecked, OnDestroy } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
import { Subscription } from 'rxjs/Subscription';

@Component({
    selector: 'app-hero',
    templateUrl: './hero.component.html',
    styleUrls: ['./hero.component.scss']
})
export class HeroComponent implements OnInit, AfterViewChecked, OnDestroy {
    private fragment: string;
    fragSub: Subscription;

    constructor(private route: ActivatedRoute) { }

    ngOnInit() {
        this.fragSub = this.route.fragment.subscribe( fragment => { this.fragment = fragment; })
    }

    ngAfterViewChecked(): void {
        try {
            document.querySelector('#' + this.fragment).scrollIntoView({behavior: 'smooth'});
            window.location.hash = "";
          } catch (e) { }
    }

    ngOnDestroy() {
        this.fragSub.unsubscribe();
    }
}
0
ответ дан Pang 18 August 2018 в 06:54
поделиться

Несмотря на то, что ответ Гюнтера верен, он не охватывает «переход к» части метки привязки.

Поэтому дополнительно к:

<a [routerLink]="['somepath']" fragment="Test">Jump to 'Test' anchor </a>
this._router.navigate( ['/somepath', id ], {fragment: 'test'});

... в компоненте (родительском), где вам нужно поведение «перейти к», добавьте:

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

class MyAppComponent {
  constructor(router: Router) {

    router.events.subscribe(s => {
      if (s instanceof NavigationEnd) {
        const tree = router.parseUrl(router.url);
        if (tree.fragment) {
          const element = document.querySelector("#" + tree.fragment);
          if (element) { element.scrollIntoView(true); }
        }
      }
    });

  }
}

Обратите внимание, что это обходной путь! Следуйте этой проблеме github для будущих обновлений. Кредиты на Виктор Савкин за предоставление решения!

37
ответ дан Sibiraj 18 August 2018 в 06:54
поделиться
  • 1
    оно работает. благодаря – ruucm 20 November 2017 в 06:42
  • 2
    У меня нет сомнений. – asela nuwan 8 January 2018 в 12:04
  • 3
    это работает, вы спасли мой день, спасибо! – Terai 4 March 2018 в 18:58
  • 4
    привет, я создаю страницу часто задаваемых вопросов, на которой вы можете перейти к ответу, нажав на вопрос, заданный в списке вверху страницы. Таким образом, пользователь уже находится на текущей странице, когда он прыгает на якорь. Если я хочу, чтобы атрибут routerLink работал, я должен дать значение "['../faq']" в качестве значения, иначе он попытается перейти к / faq / faq / # anchor, insteaf of / faq / # anchor. Это правильный способ сделать это или есть более элегантный способ ссылаться на текущую страницу в routerlink? Кроме того, document.querySelector("#" + tree.fragment); дает мне не допустимую ошибку выбора. Вы уверены, что это правильно? – Maurice 24 June 2018 в 12:23
  • 5
  • 6
    – The Muffin Man 28 October 2018 в 19:00

Вот еще один способ обхода проблемы с ответом на JavierFuentes:

<a [routerLink]="['self-route', id]" fragment="some-element" (click)="gotoHashtag('some-element')">Jump to Element</a>

в скрипте:

import {ActivatedRoute} from "@angular/router";
import {Subscription} from "rxjs/Subscription";

export class Links {
    private scrollExecuted: boolean = false;

    constructor(private route: ActivatedRoute) {} 

    ngAfterViewChecked() {
            if (!this.scrollExecuted) {
              let routeFragmentSubscription: Subscription;
              routeFragmentSubscription = this.route.fragment.subscribe(fragment => {
                if (fragment) {
                  let element = document.getElementById(fragment);
                  if (element) {
                    element.scrollIntoView();
                    this.scrollExecuted = true;
                    // Free resources
                    setTimeout(
                      () => {
                        console.log('routeFragmentSubscription unsubscribe');
                        routeFragmentSubscription.unsubscribe();
                      }, 0);
                  }
                }
              });
            }
          }

        gotoHashtag(fragment: string) {
            const element = document.querySelector("#" + fragment);
            if (element) element.scrollIntoView(element);
        }
}

Это позволяет пользователю напрямую прокручивать элемент, если пользователь сразу приземляется страница с hashtag в url.

Но в этом случае я подписал маршрут Fragment в ngAfterViewChecked, но ngAfterViewChecked() вызывается непрерывно на каждый ngDoCheck, и он не позволяет пользователю прокручивать назад, поэтому routeFragmentSubscription.unsubscribe вызывается после тайм-аута в 0 миллисекундов после того, как представление прокручивается в элемент.

Кроме того, метод gotoHashtag определен для прокрутки к элементу, когда пользователь специально нажимает на тег привязки.

Обновление:

Если url имеет querystrings, [routerLink]="['self-route', id]" в якоре не будет сохранять повторы. Я попробовал следующее обходное решение для этого же:

<a (click)="gotoHashtag('some-element')">Jump to Element</a>

constructor( private route: ActivatedRoute,
              private _router:Router) {
}
...
...

gotoHashtag(fragment: string) {
    let url = '';
    let urlWithSegments = this._router.url.split('#');

    if(urlWithSegments.length){
      url = urlWithSegments[0];
    }

    window.location.hash = fragment;
    const element = document.querySelector("#" + fragment);
    if (element) element.scrollIntoView(element);
}
0
ответ дан Vicky Gonsalves 18 August 2018 в 06:54
поделиться

Ни один из предыдущих ответов не работал для меня. В последнем попытке я попытался в своем шаблоне:

<a (click)="onClick()">From Here</a>
<div id='foobar'>To Here</div>

С этим в моем .ts:

onClick(){
    let x = document.querySelector("#foobar");
    if (x){
        x.scrollIntoView();
    }
}

И он работает как ожидается для внутренних ссылок. Это фактически не использует теги привязки, чтобы он вообще не касался URL.

13
ответ дан Wenqin Chen 18 August 2018 в 06:54
поделиться
0
ответ дан Abderrahim Taleb 6 September 2018 в 20:38
поделиться
1
ответ дан Anand Tyagi 6 September 2018 в 20:38
поделиться
0
ответ дан baptistemm 6 September 2018 в 20:38
поделиться
0
ответ дан Baptiste Mille-Mathias 30 October 2018 в 01:56
поделиться
0
ответ дан Hrvoje Golcic 30 October 2018 в 01:56
поделиться
0
ответ дан Naheed Shareef 30 October 2018 в 01:56
поделиться
0
ответ дан Abderrahim Taleb 30 October 2018 в 01:56
поделиться
1
ответ дан आनंद 30 October 2018 в 01:56
поделиться
Другие вопросы по тегам:

Похожие вопросы: