[레벨1 - 미션3] 나만의 유튜브 강의실 기억에 남는 피드백

Nine·2022년 3월 23일
1

우테코가 비대면으로 이루어지고 있지만 제가 집에만 있다고 노는 건 아닙니다. 할 게 엄청 많습니다.

  • 피드백은 할수록 느끼는 거지만 반의 반만 체화시켜도 성공이다!!

💪HTML

태그 속성은 생각보다 대단하다!

태그를 적극 활용하려는 노력이 필요합니다.

  • type: search가 있네요.
<input id="search-input-keyword" type="search" placeholder="검색" class="search-input__keyword">

💪CSS

BEM

  • BEM을 사용하는 시도들이 곳 곳에 보입니다.

💪JS

DOM Select 함수

  • default값을 이용하여 기본을 유지하되, 추가 Element가 있다면 해당 Element만 탐색하는 점에서 유용한 메서드네요! (성능 측면)
const selectDom = (element, parent = document) => parent.querySelector(element);

API 재사용 함수

  • API에 따라 다양하게 사용할 수 있을 텐데 재사용 함수로 만들어보는 건 어떨까요?

Template 분리

  • 템플릿은 보기에 너무 복잡하죠.
  • 템플릿을 생성해주는 메서드들을 따로 분리해보는 건 어떨까요?

Snackbar의 활용

  • 사용성을 고려하여 굉장히 좋은 시도인 것 같아요.
@keyframes fadeIn {
    from {bottom: 0; opacity: 0;}
    to {bottom: 30px; opacity: 1;}
  }

  @keyframes fadeOut {
    from {bottom: 30px; opacity: 1;}
    to {bottom: 0; opacity: 0;}
  }

.snackbar-container.show {
    visibility: visible;
    animation: fadeIn 0.6s, fadeOut 0.6s 3.5s;
}

Custom EventListener

사용 방법 -> MDN 참고했어요.

  • 어떤 곳(form)에서 이벤트가 발생하면 다른 곳(textarea)에서의 값을 가져올 수 있어요.
const form = document.querySelector('form');
const textarea = document.querySelector('textarea');

// 'awesome'이라는 이벤트를 만듭니다.


const eventAwesome = new CustomEvent('awesome', {
  bubbles: true, // bubble 옵션을 true로 하고, 
  detail: { text: () => textarea.value } // detail 안에 전달하고 싶은 데이터를 작성해요.
});

// 'awesome' 이벤트가 발생하면 textarea의 value를 출력합니다.
form.addEventListener('awesome', e => console.log(e.detail.text()));

// form 내부의 textarea에서 input 이벤트가 발생하면,
textarea.addEventListener('input', e => e.target.dispatchEvent(eventAwesome)); // 강제로  dispatchEvent(eventAwesome)을 통해 eventAwesome 이벤트를 발생시킵니다.
  • 크루 중 한 분의 실제 코드를 가져와봤어요.
// 참고로 이 함수는 스크롤 이벤트 리스너 함수의 콜백함수가 될 겁니다!
onScrollVideoList() {
    const { scrollTop, clientHeight, scrollHeight } = this.searchResultVideoList; // 3개의 변수를 가져와서 
    const searchOnScrollEvent = new CustomEvent('searchOnScroll', {
      detail: { scrollTop, clientHeight, scrollHeight }, // serachOnScroll이라는 이벤트가 발생할 때 전달할 값으로 위 3개의 변수를 설정해요.
    });
    this.searchModal.dispatchEvent(searchOnScrollEvent); //스크롤이벤트 발생시 이 값을 전달해주겠다는 겁니다.
  }
  • A 요소와 B 요소가 별도로 역할이 분리되어 있는데 이벤트를 발생시키는 A요소에 있는 값들을 해당 이벤트를 수신하는 상위 컨테이너 B 요소에서 그 전달 받은 값들로 새로운 값으로 가공하거나 변경해서 다른 C 요소에게 전달해야할 때, 각 요소에 대한 의존성을 분리시키고 이벤트에 의존하게 하면서 좀 더 유연하게 처리할 수 있는 장점이 있어요.

<ul>
  <li class="a"> </li>
  <li class="b"> </li>
</ui>

👍 보통 b에서 이벤트 발생했는데, b의 값을 부모인 <ul>에서 b의 값을 받아 가공하고 a에게 넘겨줄 때 사용한다고 이해했어요. 맞는지는 모르겠고 필요성도 잘 모르겠지만 많은 크루들이 사용하더라구요. 그냥 넘겨요!


EventHandler 재사용 함수

addEvent(this.container, {
      eventType: EVENT_TYPE.CLICK,
      selector: '#remove-video-button',
      handler: this.handleClickRemoveButton,
    });

👆좋긴한데 코드가 길어지고 굳이? 라는 생각도 좀 드네요.

👇이건 좀 의미가 있어 보이네요!

export const addEvent = (component, eventType, selector, callback) => {
  const children = [...component.querySelectorAll(selector)];
  const isTarget = (target) => children.includes(target) || target.closest(selector);

  component.addEventListener(eventType, (event) => {
    if (!isTarget(event.target)) {
      return false;
    }
    return callback(event);
  });
};

객체의 인스턴스를 하나로 관리

이걸 싱글톤 패턴이라고 부르네요!

export default class StorageEngine {
  static _instance = null;

  static get instance() {
    if (!StorageEngine._instance) {
      StorageEngine._instance = new StorageEngine();
    }

    return StorageEngine._instance;
  }

DOM Clear하기

this.#myVideoList.replaceChildren();

이벤트 핸들러 네이밍

이벤트핸들러는 on/handle + {target} + {eventType} 이런 식으로 네이밍을 합니다.

예를 들면 onXXXClick/Change, handleXXXClick/Change 같은 식으로요!

this.mainView.bindModalOpenButton(this.onModalOpenButtonClick.bind(this));

Element.closest()

  • 언제까지 타고 갈래요? closest()를 사용해봅시다.
const target = e.target.parentNode.parentNode;

다이어그램

맵을 그려볼까요? 아키텍처 맵은 두 가지로 분리해서 한 번 그려보시면 좋을 것 같아요.

  • 폴더 스트럭쳐: 폴더 스트럭쳐단위로, 서로의 폴더가 어떤걸 참조하고 있는지!

  • SoC: 관심사 단위로 어떤 것들이 어떻게 분리되고 어떻게 참조하고 있는지!

-> 그려보는 것 또한 공부입니다!

profile
함께 웃어야 행복한 개발자 장호영입니다😃

0개의 댓글