프로젝트 진행 전에 컴포넌트를 활용할 확률이 많을 것으로 판단되어서 미리 R&D를 진행 했었고, 그 테스트를 통한 가정을 프로젝트 실전에 적용을 해보려고 시도했다.
일단 예상했던 부분은 카드 디자인들을 컴포넌트로 많이 사용하지않을까로 예측했었는데 막상 카드들의 생성 자체가 for문으로 반복 생성된 부분들이어서 이를 굳이 컴포넌트화 시킬 필요는 없겠다고 판단했다.
따라서 페이지별로 반복되게 사용되는 부분을 찾아보니 '헤더+타이틀'과 '푸터'였고 이 두 가지 부분만 컴포넌트화 해보기로 결정했다.
지난번에 미리 진행해 본 방법대로 진행을 해보았는데…
(웹 컴포넌트 테스트 1 - https://designerdk.tistory.com/6)
(웹 컴포넌트 테스트 2 - https://designerdk.tistory.com/7)
아니나 다를까 페이지 이동을 했더니 템플릿을 불러오지 못하는 문제가 발생했다.
(지난번 테스트 때는 페이지 이동을 안해봤었다.) 역시 테스트와 실전은 다르고 항상 변수가 발생하는구나라는 걸 몸소 체감했다.
매 페이지마다 템플릿을 넣어주는 것은 컴포넌트화 하는 의미가 없어지기 때문에 효과적인 방법을 gpt와 함께 강구해보았다.
1. 매 탬플릿을 페이지마다 복제해서 넣어주지 않는다.
2. 그러면서도 슬롯을 통해 컴포넌트의 장점인 커스터마이즈 속성을 사용할 수 있게 한다.
이 두가지를 충족하면 되겠다고 판단하고 열심히 찾아보았다.
그렇게해서 이런 컴포넌트 js파일을 구축할 수 있었고 이렇게 사용하면 위 문제들을 해결할 수 있었다.
<이번에 활용해 본 웹컴포넌트의 기본 폼>
class FooterComponent extends HTMLElement {
constructor() {
super();
this.attachShadow({ mode: 'open' });
// 직접 템플릿을 포함
const template = document.createElement('template');
template.innerHTML = `html 내용`;
const content = template.content.cloneNode(true);
this.shadowRoot.appendChild(content);
}
}
customElements.define('footer-component', FooterComponent);
<헤더+타이틀 컴포넌트>
class HeaderComponent extends HTMLElement {
constructor() {
super();
this.attachShadow({ mode: 'open' });
// 직접 템플릿을 포함
const template = document.createElement('template');
template.innerHTML = `
<style>
.home-btn {
display: flex;
height: 50px;
justify-content: center;
align-items: center;
background-color: var(--surface-primary);
}
.home-btn img {
width: 140px;
height: 36px;
}
</style>
<a class="home-btn" href="index.html">
<img src="/data/kinderseoul_logo.svg" alt="">
</a>
<slot name="title-slot"></slot>
`;
const content = template.content.cloneNode(true);
this.shadowRoot.appendChild(content);
}
}
customElements.define('header-component', HeaderComponent);
<푸터 컴포넌트>
class FooterComponent extends HTMLElement {
constructor() {
super();
this.attachShadow({ mode: 'open' });
// 직접 템플릿을 포함
const template = document.createElement('template');
template.innerHTML = `
<style>
footer {
height: 46px;
display: flex;
justify-content: space-between;
align-items: center;
background-color: var(--surface-gray);
padding: var(--large-padding);
}
footer img {
position: absolute;
left: 50%;
transform: translateX(-50%);
}
.footer-info {
color: var(--texticon-darkgray);
}
</style>
<footer>
<div class="footer-info text-body-small-m">ⓒ 2024. Designer DK All rights reserved.</div>
<img src="/data/dk_logo.svg" alt="">
<div class="footer-info">Contact : tupacalypse@naver.com</div>
</footer>
`;
const content = template.content.cloneNode(true);
this.shadowRoot.appendChild(content);
}
}
customElements.define('footer-component', FooterComponent);
js마다 html을 일일이 넣어야한다는 단점은 있지만 어떤 페이지에서든 당겨서 사용 가능하고 속성을 빼야할 경우 slot으로 커스터마이즈가 가능하다.
특히 이번 프로젝트의 경우 푸터는 고정 내용이지만 헤더는 타이틀부분이 매 페이지마다 내용이 변경되기 때문에 커스터마이즈 속성이 필요했고 그에따라 slot을 사용했다.
<header-component>
<h1 slot="title-slot" class="text-title-l">
<span class="highlight">킨더서울</span>에서 ‘서울시 유치원 정보’를 찾아보세요!
</h1>
</header-component>
컴포넌트로 적용된 헤더+타이틀 부분
앞으로 진행해가면서 또다른 문제점을 발견할수도 있긴하겠지만 일단 내가 원했던 웹컴포넌트의 목적을 잘 구현한 부분들은 만족한다.