Прокрутка к элементу при нажатии в Angular 4


110

Я хочу иметь возможность прокручиваться к цели при нажатии кнопки. Я думал примерно так.

<button (click)="scroll(#target)">Button</button>

А по моему component.tsметоду вроде.

scroll(element) {
    window.scrollTo(element.yPosition)
}

Я знаю, что приведенный выше код недействителен, но просто чтобы показать, о чем я думал. Я только начал изучать Angular 4, не имея опыта работы с Angular. Я искал что-то подобное, но все примеры находятся в AngularJs, который сильно отличается от Angular 4


1
У вашего синтаксиса нет проблем, но вам нужно определить, что такое #target.
wannadream

1
Так это должно работать? Когда я использую произвольный номер и вызываю window.scrollTo (500) в своей функции, ничего не происходит. Я думал, что этот элемент будет HTMLElement

Но что такое #target, Angular его не разрешит? Вы можете сначала протестировать scroll () без параметров.
wannadream

Да, я пробовал (click) = "scroll ()" в моей кнопке и window.scrollTo (0, 500) в компоненте, но ничего не

2
Но когда я делаю window.scrollTo (0, 500) в конструкторе с задержкой 500 мс, он работает

Ответы:


161

Сделать это можно так:

<button (click)="scroll(target)"></button>
<div #target>Your target</div>

а затем в вашем компоненте:

scroll(el: HTMLElement) {
    el.scrollIntoView();
}

Изменить: я вижу комментарии, в которых говорится, что это больше не работает из-за того, что элемент не определен. Я создал пример StackBlitz в Angular 7, и он все еще работает. Может кто-нибудь привести пример, когда это не работает?


1
@ N15M0_jk Да, есть еще объект, который можно передать с другими параметрами, в зависимости от того, что вам нужно. developer.mozilla.org/en-US/docs/Web/API/Element/scrollIntoView
Фрэнк Модика,

1
@Anthony Он позволяет вам ссылаться на элемент, который вы хотите передать scrollфункции компонента. Обратите внимание, что событие щелчка вызывает scroll(target). Если вы хотите получить доступ к элементу изнутри компонента без необходимости передавать элемент, вы можете использовать @ViewChild.
Фрэнк Модика,

2
Теперь у меня все работает нормально. Но прежде, чем я сделал глупую ошибку и использовал id="target"вместо, #targetэто дало мне "el is undefined error"!
yashthakkar1173

1
Я считаю , что неопределенная ошибка происходит , если элемент с #targetявляется внутри *ngIf, но он должен работать , если вы используете @ViewChildметод в связи с @abbastec
spectacularbob

1
просто и аккуратно. У меня работает в Angular 10
griffinleow

53

Вот как я это сделал с помощью Angular 4.

Шаблон

<div class="col-xs-12 col-md-3">
  <h2>Categories</h2>
  <div class="cat-list-body">
    <div class="cat-item" *ngFor="let cat of web.menu | async">
      <label (click)="scroll('cat-'+cat.category_id)">{{cat.category_name}}</label>
    </div>
  </div>
</div>

добавьте эту функцию в компонент.

scroll(id) {
  console.log(`scrolling to ${id}`);
  let el = document.getElementById(id);
  el.scrollIntoView();
}

1
Вы не установили elementRefs или HTML-идентификаторы в своем шаблоне. Где именно находится элемент cat - + cat.category_id, к которому вы прокручиваете?
Киган

1
Это лучший ответ. Вы можете поместить свиток в другой компонент.
Дейл Нгуен

1
Это должен быть принятый ответ. Работа для Angular 9.
Шестнадцать,

49

На самом деле существует чистый javascript-способ сделать это без использования setTimeoutили requestAnimationFrameили jQuery.

Короче говоря, найдите в scrollView элемент, который вы хотите прокрутить, и используйте scrollIntoView.

el.scrollIntoView({behavior:"smooth"});

Вот такой плункр .


3
2 способа отличить этот ответ: 1. Это анимированная плавная прокрутка, а не прыжок. 2. Этот ответ не прокручивает окно, а перемещает прокрутку внутри окна. Например, если у вас есть горизонтальная прокрутка в окне. Посмотрите пример на plunkr.
Джон

1
scrollIntoView's scrollIntoViewOptions (объект как аргумент) сейчас совместим только с Firefox.
Хесус Фуэнтес

Прекрасно работает для Chrome и Firefox, но не для Safari.
Рион

37

В Angular 7 работает отлично

HTML

<button (click)="scroll(target)">Click to scroll</button>
<div #target>Your target</div>

В компоненте

scroll(el: HTMLElement) {
    el.scrollIntoView({behavior: 'smooth'});
}

2
бонус за {behavior: 'smooth'}
Рецепты

У меня это работает .. особая благодарность за {поведение: 'smooth'}
Вибху Кумар

1
Это не сработает, если #targetоно определено после кнопки, что актуально, например, если у вас есть плавающий заголовок ...
Джонатан

22

