우리가 사용하는 대부분의 Web API는 객체지향적으로 설계되어 있다.
다시한번 View 클래스 리마인드
abstract class View<T> {
private _element: HTMLElement | null = null;
// 요소 컨트롤 시 사용하는 data 속성
constructor(public data: T) {}
// 해당 컴포넌트 요소
element() {
if (this._element === null) {
throw new Error("You must call render() before accessing the element.");
} else {
return this._element;
}
}
// 렌더링할 html 요소(템플릿 리터럴)
abstract template(): Html;
// 렌더링 프로세스
render(): HTMLElement {
const wrapEl = document.createElement('div');
wrapEl.innerHTML = this.template().toHtml();
this._element = wrapEl.children[0] as HTMLElement;
this._element.classList.add(this.constructor.name);
this.onRender();
return this._element;
}
// 사용 시 override
protected onRender() {}
}
type Toggle = { on: boolean; };
class SwitchView extends View<Toggle> {
override template() {
// this.data의 값에 따라 on과 off를 구분
return html`
<button class="${this.data.on ? 'on' : ''}">
<span class="toggle"></span>
</button>
`;
}
// 요소에 직접 addEventListener 추가
protected override onRender() {
this.element().addEventListener('click', () =>
this.setOn(!this.data.on) // 현재 상태의 반대값
);
}
setOn(bool: boolean) {
this.data.on = bool;
// 즉각적으로 UI에 변경사항 적용
this.element().classList.toggle('on', bool);
}
}
// body에 렌더링
document.querySelector('#body')!.append(
new SwitchView({ on: false }).render()
);
type Setting = {
title: string;
on: boolean;
};
class SettingItemView extends View<Setting> {
switchView = new SwitchView(this.data);
// this.data가 Setting 타입
override template() {
return html`
<div>
<span class="title">${this.data.title}</span>
${this.switchView}
</div>
`;
}
}
// 렌더링
const setting = { title: 'Wi-Fi', on: false };
document.querySelector('#body')!.append(
new SettingItemView(setting).render()
);
class SettingListView extends View<Setting[]> {
itemViews = this.data.map(setting => new SettingItemView(setting));
override template() {
return html`
<div>
${this.itemViews}
</div>
`;
}
}
// 렌더링
const settings: Setting[] = [
{ title: 'Wi-Fi', on: false },
{ title: 'Bluetooth', on: true },
{ title: 'Sound', on: false },
];
document.querySelector('#body')!.append(
new SettingListView(settings).render()
);