class로 UI 컴포넌트 만들기

With·2021년 9월 9일
0

App

1. PageComponent의 역할

PageComponent는 index.htmlbody의 콘텐츠가 포함될 main 에 삽입될 ul 태그를 동적으로 생성하는 class 다.

이 class 를 이용하면, class=page 속성을 가진 ul 태그가 생성되고, 생성된 태그가 attachTo(parent, position) 라는 메서드를 통해 정해진 위치로 삽입된다.

constructor는 이 class의 instance가 생성됨과 동시에 실행되는데 (new PageComponent가 될 때) element 라는 변수가 html tag로 변환되는 과정이 담겨 있다. createElement, setAttribute, textContent 를 통해서 각각 ul 태그 생성, 속성 부여, text 삽입이 된다.

// pate.ts
class PageComponent {
  // 이 컴포넌트에서의 element를 정의
  // 타입은 Typescript 에 내장되어 있는 DOM type으로 정의
  // 정의된 element는 은닉을 위해 private 접근제한자를 설정
  private element: HTMLUListElement;
  
  // 
  constructor() {
    
    // element는 ul tag 이고,
    // class="page" 로 attribute가 설정
    
    this.element = document.createElement("ul");
    this.element.setAttribute("class", "page");
    this.element.textContent = "This is page component";
    
    // method를 정의
    // attachTo 는 부모 node를 파라미터로 받아, 그 부모를 기준으로 지정된 위치에
    // this.element를 삽입하는 method 이다
    // insertAdjacentElement는 DOM node를 지정된 위치에 insert 해주는 DOM api 이다
    
    attachTo(parent: HTMLElement, position: InsertPosition = "afterbegin") {
    	parent.insertAdjacentElement(position, this.element)
    }
  }
  
}

2. ImageComponenet의 역할

class ImageComponent {
  private element: HTMLElement;
  
  contructor(title: string, url: string) {
    // template 라는 html tag는 페이지가 로드될 때 숨겨질 컨텐츠를 보관하고 
    // js를 통해서 표시할 수 있다. 즉 처음에는 render가 되지 않다가 js를 통해 어떤
    // 명령이 실행되면 그것이 렌더링 되도록 구현 할 수 있다.
    
    // template tag 생성
    const template = document.createElement("template");
    
    // <template></template> 안에 넣을 요소들을 삽입
    template.innerHTML = `
	<section class="image">
		<div class="image__holder">
			<img class="image__thumbnail">
			<p class="image__title"></p>
		</div>
	</section>`
    
    // element를 teamplate 안 요소들중 첫 자식 tag (section)으로 initialize 한다.
    // as HTMLElement 와 같이 type assertion 이 필요한 이유  👇
    // firstElementChild 의 type이 Element | null 이지만 확정적으로 '나'는 이것의 타입이 HTMLElement 임을 알기 때문에 assertion을 해준다.
    this.element = template.content.firstElementChild as HTMLElement;
    
    // 그리고, 그 안에서 <img> 태그를 추출하여, 동적으로 src 와 alt 를 설정한다.
    const imageElement = this.element.querySelector(".image__thunmbnail")! as HTMLImageElement;
    
    // attribute set
    imageElement.alt = title;
    imageElement.src = url;
    
    const titleElement = this.element.querySelector(".image__title")! as HTMLParagrapahElement;
    
    // textContent set
    titleElement.textContent = title;
  }
  
  
	// method를 정의
    // attachTo 는 부모 node를 파라미터로 받아, 그 부모를 기준으로 지정된 위치에
    // this.element를 삽입하는 method 이다
    // insertAdjacentElement는 DOM node를 지정된 위치에 insert 해주는 DOM api 이다
  attachTo(parent: HTMLElement, position: InsertPosition = "afterbegin") {
	parent.insertAdjacentElement(position, this.element);
  }

} 

3. app.ts 에서 컴포넌트(PageComponent, ImageComponent) 사용하기

// app.ts

// 생성한 class 를 import 한다.
import { ImageComponent } from "./page/item/image.js";
import { PageCoponents } from "./page/page.js";


class App {
  private readonly page: PageComponent;
  
  constructor(appRoot: HTMLElement){
    
    // PageComponent의 instance를 생성한다.
    this.page = new PageComponent();
    this.page.attachTo(appRoot);
    
    
	// IamgeComponent의 instance를 생성한다.
    const image = new ImageComponent(
      "사진입니다",
      "https:///picsum.photos/600/300"
    );
    
    image.attachTo(appRoot, "beforeend")
  }
}

4. 결과

<!-- index.htmk -->

<body>
  <div class="app">
    <header class="banner">
      <h1 class="banner__title">Motion</h1>
      <ul class="panel">
        <li> <button id="new-image" class="panel-button">이미지</button></li>
        <li> <button id="new-video" class="panel-button">비디오</button></li>
        <li> <button id="new-note" class="panel-button">노트</button></li>
        <li> <button id="new-todo" class="panel-button">할일</button></li>
      </ul>
    </header>
    <main class="document">
      <!-- template가 class에서 생성됨 -->
    </main>
    <footer class="footer">
      <p>copyright by With, All right reserved</p>
    </footer>
  </div>
</body>

View

profile
주니어 프론트엔드 개발자 입니다.

0개의 댓글