У Джона есть правильный ответ, и это работает в моих проектах angular 5 и 6.

Если бы я хотел щелкнуть для плавной прокрутки от панели навигации к нижнему колонтитулу:

<button (click)="scrollTo('.footer')">ScrolltoFooter</button>
<footer class="footer">some code</footer>

scrollTo(className: string):void {
   const elementList = document.querySelectorAll('.' + className);
   const element = elementList[0] as HTMLElement;
   element.scrollIntoView({ behavior: 'smooth' });
}

Поскольку я хотел вернуться к заголовку из нижнего колонтитула, я создал службу, в которой находится эта функция, и внедрил ее в компоненты навигационной панели и нижнего колонтитула и передал в «верхний колонтитул» или «нижний колонтитул», где это необходимо. просто не забудьте указать в объявлениях компонентов используемые имена классов:

<app-footer class="footer"></app-footer>

15

Другой способ сделать это в Angular:

Разметка:

<textarea #inputMessage></textarea>

Добавить ViewChild()недвижимость:

@ViewChild('inputMessage')
inputMessageRef: ElementRef;

Прокрутите любое место внутри компонента, используя scrollIntoView()функцию:

this.inputMessageRef.nativeElement.scrollIntoView();

12

Вы можете прокрутить до любого элемента в вашем представлении, используя блок кода ниже. Обратите внимание, что цель (идентификатор элемента ) может быть в любом допустимом теге html.

На просмотре (файл HTML)

<div id="target"> </div>
<button (click)="scroll()">Button</button>
 

  

в .tsфайле,

scroll() {
   document.querySelector('#target').scrollIntoView({ behavior: 'smooth', block: 'center' });
}

7

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

Вот пример в stackblitz

шаблон компонента:

<div class="other-content">
      Other content
      <button (click)="element.scrollIntoView({ behavior: 'smooth', block: 'center' })">
        Click to scroll
      </button>
    </div>
    <div id="content" #element>
      Some text to scroll
</div>

7

В Angular вы можете использовать ViewChildand ElementRef: дать вашему HTML-элементу ссылку

<div #myDiv > 

и внутри вашего компонента:

import { ViewChild, ElementRef } from '@angular/core';
@ViewChild('myDiv') myDivRef: ElementRef;

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


Это хорошее решение, но проблема в том, что оно работает только при перезагрузке вкладки, но не с routerLink. Любое решение этой проблемы, ребята?
Ахсан,

0

Мне нужно проделать этот трюк, возможно потому, что я использую собственный HTML-элемент. Если я этого не сделаю, targetу onItemAmounterClickменя не будет scrollIntoViewметода

.html

<div *ngFor"...">
      <my-component #target (click)="clicked(target)"></my-component>
</div>

.ts

onItemAmounterClick(target){
  target.__ngContext__[0].scrollIntoView({behavior: 'smooth'});
}

-8

Я сделал что-то вроде того, о чем вы просите, просто используя jQuery для поиска элемента (например, document.getElementById(...)) и используя .focus()вызов.


3
Действительно ли jQuery нужен при использовании Angular? Похоже, что Angular должно хватить

Не уверен на 100%, но я был в среде, которая не была проверена и не подвергнута рефакторингу для Angular2, поэтому я не стал слишком усердно искать решение в Angular и просто выбрал то, к чему, как я знал, у меня будет доступ.
Кеннет Саломон

8
Вы не должны использовать Jquery и Angular
Stefdelec

2
Да, да, я многому научился, и все отмечают, что мне не следует использовать jQuery. Вы не говорите ничего, что другие не прокомментировали прямо над вами.
Кеннет Саломон

Проголосовал за смирение. Я хотел бы добавить, что ответы jQuery имеют некоторую ценность для тех, кто переходит на платформу SPA. Показывая, как мы это делали, и просматривая комментарии, рекомендующие другие решения.
B2K

-17

Вы можете сделать это с помощью jquery:

код ts:

    scrollTOElement = (element, offsetParam?, speedParam?) => {
    const toElement = $(element);
    const focusElement = $(element);
    const offset = offsetParam * 1 || 200;
    const speed = speedParam * 1 || 500;
    $('html, body').animate({
      scrollTop: toElement.offset().top + offset
    }, speed);
    if (focusElement) {
      $(focusElement).focus();
    }
  }

html-код:

<button (click)="scrollTOElement('#elementTo',500,3000)">Scroll</button>

Примените это к элементам, которые вы хотите прокрутить:

<div id="elementTo">some content</div>

Вот образец stackblitz.


1
За исключением того, что эта операция просит, чтобы решения TypeScript не работали с устаревшей структурой (голосование отклонено)
пепел

это машинописное решение.
Gns

1
Вы упустили мою точку зрения, в вашем ответе используется jQuery (могу ли я добавить это самым неэффективным способом), а не просто использование ES *. Ваши константы также не объявляют свой тип. Это просто плохой пример с плохой логикой с использованием jQuery, которого не спрашивали.
ash
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.