May 27, 2020
개발을 하다보면 스크롤을 잠깐 막아야하는 상황이 발생하곤 한다.
검색바를 예로들어보자. 첫 번째 요구사항은 검색창이 뜨면 backdrop 효과를 주는 것이고, 두 번째는 검색 input영역외의 바깥영역에 스크롤을 했을 때 스크롤을 주지 않는 것이다.
scroll event는 element layer에 상관없이 안쪽 영역의 레이어로 이벤트가 전파된다. 이벤트 버블링 현상인가..? 헷갈리지만 여튼 그렇다.
전파를 막기 위해서는 아래와 같은 방법들이 있다.
export function enableScroll() {
document.querySelector('body').style.overflowY = 'auto';
}
export function disableScroll() {
document.querySelector('body').style.overflowY = 'hidden';
}
⇒ PC에선 문제 없이 작동한다. 하지만 iOS 사파리랑 크롬에서는 무용지물이다.
export function enableScroll() {
document.querySelector('body').style.position = 'relative';
document.querySelector('body').style.height = '100%';
document.querySelector('body').style.width = '100%';
}
export function disableScroll() {
document.querySelector('body').style.position = 'fixed';
document.querySelector('body').style.height = '100%';
document.querySelector('body').style.width = '100%';
}
⇒ mobile keyboard height만큼 스크롤이 됨.
@HostListener('scroll', [ '$event' ])
@HostListener('touchmove', [ '$event' ])
@HostListener('mousewheel', [ '$event' ])
preventScroll(ev) {
ev.preventDefault();
ev.stopPropagation();
}
ngAfterViewInit() {
const events = [ 'scroll', 'mousewheel', 'touchmove' ];
this._sub.push(
from(events).pipe(
mergeMap((event) => fromEvent(this.elementRef.nativeElement, event))
).subscribe((event: Event) => {
event.preventDefault();
event.stopPropagation();
})
);
}
이벤트를 등록하고 preventDefault 메소드와 stopPropagation 메소드를 사용해서 이벤트 전파를 막는 것이다.
<div (mousemove)="preventScroll($event)"</div>
preventScroll(ev) {
ev.preventDefault();
ev.stopPropagation();
}
preventScroll(ev) {
const isOverflow = this.elementRef.nativeElement.scrollHeight > this.elementRef.nativeElement.clientHeight;
if (!isOverflow) {
ev.preventDefault();
ev.stopPropagation();
}
}
container {
max-height: calc(50vh - #{$header-search-input-height} * 2);
overflow-y: scroll;
}
결과 화면