App.js
const API_ENDPOINT = "api url이 들어갑니다."
const api = {
fetchCats: async keyword => {
try{
const response = await fetch(`${API_ENDPOINT}/api/items/search?q=${keyword}`);
if(response.ok)
return await response.json();
}catch(e){
console.error(e);
}
},
itemId: async id => {
try{
const response = await fetch(`${API_ENDPOINT}/api/items/${id}`);
if(response.ok)
return await response.json();
}catch(e){
console.error(e);
}
}
};
SearchResult.js
class SearchResult {
$searchResult = null;
data = null;
onClick = null;
constructor({ $target, initialData, onClick }) {
this.$searchResult = document.createElement("div");
this.$searchResult.className = "SearchResult";
$target.appendChild(this.$searchResult);
this.data = initialData;
this.onClick = onClick;
this.render();
window.addEventListener('scroll', (e) => {
let scrollLocation = document.documentElement.scrollTop;
let windowHeight = window.innerHeight;
let fullHeight = document.body.scrollHeight;
if(scrollLocation + windowHeight >= fullHeight){
this.appendPage();
}
});
}
//[D] Data추가
appendPage() {
const list = this.data
.map(
cat => {
const div = document.createElement('div');
div.className = "item";
div.innerHTML =
`
<img src=${cat.url} alt=${cat.name} />
<div class="hover">${cat.name}</div>
`;
this.$searchResult.appendChild(div);
});
this.$searchResult.querySelectorAll(".item").forEach(($item, index) => {
$item.addEventListener("click", () => {
this.onClick(this.data[index]);
});
});
}
setState(nextData) {
this.data = nextData;
this.render();
}
render() {
if(this.data.length !== 0){
this.$searchResult.innerHTML = this.data
.map(
item => `
<div class="item">
<img src=${item.url} alt=${item.name} />
<div class="hover">${item.name}</div>
</div>
`
)
.join("");
this.$searchResult.querySelectorAll(".item").forEach(($item, index) => {
$item.addEventListener("click", () => {
this.onClick(this.data[index]);
});
});
}else {
this.$searchResult.innerHTML =`
<strong>검색된 결과가 없습니다</strong>
`
}
}
}
const TEMPLATE = '<input type="text">';
class SearchInput {
constructor({ $target, onSearch, onClick }) {
const box = document.createElement('div');
box.className = 'box';
const $searchInput = document.createElement("input");
this.$searchInput = $searchInput;
this.$searchInput.placeholder = "아이템을 검색해보세요.|";
// [D] autofocus 추가
this.$searchInput.setAttribute('autofocus','autofocus');
$searchInput.className = "SearchInput";
this.$randomButton = document.createElement('button');
this.$randomButton.className ='button';
box.appendChild(this.$searchInput);
box.appendChild(this.$randomButton);
$target.appendChild(box);
$searchInput.addEventListener("keyup", e => {
if (e.keyCode === 13) {
onSearch(e.target.value);
}
});
this.$randomButton.addEventListener("click", () => {
onClick();
});
}
render() {}
}
ImageInfo.js
class ImageInfo {
$imageInfo = null;
data = null;
constructor({ $target, data }) {
const $imageInfo = document.createElement("div");
$imageInfo.className = "ImageInfo";
this.$imageInfo = $imageInfo;
$target.appendChild($imageInfo);
this.data = data;
this.render();
this.$imageInfo.addEventListener('click', (e) => {
const className = e.target.className;
if(className ==='ImageInfo' || className === 'close') {
this.fadeOut(this.$imageInfo);
}
})
window.onkeyup = (e) => {
var key = e.keyCode ? e.keyCode : e.which;
if(key === 27){
if(this.$imageInfo.style.display === 'block')
this.fadeOut(this.$imageInfo);
}
}
}
setState(nextData) {
this.data = nextData;
this.render();
}
fadeOut(element) {
var op = 1;
var timer = setInterval(function () {
if (op <= 0.1){
clearInterval(timer);
element.style.display = 'none';
}
element.style.opacity = op;
element.style.filter = 'alpha(opacity=' + op * 100 + ")";
op -= op * 0.1;
}, 50);
}
fadeIn(element) {
var op = 0.1;
element.style.display = 'block';
var timer = setInterval(function () {
if (op >= 1){
clearInterval(timer);
}
element.style.opacity = op;
element.style.filter = 'alpha(opacity=' + op * 100 + ")";
op += op * 0.1;
}, 10);
}
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>`;
} else {
this.$imageInfo.style.display = "none";
}
}
}
Loading.js
const template = `
<div class="loading"></div>
<div id="loading-text">loading</div>
`;
class LoadingInfo {
$loadingInfo = null;
data = null;
constructor({ $target, data }) {
const $loadingInfo = document.createElement("div");
$loadingInfo.className = "loading-container";
this.$loadingInfo = $loadingInfo;
this.data = data;
this.$loadingInfo.style.display = this.data.visible ? 'block' : 'none';
$target.appendChild($loadingInfo);
this.render();
}
onChange() {
this.data.visible = !this.data.visible;
this.$loadingInfo.style.display = this.data.visible ? 'block' : 'none';
}
render() {
this.$loadingInfo.innerHTML = template;
}
}