프로젝트를 만들다 보면 js를 통해서 html의 요소를 추가해야하는 경우가 자주 있다.

특히나 어떠한 상호작용(서버에서 특정 데이터를 가져온다던지, 페이지 내에서의 input value의 값을 출력해야한다던지 등)에 의해서 html의 요소가 변경된다거나 추가 또는 삭제되어야 하는 경우가 있을 것이다.

이러한 기능을 수행하기에 여러 방법들이 있을텐데 이에 대한 각각의 장단점을 알아보고자 한다.

물론 마지막에 결합되거나 만들어진 문자열로 된 html 코드를 innerHTML을 통해서 넘겨주어야 하는 것은 동일하다.

다양한 방법에 대한 예를 들기 위해서 index.html 내에 존재하는 div class='container' 이라고 하는 태그 내에 <ul>로 감싸진 많은 <li> 태그와 <h1> 태그 등의 다른 태그들이 생성되어야 한다고 가정해보자.

1. 단계적 추가 방법

html의 요소에 <ul> 등의 태그를 생성하는 createElement() 코드를 작성하고 <ul> 태그 내에 들어갈 <li> 의 수만큼 반복문을 통해서 추가하는 방법이 있을 것이다.

const container = documnet.getElementByClassName('container');

const ul = createElement('ul');

const fruits = ['apple', 'banana', 'cherry']

container.appendChild(ul);

for(let i=0; i<3; ++i) {
    const h1 = createElement('h1');
    h1.innerHTML = `${i} fruit`;
    const li = createElement('li');
    li.innerHTML = `is ${fruits[i]}`;
}

배열로 된 아이템들을 출력할 때에 forEach() 를 이용한 방법 또한 가능하다. for문에 비해 장점으로는 배열의 개수가 변경되는 것에 맞추어 i 의 범위를 재수정할 필요가 없다는 것이다.

2. 배열내에 순서대로 추가한 후에 문자열로 바꾸는 방법

빈배열을 생성하고 html에 추가될 코드들을 빈배열에 순차적으로 넣은 후 문자열로 변환하여 완성된 html 코드를 innerHTML 하는 방법

const container = documnet.getElementByClassName('container');
const fruitsList= [];
const fruits = ['apple', 'banana', 'cherry'];

fruitsList.push('<ul>');

fruits.forEach((fruit,idx) => {
    fruitsList.push(`
    <h1>${idx} fruit</h1>
    <li>is ${fruit}</li>
    `)
});

fruitsList.push('</ul>');

container.innerHTML = fruitsList.join('');

<li> 태그의 경우는 <ul> 태그 내에서 반복되지만, <ul> 태그는 그렇지 않다. 따라서 먼저 <ul> 태그를 맨 앞과 맨 뒤에 추가하였고 반복되어 추가되어야할 <li>forEach() 를 통해서 반복 생성하여 배열에 추가하였다.

마지막에 join('') 을 통해서 배열을 하나의 문자열로 생성하여 html 코드를 생성한 방법이다.

#1 과 #2 방법은 간단한 html 코드에 나쁘지 않을 수 있다라고 생각할 수 있겠지만 코드가 더욱 복잡해지고 담을 정보가 많다라고 가정하였을 경우에 어떤 형식을 갖춘 html 코드인지 명확히 알 수 없고 복잡하다. 이를 조금 더 명확하게 하기 위해 템플릿 방식의 html 코드를 추가하는 방법이 있다.

3. 템플릿 방식을 통한 방법

말 그대로 추가할 html 코드, 특히 동일하거나 자주 반복되는 코드에 대한 형식을 미리 갖춘 템플릿을 만들고 템플릿 내의 교체될 부분에 네이밍을 하여 해당 공간을 실제 값과 바꾸는 방식이다.

const container = documnet.getElementByClassName('container');
const title = ['과일', '음식'];
const fruits = ['사과', '바나나', '체리'];
const food = ['김치', '찌개', '부침개']
const NO = ['1st', '2nd', '3rd'];

let template = `
    <h1>
        {{__category_title__}}
    </h1>
    <ul>
        {{__category_list__}}
    </ul>
`;

const List = [];
function makeList(category) {
    for(let i =0; i<3; ++i) {
        List.push(`
            <li>
                <h2>NO[i]</h2>
                category[i]
            </li>
        `);
    }
}
makeList(fruits);
template = template.replace('{{__category_title__}}', title[1]);
template = template.replace('{{__category_list__}}', List.join(''));
container.innerHTML = template;

makeList(food);
template = template.replace('{{__category_title__}}', title[2]);
template = template.replace('{{__category_list__}}', List.join(''));
container.innerHTML = template;

이 방식은 template를 통해서 html의 구성이 더욱 잘보이지만 단점이라고 한다면, replace 되어야 할 부분이 많다면 그만큼 코드가 늘어난다.

하지만 이를 보안하기 위한 템플릿 라이브러리들이 존재하기 때문에 이를 활용하여 이를 통해서 보안할 수 있다.

대표적인 라이브러리로 handlebars 가 있다.