오늘은 고양이 사진 검색 사이트 해설의 마지막 강의인 추가 요구 사항 3가지를 해결하는 내용이다
마지막 강의에서는 엄청 중요한 기능은 아니지만 사용자 경험을 향상시킬 수 있는 추가적인 기능 구현에 대해 진행된다
이번 강의를 통해서 더 많은 것을 알아가야겠다
# 추가 요구 사항 해결
# 추가 요구 사항 1
1. 최근 검색어 input 창에 마우스 호버시에만 보이도록 하기
SearchInput 컴포넌트 내에 SearchInputSection 클래스를 생성한다
상단의 input과 최근 검색어 부분이 한 section 안에 위치되도록 한다
CSS 설정을 통해서 input 창에 마우스 hover 시에만 최근 검색어가 보이도록 설정한다
# SearchInputSection에 적용한 CSS
.SearchInputSection {
position: relative;
}
.KeywordHistory {
display: none;
position: absolute;
top: 75px;
left: 0;
width: 100%;
background-color: #000;
margin: 0;
padding: 20px;
}
.SearchInputSection:hover .KeywordHistory {
display: block;
}
2. 고양이 상세정보 클릭시 fade in/out 효과 추가하기
opacity, visibility, transition 효과를 사용해서 모달이 생기고 사라질 때 부드럽게 바뀌는 효과를 추가한다
# 적용된 CSS 코드
.ImageInfo {
position: fixed;
left: 0;
top: 0;
width: 100vw;
height: 100vh;
background-color: rgba(0, 0, 0, 0.5);
opacity: 0;
visibility: hidden;
transition: all 1s ease;
}
.ImageInfo.show {
opacity: 1;
visibility: visible;
}
# 추가 요구사항 2
1. 검색 결과 각 아이템에 마우스 오버 시 고양이 이름 노출
searchResult 컴포넌트 내에 innerHTML로 이름을 띄워줄 div를 추가한다
# searchResult 내 div 추가 코드
this.$searchResult.innerHTML = this.data
.map(
(cat, index) => `
<li class="item" data-index = ${index}>
<img src="https://via.placeholder.com/200x300" data-src=${cat.url} alt=${cat.name} />
<div class="content">
${cat.name}
</div>
</li>
`
)
.join("");
# 적용된 CSS
.SearchResult .item {
background-color: #eee;
display: inline-block;
margin: 0 0 1em;
width: 100%;
cursor: pointer;
position: relative;
}
.SearchResult .item .content {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.3);
text-align: center;
font-size: 30px;
color: #fff;
opacity: 0;
transition: all 1s ease;
}
.SearchResult .item:hover .content {
opacity: 1;
}
2. 최대 검색 결과 갯수를 설정할 수 있는 select UI 제공
옵션으로 10개, 25개, 50개 지정해야 한다
# 적용된 CSS
.SearchInput {
width: 70%;
font-size: 40px;
padding: 10px 15px;
}
.LimitCount {
width: 10%;
height: 75px;
vertical-align: top;
font-size: 20px;
}
# 옵션을 선택할 수 있는 셀렉트 박스 구현 코드
//샐렉트 UI
const $limitCount = document.createElement("select");
this.$limitCount = $limitCount;
this.$limitCount.classList = "LimitCount";
const LimitCountOptions = [10, 25, 50];
LimitCountOptions.map((option) => {
let $option = document.createElement("option");
$option.value = option;
$option.textContent = option;
$limitCount.appendChild($option);
});
$wrapper.appendChild($limitCount);
# 수정된 API
//api 수정
fetchCatsWithLimit: (keyword, limit) => {
return request(
`${API_ENDPOINT}/api/cats/search?q=${keyword}&limit=${limit}`
);
},
# 추가 요구사항 3
# 랜덤 고양이 배너 섹션 추가
배너를 만드는 과정을 실습해보고 이해하면서 동작 원리에 대해 이해한다
# Banner 컴포넌트 코드
import api from "./api.js";
class Banner {
$banner = null;
data = null;
//현재 위치 저장
current = 0;
constructor({ $target }) {
this.$wrapper = document.createElement("div");
this.$wrapper.className = "Banner";
this.$banner = document.createElement("ul");
this.$prevButton = document.createElement("button");
this.$prevButton.textContent = "PREV";
this.$prevButton.className = "prev";
this.$prevButton.addEventListener("click", (e) => {
console.log("prev");
let prev = this.current - 1;
if (prev === 0) {
return;
}
this.changeCurrent(prev);
});
this.$nextButton = document.createElement("button");
this.$nextButton.textContent = "NEXT";
this.$nextButton.className = "next";
this.$nextButton.addEventListener("click", (e) => {
console.log("next");
let next = this.current + 1;
if (next === this.data.length) {
return;
}
this.changeCurrent(next);
});
this.$wrapper.appendChild(this.$banner);
this.$wrapper.appendChild(this.$prevButton);
this.$wrapper.appendChild(this.$nextButton);
$target.appendChild(this.$wrapper);
this.getRandom();
}
changeCurrent(index) {
this.current = index;
this.moveTo(index);
}
moveTo(index) {
let leftPos = -(Number(this.$wrapper.clientWidth) * index);
this.$banner.style.left = leftPos + "px";
}
setState(nextData) {
this.data = nextData;
this.render();
}
getRandom() {
api.fetchRandomCats().then(({ data }) => {
this.setState(data ? data.slice(0, 5) : []);
});
}
render() {
this.$banner.innerHTML = this.data
.map(
(banner) => `
<li style="background-image:url(${banner.url})"></li>`
)
.join("");
this.$banner.style.width =
Number(this.$wrapper.clientWidth) * this.data.length + "px";
this.$banner.querySelectorAll("li").forEach((item) => {
item.style.width = this.$wrapper.clientWidth * this.data.length + "px";
});
}
}
export default Banner;
# 적용된 CSS
.Banner {
width: 100%;
height: 300px;
overflow: hidden;
margin: 0;
padding: 0;
position: relative;
}
.Banner ul {
margin: 0;
padding: 0;
position: absolute;
transition: all 0.3s ease;
}
.Banner ul li {
float: left;
margin: 0;
padding: 0;
list-style: none;
height: 300px;
background-position: 50% 50%;
background-size: cover;
}
.Banner button {
position: absolute;
top: 50%;
z-index: 10;
}
# 새로 알게 된 점
# display와 visibility의 차이점
▶display
요소가 렌더링되는 방식을 지정한다
display : none; 으로 지정하면 해당 요소가 화면에 표시되지 않는데 이는 해당 요소가 레이아웃에서 사라지는 것이 아니라 단순히 화면에 나타나지 않는 것이다
해당 요소가 차지하는 공간 역시 없어진다
▶visibility
요소의 가시성을 조절한다
visibility : hidden; 으로 지정하면 해당 요소는 화면에서 보이지 않지만 여전히 레이아웃에서 공간을 차지한다
즉 요소는 보이지 않지만 화면에 남아있다
# display 속성과 transition 속성
display 속성과 transition 속성을 함께 사용할 때는 문제가 발생할 수 있다
display 속성은 해당 요소의 표시 방법을 변경하기 때문에 레이아웃에 영향을 미친다
이러한 변경은 트랜지션으로 부드럽게 처리하기 어렵다
따라서 display 대신에 visibility 속성이나 opacity 속성을 사용하면 transition 속성을 적용하기 용이하다
# document.createElement 정리
동적으로 HTML을 생성하는 데 사용되는 메서드이다
이 메서드를 사용하면 Javascript로 HTML 요소를 생성하고 동적으로 문서에 추가할 수 있다
기본 사용법은 아래와 같다
// 새로운 div 요소를 생성
const newDiv = document.createElement('div');
// 생성한 div에 텍스트 내용 추가
newDiv.textContent = 'Hello, World!';
// 문서의 어딘가에 새로운 div를 추가
document.body.appendChild(newDiv);
예시 코드는 아래와 같다
// 새로운 이미지 요소 생성
const newImage = document.createElement('img');
// 이미지 속성 설정
newImage.src = 'path/to/image.jpg';
newImage.alt = 'Description of the image';
// 문서의 특정 요소에 이미지 추가
const containerElement = document.getElementById('container');
containerElement.appendChild(newImage);
어렵거나 모르는 개념을 다시 한번 정리하는 것을 끝으로 고양이 사진 검색 사이트의 강의가 끝이 났다
모르는 개념들도 많고 새로 배운 개념들도 많아서 여러번 반복해서 구현해보며 정리를 해야겠다
다음주에는 고양이 사진첩 애플리케이션 테스트와 해설 강의를 진행하게 된다
이번에 배운 내용을 잘 정리해서 다음주 강의도 열심히 들어야겠다
'TIL > 프로그래머스 데브코스' 카테고리의 다른 글
클라우딩 어플리케이션 엔지니어링 TIL Day 22 - 프로그래머스 알고리즘 (0) | 2024.02.01 |
---|---|
클라우딩 어플리케이션 엔지니어링 TIL Day 23 - 피그마 기초 (1) | 2024.01.31 |
클라우딩 어플리케이션 엔지니어링 TIL Day 18, 19 - 고양이 사진첩 만들기 모의고사, 최종 모의고사 후기 (1) | 2024.01.24 |
클라우딩 어플리케이션 엔지니어링 TIL Day 17 - 고양이 사진 검색 사이트 해설 (3) (0) | 2024.01.20 |
클라우딩 어플리케이션 엔지니어링 TIL Day 16 - 고양이 사진 검색 사이트 해설 (2) (0) | 2024.01.19 |