import { ElementRef, Injectable, QueryList } from '@angular/core';
import { Subject } from 'rxjs';
@Injectable({
providedIn: 'root',
})
export class ScrollService {
subject$ = new Subject(); // 스크롤 이벤트를 전달하기 위한 Subject 객체
select(index: number) {
this.subject$.next(index); // 주어진 인덱스를 Subject에 전달하여 구독자들에게 알림
}
scrollTo(found: ElementRef<HTMLElement>) {
if (found) {
const layout = document.querySelector('#layout'); // id가 'layout'인 요소를 가져옴
// 스크롤 위치 계산
const top =
found.nativeElement.getBoundingClientRect().top +
layout.scrollTop -
layout.clientTop -
70;
if (layout) {
layout.scrollTo({
top: top,
behavior: 'smooth', // 부드러운 스크롤 동작 설정
});
}
}
}
observe(sections: QueryList<ElementRef<HTMLElement>>) {
this.subject$.subscribe((index: number) => {
const found = sections.find((section, i) => i === index); // 주어진 인덱스에 해당하는 요소를 찾음
this.scrollTo(found); // 해당 요소로 스크롤 이동
});
}
}
<section #sections></section>
<section #sections></section>
<section #sections></section>
<section #sections></section>
<section #sections></section>
@ViewChildren('sections') sections!: QueryList<ElementRef<HTMLElement>>;
ngAfterViewInit(): void { // 템플릿이 전부 그려진 후
this.scrollService.observe(this.sections); // 섹션들 HTML 객체 타입으로 전달
}
3.. 컴포넌트 내부
QueryList
는 Angular에서 제공하는 컬렉션 타입으로, 여러 개의 DOM 요소에 대한 참조를 저장하고 관리하는 기능을 제공합니다. QueryList
는 주로 @ViewChildren
데코레이터와 함께 사용되어 템플릿에서 선택자를 사용하여 여러 DOM 요소를 참조하는 데 유용합니다.
요소 추가 및 제거: QueryList
는 동적으로 요소를 추가하거나 제거할 수 있는 기능을 제공합니다. 즉, DOM에 새로운 요소가 추가되거나 삭제되면 QueryList
도 자동으로 업데이트됩니다.
요소 순회: QueryList
는 forEach()
메서드를 통해 내부에 저장된 요소들을 순회할 수 있습니다. 이를 통해 각 요소에 접근하고 작업을 수행할 수 있습니다.
변경 감지: QueryList
는 내부 요소의 상태 변경을 감지할 수 있습니다. 예를 들어, 요소의 속성이 변경되면 QueryList
는 이를 감지하여 자동으로 업데이트됩니다.
이벤트 감지: QueryList
는 내부 요소에서 발생하는 이벤트를 감지할 수 있습니다. 이를 통해 특정 이벤트에 대한 처리를 수행하거나 상호작용할 수 있습니다.
따라서, 주어진 코드에서 sections
변수는 QueryList<ElementRef<HTMLElement>>
타입으로 선언되어 여러 DOM 요소의 참조를 저장하고 관리합니다. 이를 통해 템플릿에서 선택자를 사용하여 해당 요소들에 접근하고 조작할 수 있습니다. 변경된 요소에 대한 업데이트 및 이벤트 감지도 자동으로 처리됩니다.
<div
class="flex flex-col justify-start gap-2.5 cursor-pointer p-2 bg-gray-50"
*ngFor="let child of menu.children; index as i"
>
<div (click)="_scrollTo(i)">
<div
class="font-semibold text-sm text-gray-800 hover:bg-gray-100 py-2 rounded-xl px-10 w-full"
>
<p>{{ child.name }}</p>
</div>
</div>
</div>
_scrollTo(index: number) {
this.scrollService.select(index);
}