컴포넌트내에 스크롤 이벤트 감지 로직 - ChoDragon9/posts GitHub Wiki

헤더와 푸터 컴포넌트의 스크롤 이벤트 감지

추상화 대상은 무엇?

추상화 전략은 무엇?

근거는?

결론

배경 설명

컴포넌트의 요구사항은 이렇다.

  • [헤더] 스크롤 시, 태그에 scroll 클래스 추가
  • [푸터] 스크롤 시, Top 버튼 노출

요구 사항은 다르지만 스크롤이라는 동작을 감지해야 한다. 헤더와 푸터의 부모 컴포넌트에서 스크롤을 감지 할수 있지만 헤더와 푸터는 2가지의 레이아웃 컴포넌트에서 사용되고 있다.

content-layout.vue
 ├─ page-header.vue
 ├─ contents.vue
 └─ page-footer.vue

project-layout.vue
 ├─ page-header.vue
 ├─ alarm.vue
 └─ page-footer.vue

중복되는 로직은 이런 형태이다. 두 클래스의 중복은 상수, 함수, 라이프 사이클 훅 부분이 중복된다. 요구사항은 다른 시점에 추가되었으며 의도적으로 네이밍도 동일하게 중복되게 구현했다. 이유는 중복되었음을 쉽게 식별할 수 있기 때문이다.

class PageHeader extends Vue {
  readonly SCROLL_EVENT = 'scroll'
  readonly SCROLL_LIMIT = 10

  isScrolling = ToggleHelper.create()

  handleScroll(): void {
    if (window.scrollY > this.SCROLL_LIMIT) {
      this.isScrolling.on()
    } else {
      this.isScrolling.off()
    }
  }

  mounted(): void {
    window.addEventListener(this.SCROLL_EVENT, this.handleScroll)
  }

  beforeDestroy(): void {
    window.removeEventListener(this.SCROLL_EVENT, this.handleScroll)
  }
}
class PageFooter extends Vue {
  readonly SCROLL_EVENT = 'scroll'
  readonly SCROLL_LIMIT = 10

  topButton = ToggleHelper.create()

  handleScroll(): void {
    if (window.scrollY > this.SCROLL_LIMIT) {
      this.topButton.on()
    } else {
      this.topButton.off()
    }
  }

  mounted(): void {
    window.addEventListener(this.SCROLL_EVENT, this.handleScroll)
  }

  beforeDestroy(): void {
    window.removeEventListener(this.SCROLL_EVENT, this.handleScroll)
  }
}

고려사항

  • 컴포넌트를 사용할 때만 스크롤 이벤트를 감지해야 한다.
    • 컴포넌트의 생명주기와 스크롤 감지가 같아야 한다.
  • 상태와 로직의 중복이기 때문에 클래스를 통해 해결한다.

해결방안

스크롤 이벤트를 감지하는 클래스를 만들어 해결

export class ScrollDetector {
  readonly SCROLL_EVENT = 'scroll'
  readonly SCROLL_LIMIT = 10
  private toggleDetection = ToggleHelper.create()

  get isScrolled(): boolean {
    return this.toggleDetection.isOn
  }

  private handleScroll = (): void => {
    window.scrollY > this.SCROLL_LIMIT
      ? this.toggleDetection.on()
      : this.toggleDetection.off()
  }

  start(): void {
    window.addEventListener(this.SCROLL_EVENT, this.handleScroll)
  }

  stop(): void {
    window.removeEventListener(this.SCROLL_EVENT, this.handleScroll)
  }

  static create(): ScrollDetector {
    return new ScrollDetector()
  }
}