장인의 DOM 생성 코드를 템플릿 엔진으로 대체

배경



실행중인 응용 프로그램을 변경할 때 장인의 DOM 생성 코드를 읽는 것이 어려울 수 있습니다.
예를 들면, 다음과 같이 장인적으로 HTML Document Object를 작성
function createElement(id, data) {
  const element = document.createElement('div')
  element.setAttribute('id', id)
  element.setAttribute('title', 'id: ' + data.id + ', pred: ' + data.pred + ', value: ' + data.value)
  element.setAttribute('origin-id', data.id)
  element.setAttribute('type', data.value)
  element.setAttribute('pred', data.pred)
  element.classList.add('textae-editor__attribute')
  element.innerText = data.value

  const popUpEditorElement = document.createElement('div')
  popUpEditorElement.classList.add('textae-editor__attribute-buttons')

  const editButtonElement = document.createElement('div')
  editButtonElement.classList.add('textae-editor__attribute-button')
  editButtonElement.classList.add('textae-editor__attribute-button--edit')
  editButtonElement.setAttribute('title', 'Edit this attribute.')

  const deleteButtonElement = document.createElement('div')
  deleteButtonElement.classList.add('textae-editor__attribute-button')
  deleteButtonElement.classList.add('textae-editor__attribute-button--delete')
  deleteButtonElement.setAttribute('title', 'Delete this attribute.')

  popUpEditorElement.appendChild(editButtonElement)
  popUpEditorElement.appendChild(deleteButtonElement)

  element.appendChild(popUpEditorElement)
}

jQuery.append()를 사용하여 DOM을 추가하는 소스 코드가 있다고 가정합니다.
$(parent).append(createElement(id, data))

도전



이 소스 코드에서 렌더링되는 HTML을 직관적으로 읽는 것은 어렵습니다.
DOM의 구조를 수정하고 싶을 때 변경 위치를 식별하기가 어렵습니다.
자주 하는 대응에서는, 소스 코드를 조금 바꾸어 렌더링되는 내용의 변화를 확인하면서, 변경 부분을 특정해 갑니다.

대응할 수 있습니다만, 변경 빈도가 높을 때는 수고가 바보가 되지 않습니다.

리팩토링 기법



템플릿 엔진을 도입하고 소스 코드에 렌더링 후 HTML 이미지를 그대로 씁니다.
여기에서는 Handlebars.js 을 사용합니다.

절차 1. Google 크롬 개발 콘솔을 사용하여 렌더링 후 HTML을 가져옵니다.



Google 크롬에서 대상 DOM을 선택하고 컨텍스트 메뉴에서 Copy> Copy outerHTML을 선택합니다.



다음 HTML을 얻을 수 있습니다.
<div id="editor1__AA1" title="id: A1, pred: example_predicate_1, value: attr1" origin-id="A1" type="attr1" pred="example_predicate_1" class="textae-editor__attribute">attr1
  <div class="textae-editor__attribute-buttons">
    <div class="textae-editor__attribute-button textae-editor__attribute-button--edit" title="Edit this attribute."></div>
    <div class="textae-editor__attribute-button textae-editor__attribute-button--delete" title="Delete this attribute."></div>
  </div>
</div>

2단계. 템플릿으로 대체할 위치 설정



Handlebars.js에서 {{}}로 묶인 문자열을 지정된 값으로 바꿉니다.
JavaScript에서는 템플릿 문자열을 사용하면 줄 바꿈을 포함하는 문자열을 소스 코드에 쓸 수 있습니다.
다음과 같은 소스 코드입니다.
const source = `
<div id="{{id}}" title="{{title}}" origin-id="{{originId}}" type="{{value}}" pred="{{pred}}" class="textae-editor__attribute">{{value}}
  <div class="textae-editor__attribute-buttons">
    <div class="textae-editor__attribute-button textae-editor__attribute-button--edit" title="Edit this attribute."></div>
    <div class="textae-editor__attribute-button textae-editor__attribute-button--delete" title="Delete this attribute."></div>
  </div>
</div>
`

절차 3. HTML 생성



이들을 조합하여 HTML을 생성하는 코드를 작성합니다.
예를 들면 다음과 같은 소스 코드가 됩니다.
import Handlebars from 'handlebars'

const source = `
<div id="{{id}}" title="{{title}}" origin-id="{{originId}}" type="{{value}}" pred="{{pred}}" class="textae-editor__attribute">{{value}}
  <div class="textae-editor__attribute-buttons">
    <div class="textae-editor__attribute-button textae-editor__attribute-button--edit" title="Edit this attribute."></div>
    <div class="textae-editor__attribute-button textae-editor__attribute-button--delete" title="Delete this attribute."></div>
  </div>
</div>
`
const template = Handlebars.compile(source)

function createHtml(id, attribute) {
  return template({
    id,
    title: `id: ${attribute.id}, pred: ${attribute.pred}, value: ${attribute.value}`,
    originId: attribute.id,
    value: attribute.value,
    pred: attribute.pred
  })
}

이 함수는 createElement 함수와 동등한 내용을 생성합니다.
차이는 생성하는 것이 DOM Element인지 HTML 문자열인지의 차이입니다.

4단계. createElement를 createHtml로 바꾸기



jQuery.append 은 인수에 HTML 문자열을 받을 수 있습니다.
호출하는 함수를 바꾸는 것만으로 대응이 완료됩니다.
$(parent).append(createHtml(id, data))



jQuery를 사용하지 않고 Node.appendChild()을 사용하는 경우, 예를 들어 다음 소스 코드
parent.appendChild(createElement(id, data))

Node.appendChild()는 인수에 DOM 요소만 허용합니다.
DOM의 아무 곳이나 HTML 문자열을 삽입하려면 element.insertAdjacentHTML을 사용하십시오.
parent.insertAdjacentHTML('beforeend', createHtml(id, data))

참고


  • innerHTML에서 insertAdjacentHTML 사용 - Qiita
  • 좋은 웹페이지 즐겨찾기