1. 모달창 닫기 구현하기
# 기존 코드 (app.js)
constructor($target) {
this.$target = $target;
...
this.imageInfo = new ImageInfo({
$target,
data: {
visible: false,
image: null
}
});
}
# 닫기 버튼 추가 (1)
// imageInfo.js 의 render 메서드.
render() {
if (this.data.visible) {
const { name, url, temperament, origin } = this.data.image;
this.$imageInfo.innerHTML = `
<div class="content-wrapper">
<div class="title">
<span>${name}</span>
<div class="close">x</div>
</div>
<img src="${url}" alt="${name}"/>
<div class="description">
<div>성격: ${temperament}</div>
<div>태생: ${origin}</div>
</div>
</div>`;
this.$imageInfo.style.display = "block";
} else {
this.$imageInfo.style.display = "none";
}
// render 메서드에 이벤트 리스너 추가
document.addEventListener('click', (e) => {
if (
e.target == document.querySelector('.imageInfo') ||
e.target == document.querySelector('.close')
) this.$imageInfo.style.display = 'none';
}
- 이런 식으로 작성해줘도 물론 동작은 잘 되지만, 선언적 프로그래밍의 지향점과는 다른 듯 하다.
# 선언적 프로그래밍에 맞는 코드
// app.js의 constructor 중 imageInfo 초기화 부분
constructor($target) {
...
this.imageInfo = new ImageInfo({
$target,
data: {
visible: false,
image: null,
},
onClose: () => {
this.imageInfo.setState({
visible: false,
image: null,
});
},
});
}
// imageInfo.js의 constructor 부분
constructor({ $target, data, onClose }) {
const $imageInfo = document.createElement("div");
$imageInfo.className = "ImageInfo";
this.$imageInfo = $imageInfo;
$target.appendChild($imageInfo);
this.data = data;
this.onClose = onClose;
$target.addEventListener("click", (e) => {
if (
e.target == document.querySelector(".ImageInfo") ||
e.target == document.querySelector(".close")
) {
this.onClose();
}
});
$target.addEventListener("keydown", (e) => {
if (e.keyCode == 27) this.onClose();
});
this.render();
}
- searchResult나 다른 코드의 구조를 참고해서 최대한 비슷하게 짜봤다.
- 다른 모듈들과 마찬가지로, 상태 갱신 => reder 메서드 호출 이므로 onclose 메서드를 새로 추가해 'click' 이벤트가 발생했으며 조건이 부합한다면 app에서 정의한 onclose메서드가 실행되도록 짰다.
- app.js에서 정의한 onclose에 의해 해당 imageInfo의 setState 값이 변경되어 render에서 걸러진다.